Compare commits

...

32 Commits

Author SHA1 Message Date
92771db871 anilife update 2022.10.28(01.) 2022-10-28 16:14:33 +09:00
4fef22f3df anilife update 2022.10.24(03.) 2022-10-25 00:29:16 +09:00
a8138d4a71 anilife update 2022.10.24(02.) 2022-10-24 04:42:17 +09:00
af3c43128d anilife update 2022.10.24(02.) 2022-10-24 04:36:51 +09:00
3b2c92a0e3 anilife update 2022.10.24(02.) 2022-10-24 04:22:25 +09:00
2ddda383c5 anilife update 2022.10.24(02.) 2022-10-24 04:21:49 +09:00
47a6407dfe anilife update 2022.10.24(02.) 2022-10-24 04:13:11 +09:00
af73adf1aa anilife update 2022.10.24(01.) 2022-10-24 03:59:32 +09:00
3102ba50ad anilife update 2022.10.23(01.) 2022-10-24 03:59:23 +09:00
6e9b71f4cc anilife update 2022.10.24(01.) 2022-10-24 01:42:47 +09:00
5ff663e288 anilife update 2022.10.23(01.) 2022-10-24 00:49:35 +09:00
11a933a4f6 anilife update 2022.10.23(01.) 2022-10-24 00:18:12 +09:00
a426a57824 anilife update 2022.10.23(01.) 2022-10-23 23:36:05 +09:00
a900247086 anilife update 2022.10.23(01.) 2022-10-23 23:23:46 +09:00
2aa073f504 anilife update 2022.10.23(01.) 2022-10-23 23:01:29 +09:00
cf5ec2e073 anilife update 2022.10.23(01.) 2022-10-23 23:01:19 +09:00
f033c96878 anilife update 2022.10.23(01.) 2022-10-23 22:51:55 +09:00
64eec69efe anilife update 2022.10.23(01.) 2022-10-23 22:44:58 +09:00
bf964a6def anilife update 2022.10.23(01.) 2022-10-23 22:23:56 +09:00
a6541ce299 anilife update 2022.10.23(01.) 2022-10-23 22:14:04 +09:00
3872bd7706 자기전 정리 2022.10.21(01.) 2022-10-23 21:24:28 +09:00
be00760dc2 anilife update 2022.10.23(01.) 2022-10-23 21:22:33 +09:00
a0ce90148f 자기전 정리 2022.10.21(01.) 2022-10-21 18:11:27 +09:00
8755606986 자기전 정리 2022.10.21(01.) 2022-10-21 18:05:03 +09:00
0462792bfb 자기전 정리 2022.10.21(01.) 2022-10-21 18:01:22 +09:00
b04d361805 자기전 정리 2022.10.17(01.) 2022-10-17 23:01:28 +09:00
9adb4f73ee 2022.10.15(01.) 2022-10-15 19:35:46 +09:00
b13dbeb2d8 애니라이프 추가 및 애니24 수정 2022.09.25
os platform fix
2022-09-27 13:18:21 +09:00
b08f45bdc8 애니라이프 추가 및 애니24 수정 2022.09.25
os platform fix
2022-09-27 13:15:55 +09:00
4e5498d6c8 애니라이프 추가 및 애니24 수정 2022.09.25
os platform fix
2022-09-27 13:08:25 +09:00
507a5b9053 애니라이프 추가 및 애니24 수정 2022.09.25
selenium-stealth package import error fixed
2022-09-25 17:41:42 +09:00
1fa8b3f178 애니라이프 추가 및 애니24 수정 2022.09.25
selenium-stealth package import error fixed
2022-09-25 17:38:23 +09:00
12 changed files with 2959 additions and 764 deletions

BIN
bin/Linux/chromedriver Executable file

Binary file not shown.

View File

@@ -1,11 +1,13 @@
import os import os
import sys import sys
import threading
import traceback import traceback
import json import json
from datetime import datetime from datetime import datetime
import hashlib import hashlib
import re import re
import asyncio import asyncio
import platform
import lxml.etree import lxml.etree
@@ -15,7 +17,13 @@ from lxml import html
from urllib import parse from urllib import parse
import urllib import urllib
packages = ["beautifulsoup4", "requests-cache", "cloudscraper"] packages = [
"beautifulsoup4",
"requests-cache",
"cloudscraper",
"selenium_stealth",
"webdriver_manager",
]
for package in packages: for package in packages:
try: try:
import package import package
@@ -80,6 +88,8 @@ class LogicAniLife(LogicModuleBase):
episode_url = None episode_url = None
cookies = None cookies = None
os_platform = platform.system()
session = requests.Session() session = requests.Session()
headers = { 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", "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",
@@ -102,38 +112,23 @@ class LogicAniLife(LogicModuleBase):
default_route_socketio(P, self) default_route_socketio(P, self)
@staticmethod @staticmethod
def get_html(url, referer=None, stream=False, timeout=5): def get_html(url: str, referer: str = None, stream: bool = False, timeout: int = 5):
data = "" data = ""
try: try:
print("cloudflare protection bypass ==================") print("cloudflare protection bypass ==================")
# return LogicAniLife.get_html_cloudflare(url) # return LogicAniLife.get_html_cloudflare(url)
return LogicAniLife.get_html_selenium(url, referer) return LogicAniLife.get_html_selenium(url, referer)
# return LogicAniLife.get_html_playwright(url) # return LogicAniLife.get_html_playwright(url)
# import browser_cookie3
# cj = browser_cookie3.chrome(domain_name="anilife.live")
referer = "https://anilife.live/"
if LogicAniLife.session is None:
LogicAniLife.session = requests.session()
# logger.debug('get_html :%s', url)
LogicAniLife.headers["Referer"] = "" if referer is None else referer
LogicAniLife.headers[
"Cookie"
] = "_ga=GA1.1.578607927.1660813724; __gads=ID=10abb8b98b6828ae-2281c943a9d500fd:T=1660813741:RT=1660813741:S=ALNI_MYU_iB2lBgSrEQUBwhKpNsToaqQ8A; sbtsck=javuwDzcOJqUyweM1OQeNGzHbjoHp7Cgw44XnPdM738c3E=; SPSI=e48379959d54a6a62cc7abdcafdb2761; SPSE=h5HfMGLJzLqzNafMD3YaOvHSC9xfh77CcWdKvexp/z5N5OsTkIiYSCudQhFffEfk/0pcOTVf0DpeV0RoNopzig==; anilife_csrf=b93b9f25a12a51cf185805ec4de7cf9d; UTGv2=h46b326af644f4ac5d0eb1502881136b3750; __gpi=UID=000008ba227e99e0:T=1660813741:RT=1660912282:S=ALNI_MaJHIVJIGpQ5nTE9lvypKQxJnn10A; DSR=SXPX8ELcRgh6N/9rNgjpQoNfaX2DRceeKYR0/ul7qTI9gApWQpZxr8jgymf/r0HsUT551vtOv2CMWpIn0Hd26A==; DCSS=89508000A76BBD939F6DDACE5BD9EB902D2212A; DGCC=Wdm; adOtr=7L4Xe58995d; spcsrf=6554fa003bf6a46dd9b7417acfacc20a; _ga_56VYJJ7FTM=GS1.1.1660912281.10.1.1660912576.0.0.0; PRLST=EO"
page_content = LogicAniLife.session.get(
url, headers=headers, timeout=timeout, allow_redirects=True
)
data = page_content.text
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 data
@staticmethod @staticmethod
def get_html_requests(url, referer=None, stream=False, timeout=5): def get_html_requests(
url: str, referer: str = None, stream: str = False, timeout: int = 5
) -> str:
data = "" data = ""
try: try:
print("get_html_requests ==================") print("get_html_requests ==================")
@@ -163,14 +158,59 @@ class LogicAniLife(LogicModuleBase):
@staticmethod @staticmethod
async def get_html_playwright( async def get_html_playwright(
url, headless=False, referer=None, engine="chrome", stealth=False url: str,
): headless: bool = False,
referer: str = None,
engine: str = "chrome",
stealth: bool = False,
) -> str:
try:
from playwright.sync_api import sync_playwright from playwright.sync_api import sync_playwright
from playwright.async_api import async_playwright from playwright.async_api import async_playwright
from playwright_stealth import stealth_sync, stealth_async from playwright_stealth import stealth_sync, stealth_async
import time 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",
]
# scraper = cloudscraper.create_scraper( # scraper = cloudscraper.create_scraper(
# browser={"browser": "chrome", "platform": "windows", "desktop": True}, # browser={"browser": "chrome", "platform": "windows", "desktop": True},
# debug=False, # debug=False,
@@ -188,8 +228,8 @@ class LogicAniLife(LogicModuleBase):
"AppleWebKit/537.36 (KHTML, like Gecko) " "AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/69.0.3497.100 Safari/537.36" "Chrome/69.0.3497.100 Safari/537.36"
) )
# from playwright_stealth import stealth_sync # from playwright_stealth import stealth_sync
cookie = None
def set_cookie(req): def set_cookie(req):
nonlocal cookie nonlocal cookie
@@ -197,17 +237,28 @@ class LogicAniLife(LogicModuleBase):
cookie = req.headers["cookie"] cookie = req.headers["cookie"]
async with async_playwright() as p: async with async_playwright() as p:
try:
if engine == "chrome": if engine == "chrome":
browser = await p.chromium.launch(channel="chrome", headless=headless) browser = await p.chromium.launch(
channel="chrome", args=browser_args, headless=headless
)
elif engine == "webkit": elif engine == "webkit":
browser = await p.webkit.launch(headless=headless) browser = await p.webkit.launch(
headless=headless,
args=browser_args,
)
else: else:
browser = await p.firefox.launch(headless=headless) browser = await p.firefox.launch(
headless=headless,
args=browser_args,
)
# context = browser.new_context( # context = browser.new_context(
# user_agent=ua, # user_agent=ua,
# ) # )
LogicAniLife.headers["Referer"] = "https://anilife.live/detail/id/471" LogicAniLife.headers[
"Referer"
] = "https://anilife.live/detail/id/471"
# print(LogicAniLife.headers) # print(LogicAniLife.headers)
LogicAniLife.headers["Referer"] = LogicAniLife.episode_url LogicAniLife.headers["Referer"] = LogicAniLife.episode_url
@@ -216,7 +267,9 @@ class LogicAniLife(LogicModuleBase):
LogicAniLife.headers["Referer"] = referer LogicAniLife.headers["Referer"] = referer
logger.debug(f"LogicAniLife.headers::: {LogicAniLife.headers}") logger.debug(f"LogicAniLife.headers::: {LogicAniLife.headers}")
context = await browser.new_context(extra_http_headers=LogicAniLife.headers) context = await browser.new_context(
extra_http_headers=LogicAniLife.headers
)
await context.add_cookies(LogicAniLife.cookies) await context.add_cookies(LogicAniLife.cookies)
# LogicAniLife.headers["Cookie"] = cookie_value # LogicAniLife.headers["Cookie"] = cookie_value
@@ -259,12 +312,27 @@ class LogicAniLife(LogicModuleBase):
print(f"run at {time.time() - start} sec") print(f"run at {time.time() - start} sec")
return await page.content() return await page.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 get_vod_url(url, headless=False): async def get_vod_url_v1(
url, headless=False, referer=None, engine="chrome", stealth=False
):
from playwright.sync_api import sync_playwright from playwright.sync_api import sync_playwright
from playwright_stealth import stealth_sync from playwright.async_api import async_playwright
import html_to_json from playwright_har_tracer import HarTracer
from playwright_stealth import stealth_sync, stealth_async
import time import time
@@ -286,10 +354,150 @@ class LogicAniLife(LogicModuleBase):
"Chrome/69.0.3497.100 Safari/537.36" "Chrome/69.0.3497.100 Safari/537.36"
) )
# from playwright_stealth import stealth_sync # from playwright_stealth import stealth_sync
cookie = None
with sync_playwright() as p: def set_cookie(req):
browser = p.chromium.launch(headless=headless) nonlocal cookie
# browser = p.webkit.launch(headless=headless) if "cookie" in req.headers:
cookie = req.headers["cookie"]
async with async_playwright() as p:
if engine == "chrome":
browser = await p.chromium.launch(channel="chrome", headless=headless)
elif engine == "webkit":
browser = await p.webkit.launch(headless=headless)
else:
browser = await p.firefox.launch(headless=headless)
LogicAniLife.headers["Referer"] = "https://anilife.live/detail/id/471"
# print(LogicAniLife.headers)
LogicAniLife.headers["Referer"] = LogicAniLife.episode_url
if referer is not None:
LogicAniLife.headers["Referer"] = referer
logger.debug(f"LogicAniLife.headers::: {LogicAniLife.headers}")
context = await browser.new_context(extra_http_headers=LogicAniLife.headers)
await context.add_cookies(LogicAniLife.cookies)
# LogicAniLife.headers["Cookie"] = cookie_value
# context.set_extra_http_headers(LogicAniLife.headers)
tracer = HarTracer(context=context, browser_name=p.webkit.name)
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(LogicAniLife.headers["Referer"])
page.on("request", set_cookie)
print(f'Referer:: {LogicAniLife.headers["Referer"]}')
# await page.set_extra_http_headers(LogicAniLife.headers)
await page.goto(
url, wait_until="load", referer=LogicAniLife.headers["Referer"]
)
har = await tracer.flush()
# page.wait_for_timeout(10000)
await asyncio.sleep(10)
# await page.reload()
# time.sleep(10)
# cookies = context.cookies
# print(cookies)
print(f"page.url:: {page.url}")
LogicAniLife.origin_url = page.url
# print(page.content())
print(f"run at {time.time() - start} sec")
return await page.content()
@staticmethod
async def get_vod_url(url: str, headless: bool = False) -> str:
from playwright.sync_api import sync_playwright
from playwright.async_api import async_playwright
from playwright_stealth import stealth_async
import html_to_json
from playwright_har_tracer import HarTracer
import time
# 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}")
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",
]
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
async with async_playwright() as p:
try:
# browser = await p.chromium.launch(headless=headless, args=browser_args)
browser = await p.chromium.launch(headless=headless, args=browser_args)
# browser = await p.webkit.launch(headless=headless)
# context = browser.new_context( # context = browser.new_context(
# user_agent=ua, # user_agent=ua,
# ) # )
@@ -297,38 +505,46 @@ class LogicAniLife(LogicModuleBase):
LogicAniLife.headers[ LogicAniLife.headers[
"Referer" "Referer"
] = "https://anilife.live/g/l?id=14344143-040a-4e40-9399-a7d22d94554b" ] = "https://anilife.live/g/l?id=14344143-040a-4e40-9399-a7d22d94554b"
print(LogicAniLife.headers) # print(LogicAniLife.headers)
context = browser.new_context(extra_http_headers=LogicAniLife.headers) # context = await browser.new_context(extra_http_headers=LogicAniLife.headers)
context = await browser.new_context()
await context.set_extra_http_headers(LogicAniLife.headers)
context.add_cookies(LogicAniLife.cookies) # await context.add_cookies(LogicAniLife.cookies)
# tracer = HarTracer(context=context, browser_name=p.chromium.name)
tracer = HarTracer(context=context, browser_name=p.webkit.name)
# LogicAniLife.headers["Cookie"] = cookie_value # LogicAniLife.headers["Cookie"] = cookie_value
# context.set_extra_http_headers(LogicAniLife.headers) # context.set_extra_http_headers(LogicAniLife.headers)
page = context.new_page() page = await context.new_page()
# page.set_extra_http_headers(LogicAniLife.headers) # await page.set_extra_http_headers(LogicAniLife.headers)
stealth_sync(page) # await stealth_async(page)
# logger.debug(url)
def set_cookie(req):
if "cookie" in req.headers:
print(req.headers["cookie"])
cookie = req.headers["cookie"]
# page.on("request", set_cookie) # page.on("request", set_cookie)
# stealth_sync(page) # stealth_sync(page)
page.goto( # await page.goto(
url, wait_until="networkidle", referer=LogicAniLife.headers["Referer"] # url, wait_until="load", referer=LogicAniLife.headers["Referer"]
) # )
# await page.goto(url, wait_until="load")
await page.goto(url, wait_until="domcontentloaded")
har = await tracer.flush()
# page.wait_for_timeout(10000) # page.wait_for_timeout(10000)
time.sleep(1) await asyncio.sleep(2)
# logger.debug(har)
# page.reload() # page.reload()
# time.sleep(10) # time.sleep(10)
cookies = context.cookies # cookies = context.cookies
# print(cookies) # print(cookies)
# print(page.content()) # print(page.content())
@@ -336,40 +552,37 @@ class LogicAniLife(LogicModuleBase):
# """() => { # """() => {
# return console.log(vodUrl_1080p) }""" # return console.log(vodUrl_1080p) }"""
# ) # )
vod_url = page.evaluate(
"""async () =>{ # vod_url = page.evaluate(
return _0x55265f(0x99) + alJson[_0x55265f(0x91)] # """async () =>{
}""" # return _0x55265f(0x99) + alJson[_0x55265f(0x91)]
) # }"""
# )
result_har_json = har.to_json()
result_har_dict = har.to_dict()
# logger.debug(result_har_dict)
tmp_video_url = []
for i, elem in enumerate(result_har_dict["log"]["entries"]):
if "m3u8" in elem["request"]["url"]:
logger.debug(elem["request"]["url"])
tmp_video_url.append(elem["request"]["url"])
vod_url = tmp_video_url[-1]
logger.debug(f"vod_url:: {vod_url}") logger.debug(f"vod_url:: {vod_url}")
print(f"run at {time.time() - start} sec") logger.debug(f"run at {time.time() - start} sec")
# html_content = LogicAniLife.get_html_selenium(
# vod_url, "https://anilife.live"
# )
html_content = LogicAniLife.get_html_playwright(
vod_url, False, referer="https://anilife.live"
)
# html_content = LogicAniLife.get_html(
# vod_url, referer="https://anilife.live"
# )
# html_content = LogicAniLife.get_html_requests(
# vod_url, referer="https://anilife.live"
# )
print(f"html_content:: {html_content}")
output_json = html_to_json.convert(html_content)
resolution = output_json["html"][0]["body"][0]["_value"]
logger.debug(f"output_json:: {resolution}")
return vod_url return vod_url
except Exception as e:
logger.error("Exception:%s", e)
logger.error(traceback.format_exc())
finally:
await browser.close()
@staticmethod @staticmethod
def get_html_selenium(url, referer): def get_html_selenium(url: str, referer: str) -> 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
@@ -381,17 +594,32 @@ class LogicAniLife(LogicModuleBase):
options.add_argument("start-maximized") options.add_argument("start-maximized")
options.add_argument("--headless") options.add_argument("--headless")
options.add_argument("--no-sandbox") options.add_argument("--no-sandbox")
options.add_argument("window-size=1920x1080")
options.add_argument("disable-gpu")
# options.add_argument('--no-sandbox')
options.add_argument("--disable-dev-shm-usage")
options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False) options.add_experimental_option("useAutomationExtension", False)
if LogicAniLife.os_platform == "Darwin":
# 크롬드라이버 경로 # 크롬드라이버 경로
driver_path = "./bin/Darwin/chromedriver" driver_path = "./bin/Darwin/chromedriver"
# driver = webdriver.Chrome(executable_path=driver_path, chrome_options=options) # driver = webdriver.Chrome(executable_path=driver_path, chrome_options=options)
driver = webdriver.Chrome( driver = webdriver.Chrome(
ChromeDriverManager().install(), chrome_options=options ChromeDriverManager().install(), chrome_options=options
) )
else:
driver_bin_path = os.path.join(
os.path.dirname(__file__), "bin", f"{LogicAniLife.os_platform}"
)
driver_path = f"{driver_bin_path}/chromedriver"
driver = webdriver.Chrome(
executable_path=driver_path, chrome_options=options
)
stealth( stealth(
driver, driver,
languages=["en-US", "en"], languages=["ko-KR", "ko"],
vendor="Google Inc.", vendor="Google Inc.",
platform="Win32", platform="Win32",
webgl_vendor="Intel Inc.", webgl_vendor="Intel Inc.",
@@ -409,7 +637,7 @@ class LogicAniLife(LogicModuleBase):
for cookie in cookies_list: for cookie in cookies_list:
cookies_dict[cookie["name"]] = cookie["value"] cookies_dict[cookie["name"]] = cookie["value"]
logger.debug(cookies_dict) # logger.debug(cookies_dict)
LogicAniLife.cookies = cookies_list LogicAniLife.cookies = cookies_list
# LogicAniLife.headers["Cookie"] = driver.get_cookies() # LogicAniLife.headers["Cookie"] = driver.get_cookies()
LogicAniLife.episode_url = driver.current_url LogicAniLife.episode_url = driver.current_url
@@ -417,6 +645,8 @@ class LogicAniLife(LogicModuleBase):
elem = driver.find_element(By.XPATH, "//*") elem = driver.find_element(By.XPATH, "//*")
source_code = elem.get_attribute("outerHTML") source_code = elem.get_attribute("outerHTML")
driver.close()
return source_code.encode("utf-8") return source_code.encode("utf-8")
# Create a request interceptor # Create a request interceptor
@@ -513,7 +743,7 @@ class LogicAniLife(LogicModuleBase):
# print(scraper.get(url, headers=LogicAniLife.headers).content) # print(scraper.get(url, headers=LogicAniLife.headers).content)
# print(scraper.get(url).content) # print(scraper.get(url).content)
# return scraper.get(url, headers=LogicAniLife.headers).content # return scraper.get(url, headers=LogicAniLife.headers).content
print(LogicAniLife.headers) # print(LogicAniLife.headers)
return sess.get( return sess.get(
url, headers=LogicAniLife.session.headers, timeout=10, allow_redirects=True url, headers=LogicAniLife.session.headers, timeout=10, allow_redirects=True
).content.decode("utf8", errors="replace") ).content.decode("utf8", errors="replace")
@@ -526,6 +756,8 @@ class LogicAniLife(LogicModuleBase):
arg = P.ModelSetting.to_dict() arg = P.ModelSetting.to_dict()
arg["sub"] = self.name arg["sub"] = self.name
if sub in ["setting", "queue", "list", "category", "request"]: if sub in ["setting", "queue", "list", "category", "request"]:
if sub == "request" and req.args.get("content_code") is not None:
arg["anilife_current_code"] = req.args.get("content_code")
if sub == "setting": if sub == "setting":
job_id = "%s_%s" % (self.P.package_name, self.name) job_id = "%s_%s" % (self.P.package_name, self.name)
arg["scheduler"] = str(scheduler.is_include(job_id)) arg["scheduler"] = str(scheduler.is_include(job_id))
@@ -551,7 +783,7 @@ class LogicAniLife(LogicModuleBase):
# logger.info("code::: %s", code) # logger.info("code::: %s", code)
P.ModelSetting.set("anilife_current_code", code) P.ModelSetting.set("anilife_current_code", code)
data = self.get_series_info(code, wr_id, bo_table) data = self.get_series_info(code)
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":
@@ -564,6 +796,37 @@ class LogicAniLife(LogicModuleBase):
return jsonify( return jsonify(
{"ret": "success", "cate": cate, "page": page, "data": data} {"ret": "success", "cate": cate, "page": page, "data": data}
) )
elif sub == "complete_list":
data = []
cate = request.form["type"]
logger.debug("cate:: %s", cate)
page = request.form["page"]
data = self.get_anime_info(cate, page)
# self.current_data = data
return jsonify(
{"ret": "success", "cate": cate, "page": page, "data": data}
)
elif sub == "search":
data = []
# cate = request.form["type"]
# page = request.form["page"]
cate = request.form["type"]
query = request.form["query"]
page = request.form["page"]
data = self.get_search_result(query, page, cate)
# self.current_data = data
return jsonify(
{
"ret": "success",
"cate": cate,
"page": page,
"query": query,
"data": data,
}
)
elif sub == "add_queue": elif sub == "add_queue":
logger.debug(f"add_queue routine ===============") logger.debug(f"add_queue routine ===============")
ret = {} ret = {}
@@ -578,11 +841,89 @@ class LogicAniLife(LogicModuleBase):
req.form["command"], int(req.form["entity_id"]) req.form["command"], int(req.form["entity_id"])
) )
return jsonify(ret) return jsonify(ret)
elif sub == "add_queue_checked_list":
data = json.loads(request.form["data"])
def func():
count = 0
for tmp in data:
add_ret = self.add(tmp)
if add_ret.startswith("enqueue"):
self.socketio_callback("list_refresh", "")
count += 1
notify = {
"type": "success",
"msg": "%s 개의 에피소드를 큐에 추가 하였습니다." % count,
}
socketio.emit(
"notify", notify, namespace="/framework", broadcast=True
)
thread = threading.Thread(target=func, args=())
thread.daemon = True
thread.start()
return jsonify("")
elif sub == "web_list":
return jsonify(ModelAniLifeItem.web_list(request))
elif sub == "db_remove":
return jsonify(ModelAniLifeItem.delete_by_id(req.form["id"]))
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())
@staticmethod
def add_whitelist(*args):
ret = {}
logger.debug(f"args: {args}")
try:
if len(args) == 0:
code = str(LogicAniLife.current_data["code"])
else:
code = str(args[0])
print(code)
whitelist_program = P.ModelSetting.get("anilife_auto_code_list")
# whitelist_programs = [
# str(x.strip().replace(" ", ""))
# for x in whitelist_program.replace("\n", "|").split("|")
# ]
whitelist_programs = [
str(x.strip()) for x in whitelist_program.replace("\n", "|").split("|")
]
if code not in whitelist_programs:
whitelist_programs.append(code)
whitelist_programs = filter(
lambda x: x != "", whitelist_programs
) # remove blank code
whitelist_program = "|".join(whitelist_programs)
entity = (
db.session.query(P.ModelSetting)
.filter_by(key="anilife_auto_code_list")
.with_for_update()
.first()
)
entity.value = whitelist_program
db.session.commit()
ret["ret"] = True
ret["code"] = code
if len(args) == 0:
return LogicAniLife.current_data
else:
return ret
else:
ret["ret"] = False
ret["log"] = "이미 추가되어 있습니다."
except Exception as e:
logger.error("Exception:%s", e)
logger.error(traceback.format_exc())
ret["ret"] = False
ret["log"] = str(e)
return ret
def setting_save_after(self): def setting_save_after(self):
if self.queue.get_max_ffmpeg_count() != P.ModelSetting.get_int( if self.queue.get_max_ffmpeg_count() != P.ModelSetting.get_int(
"anilife_max_ffmpeg_process_count" "anilife_max_ffmpeg_process_count"
@@ -592,7 +933,12 @@ class LogicAniLife(LogicModuleBase):
) )
def scheduler_function(self): def scheduler_function(self):
pass logger.debug(f"ohli24 scheduler_function::=========================")
content_code_list = P.ModelSetting.get_list("ohli24_auto_code_list", "|")
url = f'{P.ModelSetting.get("anilife_url")}/dailyani'
if "all" in content_code_list:
ret_data = LogicAniLife.get_auto_anime_info(self, url=url)
def plugin_load(self): def plugin_load(self):
self.queue = FfmpegQueue( self.queue = FfmpegQueue(
@@ -607,7 +953,7 @@ class LogicAniLife(LogicModuleBase):
return True return True
# 시리즈 정보를 가져오는 함수 # 시리즈 정보를 가져오는 함수
def get_series_info(self, code, wr_id, bo_table): def get_series_info(self, code):
try: try:
if code.isdigit(): if code.isdigit():
url = P.ModelSetting.get("anilife_url") + "/detail/id/" + code url = P.ModelSetting.get("anilife_url") + "/detail/id/" + code
@@ -628,8 +974,7 @@ class LogicAniLife(LogicModuleBase):
.text_content() .text_content()
.strip() .strip()
) )
# print(des_items1)
# print(len(des_items))
des = {} des = {}
des_key = [ des_key = [
"_otit", "_otit",
@@ -669,8 +1014,8 @@ class LogicAniLife(LogicModuleBase):
"최근 방영일": "_recent_date", "최근 방영일": "_recent_date",
"개봉년도": "_release_year", "개봉년도": "_release_year",
} }
print(main_title) # print(main_title)
print(image) # print(image)
# print(des_items) # print(des_items)
list_body_li = tree.xpath('//div[@class="eplister"]/ul/li') list_body_li = tree.xpath('//div[@class="eplister"]/ul/li')
@@ -691,7 +1036,7 @@ class LogicAniLife(LogicModuleBase):
episodes.append( episodes.append(
{ {
"ep_num": ep_num, "ep_num": ep_num,
"title": title, "title": f"{main_title} {ep_num}화 - {title}",
"link": link, "link": link,
"thumbnail": image, "thumbnail": image,
"date": date, "date": date,
@@ -779,9 +1124,9 @@ class LogicAniLife(LogicModuleBase):
logger.info("url:::> %s", url) logger.info("url:::> %s", url)
data = {} data = {}
response_data = LogicAniLife.get_html(url, timeout=10) response_data = LogicAniLife.get_html(url, timeout=10)
print(response_data) # logger.debug(response_data)
logger.debug(f"wrapper_xath:: {wrapper_xpath}") # logger.debug(f"wrapper_xath:: {wrapper_xpath}")
tree = html.fromstring(response_data) tree = html.fromstring(response_data)
tmp_items = tree.xpath(wrapper_xpath) tmp_items = tree.xpath(wrapper_xpath)
data["anime_count"] = len(tmp_items) data["anime_count"] = len(tmp_items)
@@ -790,16 +1135,15 @@ class LogicAniLife(LogicModuleBase):
for item in tmp_items: for item in tmp_items:
entity = {} entity = {}
entity["link"] = item.xpath(".//a/@href")[0] entity["link"] = item.xpath(".//a/@href")[0]
logger.debug(entity["link"]) # logger.debug(entity["link"])
p = re.compile(r"^[http?s://]+[a-zA-Z0-9-]+/[a-zA-Z0-9-_.?=]+$") p = re.compile(r"^[http?s://]+[a-zA-Z0-9-]+/[a-zA-Z0-9-_.?=]+$")
print(p.match(entity["link"]) != None) # print(p.match(entity["link"]) != None)
if p.match(entity["link"]) is None: if p.match(entity["link"]) is None:
entity["link"] = P.ModelSetting.get("anilife_url") + entity["link"] entity["link"] = P.ModelSetting.get("anilife_url") + entity["link"]
# real_url = LogicAniLife.get_real_link(url=entity["link"]) # real_url = LogicAniLife.get_real_link(url=entity["link"])
logger.debug(entity["link"]) # logger.debug(entity["link"])
entity["code"] = entity["link"].split("/")[-1] entity["code"] = entity["link"].split("/")[-1]
entity["title"] = item.xpath(".//div[@class='tt']/text()")[0].strip() entity["title"] = item.xpath(".//div[@class='tt']/text()")[0].strip()
@@ -870,7 +1214,7 @@ class AniLifeQueueEntity(FfmpegQueueEntity):
self.module_logic.socketio_callback("status", self.as_dict()) self.module_logic.socketio_callback("status", self.as_dict())
def info_dict(self, tmp): def info_dict(self, tmp):
logger.debug("self.info::> %s", self.info) # logger.debug("self.info::> %s", self.info)
for key, value in self.info.items(): for key, value in self.info.items():
tmp[key] = value tmp[key] = value
tmp["vtt"] = self.vtt tmp["vtt"] = self.vtt
@@ -899,10 +1243,11 @@ class AniLifeQueueEntity(FfmpegQueueEntity):
ourls = parse.urlparse(url) ourls = parse.urlparse(url)
headers = { self.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",
} }
headers["Referer"] = "https://anilife.live/detail/id/471" headers["Referer"] = "https://anilife.live/detail/id/471"
headers["Referer"] = LogicAniLife.episode_url headers["Referer"] = LogicAniLife.episode_url
@@ -924,13 +1269,15 @@ class AniLifeQueueEntity(FfmpegQueueEntity):
text = asyncio.run( text = asyncio.run(
LogicAniLife.get_html_playwright( LogicAniLife.get_html_playwright(
url, url,
headless=False, headless=True,
referer=referer_url, referer=referer_url,
engine="chrome", engine="chrome",
stealth=True, stealth=True,
) )
) )
# vod_1080p_url = text
# logger.debug(text) # logger.debug(text)
soup = BeautifulSoup(text, "lxml") soup = BeautifulSoup(text, "lxml")
@@ -941,14 +1288,77 @@ class AniLifeQueueEntity(FfmpegQueueEntity):
match = re.compile(regex).search(text) match = re.compile(regex).search(text)
jawcloud_url = None jawcloud_url = None
print(match) # print(match)
if match: if match:
jawcloud_url = match.group("jawcloud_url") jawcloud_url = match.group("jawcloud_url")
print(f"jawcloud_url:: {jawcloud_url}") logger.debug(f"jawcloud_url:: {jawcloud_url}")
vod_1080p_url = LogicAniLife.get_vod_url(jawcloud_url) # loop = asyncio.new_event_loop()
# asyncio.set_event_loop(loop)
#
logger.info(self.info)
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
self.quality = "1080P"
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-AL.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-AL.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}")
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)
vod_1080p_url = asyncio.run(
LogicAniLife.get_vod_url(jawcloud_url, headless=True)
)
print(f"vod_1080p_url:: {vod_1080p_url}") print(f"vod_1080p_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())
@@ -996,6 +1406,10 @@ class ModelAniLifeItem(db.Model):
) )
return ret return ret
def save(self):
db.session.add(self)
db.session.commit()
@classmethod @classmethod
def get_by_id(cls, idx): def get_by_id(cls, idx):
return db.session.query(cls).filter_by(id=idx).first() return db.session.query(cls).filter_by(id=idx).first()
@@ -1004,9 +1418,28 @@ class ModelAniLifeItem(db.Model):
def get_by_anilife_id(cls, anilife_id): def get_by_anilife_id(cls, anilife_id):
return db.session.query(cls).filter_by(anilife_id=anilife_id).first() return db.session.query(cls).filter_by(anilife_id=anilife_id).first()
def save(self): @classmethod
db.session.add(self) def delete_by_id(cls, idx):
db.session.query(cls).filter_by(id=idx).delete()
db.session.commit() db.session.commit()
return True
@classmethod
def web_list(cls, req):
ret = {}
page = int(req.form["page"]) if "page" in req.form else 1
page_size = 30
job_id = ""
search = req.form["search_word"] if "search_word" in req.form else ""
option = req.form["option"] if "option" in req.form else "all"
order = req.form["order"] if "order" in req.form else "desc"
query = cls.make_query(search=search, order=order, option=option)
count = query.count()
query = query.limit(page_size).offset((page - 1) * page_size)
lists = query.all()
ret["list"] = [item.as_dict() for item in lists]
ret["paging"] = Util.get_paging_info(count, page, page_size)
return ret
@classmethod @classmethod
def make_query(cls, search="", order="desc", option="all"): def make_query(cls, search="", order="desc", option="all"):
@@ -1034,6 +1467,10 @@ class ModelAniLifeItem(db.Model):
) )
return query return query
@classmethod
def get_list_uncompleted(cls):
return db.session.query(cls).filter(cls.status != "completed").all()
@classmethod @classmethod
def append(cls, q): def append(cls, q):
item = ModelAniLifeItem() item = ModelAniLifeItem()

View File

@@ -33,6 +33,41 @@ from .plugin import P
class LogicLinkkf(LogicModuleBase): class LogicLinkkf(LogicModuleBase):
db_default = {
"linkkf_db_version": "1",
"linkkf_url": "https://linkkf.app",
"linkkf_download_path": os.path.join(path_data, P.package_name, "linkkf"),
"linkkf_auto_make_folder": "True",
"linkkf_auto_make_season_folder": "True",
"linkkf_finished_insert": "[완결]",
"linkkf_max_ffmpeg_process_count": "1",
"linkkf_order_desc": "False",
"linkkf_auto_start": "False",
"linkkf_interval": "* 5 * * *",
"linkkf_auto_mode_all": "False",
"linkkf_auto_code_list": "all",
"linkkf_current_code": "",
"linkkf_uncompleted_auto_enqueue": "False",
"linkkf_image_url_prefix_series": "",
"linkkf_image_url_prefix_episode": "",
"linkkf_discord_notify": "True",
}
current_headers = None
current_data = None
session = requests.Session()
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"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-Language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
"Referer": "",
}
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"
}
def __init__(self, P): def __init__(self, P):
super(LogicLinkkf, self).__init__(P, "setting", scheduler_desc="linkkf 자동 다운로드") super(LogicLinkkf, self).__init__(P, "setting", scheduler_desc="linkkf 자동 다운로드")
self.name = "linkkf" self.name = "linkkf"
@@ -41,9 +76,9 @@ class LogicLinkkf(LogicModuleBase):
def process_menu(self, sub, req): def process_menu(self, sub, req):
arg = P.ModelSetting.to_dict() arg = P.ModelSetting.to_dict()
arg["sub"] = self.name arg["sub"] = self.name
if sub in ["setting", "queue", "list", "request"]: if sub in ["setting", "queue", "category", "list", "request"]:
if sub == "request" and req.args.get("content_code") is not None: if sub == "request" and req.args.get("content_code") is not None:
arg["ani365_current_code"] = req.args.get("content_code") arg["linkkf_current_code"] = req.args.get("content_code")
if sub == "setting": if sub == "setting":
job_id = "%s_%s" % (self.P.package_name, self.name) job_id = "%s_%s" % (self.P.package_name, self.name)
arg["scheduler"] = str(scheduler.is_include(job_id)) arg["scheduler"] = str(scheduler.is_include(job_id))
@@ -56,4 +91,84 @@ class LogicLinkkf(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):
try:
if sub == "analysis":
pass pass
elif sub == "anime_list":
pass
elif sub == "complete_list":
pass
elif sub == "search":
pass
elif sub == "add_queue":
pass
elif sub == "entity_list":
pass
elif sub == "queue_command":
pass
elif sub == "add_queue_checked_list":
pass
elif sub == "web_list":
pass
elif sub == "db_remove":
pass
elif sub == "add_whitelist":
pass
except Exception as e:
P.logger.error("Exception:%s", e)
P.logger.error(traceback.format_exc())
pass
class ModelLinkkfItem(db.Model):
__tablename__ = "{package_name}_linkkf_item".format(package_name=P.package_name)
__table_args__ = {"mysql_collate": "utf8_general_ci"}
__bind_key__ = P.package_name
id = db.Column(db.Integer, primary_key=True)
created_time = db.Column(db.DateTime)
completed_time = db.Column(db.DateTime)
reserved = db.Column(db.JSON)
content_code = db.Column(db.String)
season = db.Column(db.Integer)
episode_no = db.Column(db.Integer)
title = db.Column(db.String)
episode_title = db.Column(db.String)
linkkf_va = db.Column(db.String)
linkkf_vi = db.Column(db.String)
linkkf_id = db.Column(db.String)
quality = db.Column(db.String)
filepath = db.Column(db.String)
filename = db.Column(db.String)
savepath = db.Column(db.String)
video_url = db.Column(db.String)
vtt_url = db.Column(db.String)
thumbnail = db.Column(db.String)
status = db.Column(db.String)
linkkf_info = db.Column(db.JSON)
def __int__(self):
self.created_time == datetime.now()
def __repr__(self):
return repr(self.as_dict())
def as_dict(self):
ret = {x.name: getattr(self, x.name) for x in self.__table__.columns}
ret["created_time"] = self.created_time.strftime("%Y-%m-%d %H:%M:%S")
ret["completed_time"] = (
self.completed_time.strftime("%Y-%m-%d %H:%M:%S")
if self.completed_time is not None
else None
)
return ret
def save(self):
db.session.add(self)
db.session.commit()
@classmethod
def get_by_id(cls, idx):
return db.session.query(cls).filter_by(id=idx).first()

View File

@@ -804,7 +804,7 @@ class Ohli24QueueEntity(FfmpegQueueEntity):
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("make_episode_info()::url==> %s", url) logger.debug("make_episode_info()::url==> %s", url)

View File

@@ -50,6 +50,7 @@ class P(object):
["setting", "설정"], ["setting", "설정"],
["request", "요청"], ["request", "요청"],
["queue", ""], ["queue", ""],
["category", "검색"],
["list", "목록"], ["list", "목록"],
], ],
"anilife": [ "anilife": [

View File

@@ -1,5 +1,25 @@
{% extends "base.html" %} {% block content %} {% extends "base.html" %} {% block content %}
<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 class="input-group mb-2"> <div class="input-group mb-2">
<input <input
id="input_search" id="input_search"
@@ -9,7 +29,7 @@
aria-label="Search" aria-label="Search"
aria-describedby="search-addon" aria-describedby="search-addon"
/> />
<button id="btn_search" type="button" class="btn btn-outline-primary"> <button id="btn_search" type="button" class="btn btn-primary">
search search
</button> </button>
</div> </div>
@@ -70,6 +90,13 @@
enableAutoReload: true // it will reload the new image when validating attributes changes enableAutoReload: true // it will reload the new image when validating attributes changes
}); });
observer.observe(); observer.observe();
const loader = document.getElementById("preloader");
const dismissLoadingScreen = async function () {
console.log("Before the delay")
// await delay(2.5);
loader.style.display = "none";
};
const get_anime_list = (type, page) => { const get_anime_list = (type, page) => {
@@ -128,6 +155,7 @@
div_visible = true div_visible = true
console.log(div_visible) console.log(div_visible)
} }
dismissLoadingScreen()
next_page = page + 1 next_page = page + 1
} }
}) })
@@ -652,5 +680,134 @@
button.btn-favorite { button.btn-favorite {
background-color: #e0ff42; 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);
}
.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%;
}
.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> </style>
{% endblock %} {% endblock %}

View File

@@ -0,0 +1,172 @@
{% 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>
<style>
body {
width: 100%;
/*height: 100vh;*/
/*display: flex;*/
align-items: center;
justify-content: center;
background-size: 300% 300%;
background-image: linear-gradient(
-45deg,
rgba(59,173,227,1) 0%,
rgba(87,111,230,1) 25%,
rgba(152,68,183,1) 51%,
rgba(255,53,127,1) 100%
);
animation: AnimateBG 20s ease infinite;
}
#main_container {
background-color: white;
}
@keyframes AnimateBG {
0%{background-position:0% 50%}
50%{background-position:100% 50%}
100%{background-position:0% 50%}
}
</style>
{% endblock %}

View File

@@ -1,10 +1,31 @@
{% extends "base.html" %} {% block content %} {% extends "base.html" %} {% block content %}
<div> <div>
<div id="preloader" class="loader">
<div class="loader-inner">
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
</div>
</div>
<form id="program_list"> <form id="program_list">
{{ macros.setting_input_text_and_buttons('code', '작품 Code', {{ macros.setting_input_text_and_buttons('code', '작품 Code',
[['analysis_btn', '분석'], ['go_anilife_btn', 'Go 애니라이프']], desc='예) [['analysis_btn', '분석'], ['go_anilife_btn', 'Go 애니라이프']], desc='예)
"https://anilife.live/g/l?id=f6e83ec6-bd25-4d6c-9428-c10522687604" 이나 "f6e83ec6-bd25-4d6c-9428-c10522687604"') }} "https://anilife.live/detail/id/101 예> 원피스 코드: 101"')
}}
</form> </form>
<form id="program_auto_form"> <form id="program_auto_form">
<div id="episode_list"></div> <div id="episode_list"></div>
@@ -23,7 +44,6 @@
}) })
function findGetParameter(parameterName) { function findGetParameter(parameterName) {
let result = null, let result = null,
tmp = []; tmp = [];
@@ -35,7 +55,48 @@
return result; return result;
} }
const loader = document.getElementById("preloader");
const dismissLoadingScreen = async function () {
console.log("Before the delay")
// await delay(2.5);
loader.style.display = "none";
};
const wait_seconds = function () {
// REFERENCE: https://www.w3schools.com/jsref/met_win_settimeout.asp
let result = setTimeout(dismissLoadingScreen, 2500);
console.log(result)
};
const init = function () {
}
function delay(n) {
return new Promise(function (resolve) {
setTimeout(resolve, n * 1000);
});
}
async function myAsyncFunction() {
//Do what you want here
console.log("Before the delay")
await delay(2.5);
console.log("After the delay")
//Do what you want here too
}
// myAsyncFunction();
// window.addEventListener("DOMContentLoaded", dismissLoadingScreen);
// window.addEventListener("DOMContentLoaded", wait_seconds);
function analyze(wr_id, bo_table) { function analyze(wr_id, bo_table) {
// e.preventDefault();
// e.stopPropagation()
// e.preventDefault(); // e.preventDefault();
const code = document.getElementById("code").value const code = document.getElementById("code").value
console.log(code) console.log(code)
@@ -50,6 +111,7 @@
// {#console.log(ret.code)#} // {#console.log(ret.code)#}
console.log(ret.data) console.log(ret.data)
make_program(ret.data) make_program(ret.data)
$("#loader").css("display", 'none')
} else { } else {
$.notify('<strong>분석 실패</strong><br>' + ret.log, {type: 'warning'}); $.notify('<strong>분석 실패</strong><br>' + ret.log, {type: 'warning'});
} }
@@ -59,7 +121,7 @@
function make_program(data) { function make_program(data) {
current_data = data; current_data = data;
console.log("current_data::", current_data) // console.log("current_data::", current_data)
str = ''; str = '';
tmp = '<div class="form-inline">' tmp = '<div class="form-inline">'
tmp += m_button('check_download_btn', '선택 다운로드 추가', []); tmp += m_button('check_download_btn', '선택 다운로드 추가', []);
@@ -100,7 +162,8 @@
str += m_hr_black(); str += m_hr_black();
for (i in data.episode) { for (i in data.episode) {
str += m_row_start(); tmp = ''; str += m_row_start();
tmp = '';
if (data.episode[i].thumbnail) if (data.episode[i].thumbnail)
tmp = '<img src="' + data.episode[i].thumbnail + '" class="img-fluid">' tmp = '<img src="' + data.episode[i].thumbnail + '" class="img-fluid">'
str += m_col(3, tmp) str += m_col(3, tmp)
@@ -128,7 +191,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();
} }
if ("{{arg['anilife_current_code']}}" !== "") { if ("{{arg['anilife_current_code']}}" !== "") {
@@ -157,14 +220,16 @@
}) })
$(document).ready(function () { $(document).ready(function () {
$("#loader").css("display", 'none')
// console.log('wr_id::', params.wr_id)
console.log('wr_id::', params.wr_id)
}); });
$("#analysis_btn").unbind("click").bind('click', function (e) { $("#analysis_btn").unbind("click").bind('click', function (e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation() e.stopPropagation()
$("#loader").css("display", 'block')
const code = document.getElementById("code").value const code = document.getElementById("code").value
console.log(code) console.log(code)
$.ajax({ $.ajax({
@@ -174,10 +239,13 @@
data: {code: code}, data: {code: code},
dataType: "json", dataType: "json",
success: function (ret) { success: function (ret) {
$("#loader").css("display", 'none')
if (ret.ret === 'success' && ret.data != null) { if (ret.ret === 'success' && ret.data != null) {
// {#console.log(ret.code)#} // {#console.log(ret.code)#}
console.log(ret.data) console.log(ret.data)
make_program(ret.data) make_program(ret.data)
dismissLoadingScreen()
} else { } else {
$.notify('<strong>분석 실패</strong><br>' + ret.log, {type: 'warning'}); $.notify('<strong>분석 실패</strong><br>' + ret.log, {type: 'warning'});
} }
@@ -258,6 +326,7 @@
button.code-button { button.code-button {
min-width: 82px !important; min-width: 82px !important;
} }
.tooltip { .tooltip {
position: relative; position: relative;
display: block; display: block;
@@ -306,6 +375,7 @@
left: 0; left: 0;
opacity: 1; opacity: 1;
} }
[data-tooltip-text]:hover { [data-tooltip-text]:hover {
position: relative; position: relative;
} }
@@ -364,5 +434,136 @@
#screen_movie_list { #screen_movie_list {
margin-top: 10px; margin-top: 10px;
} }
#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;
}
.loader {
background: rgb(0, 0, 0, 0.8);
background: radial-gradient(#222, #000);
bottom: 0;
left: 0;
overflow: hidden;
position: fixed;
right: 0;
top: 0;
z-index: 99999;
}
.loader-inner {
bottom: 0;
height: 60px;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
width: 100px;
}
.loader-line-wrap {
animation: spin 2000ms cubic-bezier(.175, .885, .32, 1.275) infinite;
box-sizing: border-box;
height: 50px;
left: 0;
overflow: hidden;
position: absolute;
top: 0;
transform-origin: 50% 100%;
width: 100px;
}
.loader-line {
border: 4px solid transparent;
border-radius: 100%;
box-sizing: border-box;
height: 100px;
left: 0;
margin: 0 auto;
position: absolute;
right: 0;
top: 0;
width: 100px;
}
.loader-line-wrap:nth-child(1) {
animation-delay: -50ms;
}
.loader-line-wrap:nth-child(2) {
animation-delay: -100ms;
}
.loader-line-wrap:nth-child(3) {
animation-delay: -150ms;
}
.loader-line-wrap:nth-child(4) {
animation-delay: -200ms;
}
.loader-line-wrap:nth-child(5) {
animation-delay: -250ms;
}
.loader-line-wrap:nth-child(1) .loader-line {
border-color: hsl(0, 80%, 60%);
height: 90px;
width: 90px;
top: 7px;
}
.loader-line-wrap:nth-child(2) .loader-line {
border-color: hsl(60, 80%, 60%);
height: 76px;
width: 76px;
top: 14px;
}
.loader-line-wrap:nth-child(3) .loader-line {
border-color: hsl(120, 80%, 60%);
height: 62px;
width: 62px;
top: 21px;
}
.loader-line-wrap:nth-child(4) .loader-line {
border-color: hsl(180, 80%, 60%);
height: 48px;
width: 48px;
top: 28px;
}
.loader-line-wrap:nth-child(5) .loader-line {
border-color: hsl(240, 80%, 60%);
height: 34px;
width: 34px;
top: 35px;
}
@keyframes spin {
0%, 15% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
</style> </style>
{% endblock %} {% endblock %}

View File

@@ -0,0 +1,734 @@
{% extends "base.html" %} {% block content %}
<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-outline-primary">
search
</button>
</div>
<div>
<div
id="anime_category"
class="btn-group"
role="group"
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>
<form id="airing_list_form">
<div id="airing_list"></div>
</form>
<form id="screen_movie_list_form">
<div id="screen_movie_list" class="container"></div>
</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">
<div id="episode_list"></div>
</form>
</div>
<!--전체-->
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/lozad/dist/lozad.min.js"
></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.lazyload/1.9.1/jquery.lazyload.min.js"
integrity="sha512-jNDtFf7qgU0eH/+Z42FG4fw3w7DM/9zbgNPe3wfJlCylVDTT3IgKW5r92Vy9IHa6U50vyMz5gRByIu4YIXFtaQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="text/javascript">
const package_name = "{{arg['package_name'] }}";
const sub = "{{arg['sub'] }}";
const linkkf_url = "{{arg['linkkf_url']}}";
let current_data = null;
let page = 1;
let next_page = Number
let current_cate = ''
let current_query = ''
const observer = lozad('.lozad', {
rootMargin: '10px 0px', // syntax similar to that of CSS Margin
threshold: 0.1, // ratio of element convergence
enableAutoReload: true // it will reload the new image when validating attributes changes
});
observer.observe();
const get_anime_list = (type, page) => {
console.log(`type: ${type}, page: ${page}`)
let url = ''
let data = {"page": page, "type": type}
switch (type) {
case 'ing':
url = '/' + package_name + '/ajax/' + sub + '/anime_list'
current_cate = 'ing'
break;
case 'movie':
url = '/' + package_name + '/ajax/' + sub + '/screen_movie_list'
current_cate = 'movie'
break;
case 'theater':
url = '/' + package_name + '/ajax/' + sub + '/anime_list'
current_cate = 'theater'
break;
case 'fin':
url = '/' + package_name + '/ajax/' + sub + '/complete_list'
current_cate = 'fin'
break
default:
break;
}
$.ajax({
url: url,
type: "POST",
data: data,
cache: false,
dataType: "json",
success: (ret) => {
current_screen_movie_data = ret
console.log('ret::>', ret)
if (current_screen_movie_data !== '') {
if (type === "ing") {
make_airing_list(ret.data, page)
observer.observe();
} else if (type === "fin") {
make_screen_movie_list(ret.data, page)
observer.observe();
} else if (type === "theater") {
make_screen_movie_list(ret.data, page)
observer.observe();
} else {
make_screen_movie_list(ret.data, page)
}
div_visible = true
console.log(div_visible)
}
next_page = page + 1
}
})
}
function make_airing_list(data, page) {
let str = ''
let tmp = ''
str += '<div>';
str += '<button type="button" class="btn btn-info">Page <span class="badge bg-warning">' + page + '</span></button>';
str += '</div>';
// str += '<div class="card-columns">'
str += '<div id="inner_screen_movie" class="row infinite-scroll">';
for (let i in data.anime_list) {
tmp = '<div class="col-6 col-sm-4 col-md-3">';
tmp += '<div class="card">';
// tmp += '<img class="lozad" data-src="' + data.anime_list[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 += '<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">' +#}
// {# '<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 += '<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="' +
data.anime_list[i].code +
'"><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 +=
// '<button id="add_whitelist" name="add_whitelist" class="btn btn-sm btn-favorite mb-1" data-code="' +
// data.anime_list[i].code +
// '"><i class="bi bi-heart-fill"></i></button>';
tmp += '</div><!-- .card -->';
tmp += '</div>';
tmp += '</div>';
str += tmp
}
str += '</div>';
// str += '</div><!-- .card-columns -->';
str += m_hr_black();
if (page > 1) {
const temp = document.createElement('div')
temp.innerHTML = str;
while (temp.firstChild) {
document.getElementById("screen_movie_list").appendChild(temp.firstChild);
}
page++
} else {
document.getElementById("screen_movie_list").innerHTML = str;
}
$("img.lazyload").lazyload({
threshold: 10,
effect: "fadeIn",
});
}
function make_search_result_list(data, page) {
let str = ''
let tmp = ''
console.log(data.anime_list, page)
str += '<div>';
str += '<button type="button" class="btn btn-info">Page <span class="badge bg-warning">' + page + '</span></button>';
str += '</div>';
str += '<div class="card-columns">'
str += '<div id="inner_screen_movie" class="row infinite-scroll">';
for (let i in data.anime_list) {
if (data.anime_list[i].wr_id !== '') {
const re = /bo_table=([^&]+)/
const bo_table = data.anime_list[i].link.match(re)
console.log(bo_table)
request_url = './request?code=' + data.anime_list[i].code + '&amp;wr_id=' + data.anime_list[i].wr_id + '&amp;bo_table=' + bo_table[1]
} else {
request_url = './request?code=' + data.anime_list[i].code
}
tmp = '<div class="col-sm-4">';
tmp += '<div class="card">';
tmp += '<img class="card-img-top" src="' + data.anime_list[i].image_link + '" />';
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">' +#}
// {# '<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 += '<p class="card-text">' + data.anime_list[i].code + '</p>';
tmp += '<a href="' + request_url + '" class="btn btn-primary cut-text">' + data.anime_list[i].title + '</a>';
tmp += '</div>';
tmp += '</div>';
tmp += '</div>';
str += tmp
}
str += '</div>';
str += '</div><!-- .card-columns -->';
str += m_hr_black();
if (page > 1) {
const temp = document.createElement('div')
temp.innerHTML = str;
while (temp.firstChild) {
document.getElementById("screen_movie_list").appendChild(temp.firstChild);
}
page++
} else {
document.getElementById("screen_movie_list").innerHTML = str;
}
}
function make_screen_movie_list(data, page) {
let str = ''
let tmp = ''
console.log(data.anime_list, page)
str += '<div>';
str += '<button type="button" class="btn btn-info">Page <span class="badge bg-warning">' + page + '</span></button>';
str += '</div>';
// str += '<div class="card-columns">'
str += '<div id="inner_screen_movie" class="row infinite-scroll">';
for (let i in data.anime_list) {
tmp = '<div class="col-sm-4">';
tmp += '<div class="card">';
tmp += '<img class="card-img-top" src="' + data.anime_list[i].image_link + '" />';
tmp += '<div class="card-body">'
tmp += '<h5 class="card-title">' + data.anime_list[i].title + '</h5>';
tmp += '<p class="card-text">' + data.anime_list[i].code + '</p>';
tmp += '<a href="./request?code=' + data.anime_list[i].code + '" class="btn btn-primary cut-text">' + data.anime_list[i].title + '</a>';
tmp += '</div>';
tmp += '</div>';
tmp += '</div>';
str += tmp
}
str += '</div>';
// str += '</div><!-- .card-columns -->';
str += m_hr_black();
if (page > 1) {
const temp = document.createElement('div')
temp.innerHTML = str;
while (temp.firstChild) {
document.getElementById("screen_movie_list").appendChild(temp.firstChild);
}
page++
} else {
document.getElementById("screen_movie_list").innerHTML = str;
}
$("img.lazyload").lazyload({
threshold: 10,
effect: "fadeIn",
});
}
$(document).ready(function () {
// if ( "{{arg['linkkf_current_code']}}" !== "" ) {
// document.getElementById("code").value = "{{arg['linkkf_current_code']}}";
// // 값이 공백이 아니면 분석 버튼 계속 누름
// document.getElementById("analysis_btn").click();
// }
$("#input_search").keydown(function (key) {
if (key.keyCode === 13) {
// alert("엔터키를 눌렀습니다.");
$("#btn_search").trigger("click");
}
})
get_anime_list("ing", 1)
const observer = lozad('.lozad', {
rootMargin: '10px 0px', // syntax similar to that of CSS Margin
threshold: 0.1, // ratio of element convergence
enableAutoReload: true // it will reload the new image when validating attributes changes
});
observer.observe();
});
$("body").on("click", "#btn_search", function (e) {
e.preventDefault();
let query = $("#input_search").val();
console.log(query);
current_cate = "search"
current_query = query
if ($("#input_search").val() === "") {
console.log("search keyword nothing");
return false;
}
$.ajax({
url: "/" + package_name + "/ajax/" + sub + "/search",
type: "POST",
cache: false,
data: {query: query, type: current_cate, page: page},
// dataType: "json",
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
success: function (ret) {
if (ret.ret) {
console.log('ret:::', ret)
make_search_result_list(ret.data, 1);
next_page = page + 1
} else {
$.notify("<strong>분석 실패</strong><br>" + ret.log, {
type: "warning",
});
}
},
});
});
$('#anime_category #ing').on("click", function () {
// {#console.log(this.id)#}
let spinner = document.getElementById('spinner');
spinner.style.visibility = 'visible';
get_anime_list("ing", 1)
})
$('#anime_category #complete_anilist').on("click", function () {
// {#console.log(this.id)#}
let spinner = document.getElementById('spinner');
spinner.style.visibility = 'visible';
get_anime_list("fin", 1)
})
$('#anime_category #theater').on("click", function () {
// {#console.log(this.id)#}
let spinner = document.getElementById('spinner');
spinner.style.visibility = 'visible';
get_anime_list("theater", 1)
})
// 분석 버튼 클릭시 호출
$("body").on('click', '#analysis_btn', function (e) {
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},
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_linkkf_btn', function (e) {
e.preventDefault();
window.open("{{arg['linkkf_url']}}", "_blank");
});
$("body").on("click", "#add_whitelist", function (e) {
e.preventDefault();
let data_code = $(this).attr("data-code");
console.log(data_code);
$.ajax({
url: "/" + package_name + "/ajax/"+sub+"/add_whitelist",
type: "POST",
cache: false,
data: JSON.stringify({data_code: data_code}),
contentType: "application/json;charset=UTF-8",
dataType: "json",
success: function (ret) {
if (ret.ret) {
$.notify("<strong>추가하였습니다.</strong><br>", {
type: "success",
});
// make_program(ret);
} else {
$.notify("<strong>추가 실패</strong><br>" + ret.log, {
type: "warning",
});
}
},
});
});
$("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) {
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'});
}
}
});
});
// const observer = lozad();
// const el = document.querySelector('img');
// const observer = lozad(el); // passing a `NodeList` (e.g. `document.querySelectorAll()`) is also valid
// observer.observe();
const loadNextAnimes = (cate, page) => {
spinner.style.display = "block";
let data = {type: cate, page: String(page)};
let url = ''
switch (cate) {
case 'ing':
url = '/' + package_name + '/ajax/' + sub + '/anime_list'
current_cate = 'ing'
break;
case 'movie':
url = '/' + package_name + '/ajax/' + sub + '/screen_movie_list'
current_cate = 'movie'
break;
case 'theater':
url = '/' + package_name + '/ajax/' + sub + '/anime_list'
current_cate = 'theater'
break;
case 'fin':
url = '/' + package_name + '/ajax/' + sub + '/complete_list'
current_cate = 'fin'
break
case 'search':
url = "/" + package_name + "/ajax/" + sub + "/search"
current_cate = 'search'
data.query = current_query
break;
default:
break;
}
fetch(url, {
method: "POST",
cache: "no-cache",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams(data),
})
.then((res) => res.json())
.then((response) => {
// console.log("Success:", JSON.stringify(response));
// {#imagesContainer.appendChild()#}
console.log("return page:::> ", String(response.page));
// {#page = response.page#}
if (current_cate === 'search') {
make_search_result_list(response.data, response.page);
} else {
make_screen_movie_list(response.data, response.page);
}
page++;
next_page++;
})
.catch((error) => console.error("Error:", error));
};
const onScroll = (e) => {
console.dir(e.target.scrollingElement.scrollHeight);
const {scrollTop, scrollHeight, clientHeight} = e.target.scrollingElement;
if (Math.round(scrollHeight - scrollTop) <= clientHeight) {
document.getElementById("spinner").style.display = "block";
console.log("loading");
console.log("now page::> ", page);
console.log("next_page::> ", String(next_page));
loadNextAnimes(current_cate, next_page);
}
};
const debounce = (func, delay) => {
let timeoutId = null;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(func.bind(null, ...args), delay);
};
};
document.addEventListener("scroll", debounce(onScroll, 300));
</script>
<style>
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%;
}
#screen_movie_list {
margin-top: 10px;
}
.card-body {
padding: 0 !important;
}
.card-title {
padding: 1rem !important;
}
button#add_whitelist {
float: right;
}
button.btn-favorite {
background-color: #e0ff42;
}
/*.card-columns {*/
/* @include media-breakpoint-only(lg) {*/
/* column-count: 4;*/
/* }*/
/* @include media-breakpoint-only(xl) {*/
/* column-count: 5;*/
/* }*/
/*}*/
@media (min-width: 576px) {
.container {
max-width: 100%;
}
.card-columns {
column-count: 2;
column-gap: 1.25rem;
}
.card-columns .card {
display: inline-block;
}
}
@media (min-width: 768px) {
.card-columns {column-count: 3;}
}
/* Large devices (desktops, 992px and up) */
@media (min-width: 992px) {
.card-columns {column-count: 3;}
}
/* Extra large devices (large desktops, 1200px and up) */
@media (min-width: 1200px) {
.card-columns {
column-count: 5;
}
}
.card {
margin-bottom: 0.75rem;
}
.card-columns .card {
margin-bottom: 0.75rem;
}
.card-columns .card img{
width: 100%;
}
button#add_whitelist {
/*top: -70px;*/
position: relative;
}
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);
}
</style>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.1/font/bootstrap-icons.css">
{% endblock %}

View File

@@ -1,5 +1,25 @@
{% extends "base.html" %} {% block content %} {% extends "base.html" %} {% block content %}
<!--<div id="preloader"></div>-->
<div id="preloader" class="loader">
<div class="loader-inner">
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
</div>
</div>
<div id="yommi_wrapper">
<div class="input-group mb-2"> <div class="input-group mb-2">
<input <input
id="input_search" id="input_search"
@@ -9,7 +29,7 @@
aria-label="Search" aria-label="Search"
aria-describedby="search-addon" aria-describedby="search-addon"
/> />
<button id="btn_search" type="button" class="btn btn-outline-primary"> <button id="btn_search" type="button" class="btn btn-primary">
search search
</button> </button>
</div> </div>
@@ -42,6 +62,7 @@
<div id="episode_list"></div> <div id="episode_list"></div>
</form> </form>
</div> </div>
</div>
<!--전체--> <!--전체-->
<script <script
@@ -61,6 +82,21 @@
let current_cate = '' let current_cate = ''
let current_query = '' let current_query = ''
const loader = document.getElementById("preloader");
const dismissLoadingScreen = function () {
loader.style.display = "none";
};
const wait3seconds = function () {
// REFERENCE: https://www.w3schools.com/jsref/met_win_settimeout.asp
const result = setTimeout(dismissLoadingScreen, 2000);
};
window.addEventListener("load", wait3seconds);
// window.addEventListener("load", dismissLoadingScreen);
const observer = lozad('.lozad', { const observer = lozad('.lozad', {
rootMargin: '10px 0px', // syntax similar to that of CSS Margin rootMargin: '10px 0px', // syntax similar to that of CSS Margin
threshold: 0.1, // ratio of element convergence threshold: 0.1, // ratio of element convergence
@@ -194,19 +230,23 @@
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.anime_list) {
if (data.anime_list[i].wr_id !== '') { if (data.anime_list[i].wr_id !== '') {
const re = /bo_table=([^&]+)/ const re = /bo_table=([^&]+)/
const bo_table = data.anime_list[i].link.match(re) const bo_table = data.anime_list[i].link.match(re)
// console.log(bo_table) console.log(bo_table)
if (bo_table != null) {
request_url = './request?code=' + data.anime_list[i].code + '&amp;wr_id=' + data.anime_list[i].wr_id + '&amp;bo_table=' + bo_table[1] request_url = './request?code=' + data.anime_list[i].code + '&amp;wr_id=' + data.anime_list[i].wr_id + '&amp;bo_table=' + bo_table[1]
} else { } else {
request_url = './request?code=' + data.anime_list[i].code request_url = './request?code=' + data.anime_list[i].code
} }
} else {
request_url = './request?code=' + data.anime_list[i].code
}
tmp = '<div class="col-sm-4">'; tmp = '<div class="col-6 col-sm-4 col-md-3">';
tmp += '<div class="card">'; tmp += '<div class="card">';
tmp += '<img class="card-img-top" src="' + data.anime_list[i].image_link + '" />'; tmp += '<img class="card-img-top" src="' + data.anime_list[i].image_link + '" />';
tmp += '<div class="card-body">' tmp += '<div class="card-body">'
@@ -671,6 +711,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;*/
@@ -683,10 +724,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;
} }
@@ -694,12 +737,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) */
@@ -707,21 +754,170 @@
.card-columns { .card-columns {
column-count: 5; column-count: 5;
} }
#yommi_wrapper {
max-width: 80%;
margin: 0 auto;
} }
}
.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 {
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);
}
#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;
}
/*.loader {*/
/* background: rgb(0, 0, 0, 0.8);*/
/* background: radial-gradient(#222, #000);*/
/* bottom: 0;*/
/* left: 0;*/
/* overflow: hidden;*/
/* position: fixed;*/
/* right: 0;*/
/* top: 0;*/
/* z-index: 99999;*/
/*}*/
.loader-inner {
bottom: 0;
height: 60px;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
width: 100px;
}
.loader-line-wrap {
animation: spin 2000ms cubic-bezier(.175, .885, .32, 1.275) infinite;
box-sizing: border-box;
height: 50px;
left: 0;
overflow: hidden;
position: absolute;
top: 0;
transform-origin: 50% 100%;
width: 100px;
}
.loader-line {
border: 4px solid transparent;
border-radius: 100%;
box-sizing: border-box;
height: 100px;
left: 0;
margin: 0 auto;
position: absolute;
right: 0;
top: 0;
width: 100px;
}
.loader-line-wrap:nth-child(1) {
animation-delay: -50ms;
}
.loader-line-wrap:nth-child(2) {
animation-delay: -100ms;
}
.loader-line-wrap:nth-child(3) {
animation-delay: -150ms;
}
.loader-line-wrap:nth-child(4) {
animation-delay: -200ms;
}
.loader-line-wrap:nth-child(5) {
animation-delay: -250ms;
}
.loader-line-wrap:nth-child(1) .loader-line {
border-color: hsl(0, 80%, 60%);
height: 90px;
width: 90px;
top: 7px;
}
.loader-line-wrap:nth-child(2) .loader-line {
border-color: hsl(60, 80%, 60%);
height: 76px;
width: 76px;
top: 14px;
}
.loader-line-wrap:nth-child(3) .loader-line {
border-color: hsl(120, 80%, 60%);
height: 62px;
width: 62px;
top: 21px;
}
.loader-line-wrap:nth-child(4) .loader-line {
border-color: hsl(180, 80%, 60%);
height: 48px;
width: 48px;
top: 28px;
}
.loader-line-wrap:nth-child(5) .loader-line {
border-color: hsl(240, 80%, 60%);
height: 34px;
width: 34px;
top: 35px;
}
@keyframes spin {
0%, 15% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
</style> </style>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.1/font/bootstrap-icons.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.1/font/bootstrap-icons.css">
{% endblock %} {% endblock %}

View File

@@ -34,6 +34,7 @@ socket.on('list_refresh', function(data){
}); });
socket.on('status', function(data){ socket.on('status', function(data){
console.log(data);
on_status(data) on_status(data)
}); });

View File

@@ -1,5 +1,25 @@
{% extends "base.html" %} {% block content %} {% extends "base.html" %} {% block content %}
<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> <div>
<form id="program_list"> <form id="program_list">
{{ macros.setting_input_text_and_buttons('code', '작품 Code', {{ macros.setting_input_text_and_buttons('code', '작품 Code',
@@ -22,6 +42,19 @@
get: (searchParams, prop) => searchParams.get(prop), 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) { function findGetParameter(parameterName) {
@@ -85,7 +118,6 @@
tmp += m_row_start(2) + m_col(3, '원제', 'right') + m_col(9, data.des._otit) + m_row_end(); tmp += m_row_start(2) + m_col(3, '원제', 'right') + m_col(9, data.des._otit) + m_row_end();
tmp += m_row_start(2) + m_col(3, '감독', 'right') + m_col(9, data.des._dir) + m_row_end(); tmp += m_row_start(2) + m_col(3, '감독', 'right') + m_col(9, data.des._dir) + m_row_end();
tmp += m_row_start(2) + m_col(3, '제작사', 'right') + m_col(9, data.des._pub) + m_row_end(); tmp += m_row_start(2) + m_col(3, '제작사', 'right') + m_col(9, data.des._pub) + m_row_end();
{#tmp += m_row_start(2) + m_col(3, '장르', 'right') + m_col(9, data.des._tag.join(' | ')) + m_row_end();#}
tmp += m_row_start(2) + m_col(3, '장르', 'right') + m_col(9, data.des._tag) + m_row_end(); tmp += m_row_start(2) + m_col(3, '장르', 'right') + m_col(9, data.des._tag) + m_row_end();
tmp += m_row_start(2) + m_col(3, '분류', 'right') + m_col(9, data.des._classifi) + m_row_end(); tmp += m_row_start(2) + m_col(3, '분류', 'right') + m_col(9, data.des._classifi) + m_row_end();
tmp += m_row_start(2) + m_col(3, '방영일', 'right') + m_col(9, data.date + '(' + data.day + ')') + m_row_end(); tmp += m_row_start(2) + m_col(3, '방영일', 'right') + m_col(9, data.date + '(' + data.day + ')') + m_row_end();
@@ -98,7 +130,8 @@
str += m_hr_black(); str += m_hr_black();
for (i in data.episode) { for (i in data.episode) {
str += m_row_start(); tmp = ''; str += m_row_start();
tmp = '';
if (data.episode[i].thumbnail) if (data.episode[i].thumbnail)
tmp = '<img src="' + data.episode[i].thumbnail + '" class="img-fluid">' tmp = '<img src="' + data.episode[i].thumbnail + '" class="img-fluid">'
str += m_col(3, tmp) str += m_col(3, tmp)
@@ -256,6 +289,7 @@
button.code-button { button.code-button {
min-width: 82px !important; min-width: 82px !important;
} }
.tooltip { .tooltip {
position: relative; position: relative;
display: block; display: block;
@@ -304,6 +338,7 @@
left: 0; left: 0;
opacity: 1; opacity: 1;
} }
[data-tooltip-text]:hover { [data-tooltip-text]:hover {
position: relative; position: relative;
} }
@@ -362,5 +397,151 @@
#screen_movie_list { #screen_movie_list {
margin-top: 10px; 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%;
}
.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> </style>
{% endblock %} {% endblock %}