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,10 +158,180 @@ class LogicAniLife(LogicModuleBase):
@staticmethod @staticmethod
async def get_html_playwright( async def get_html_playwright(
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.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",
]
# 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,
# )
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)
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"]
)
# page.wait_for_timeout(10000)
await asyncio.sleep(2.9)
# 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()
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
async def get_vod_url_v1(
url, headless=False, referer=None, engine="chrome", stealth=False 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.async_api import async_playwright from playwright.async_api import async_playwright
from playwright_har_tracer import HarTracer
from playwright_stealth import stealth_sync, stealth_async from playwright_stealth import stealth_sync, stealth_async
import time import time
@@ -203,9 +368,6 @@ class LogicAniLife(LogicModuleBase):
browser = await p.webkit.launch(headless=headless) browser = await p.webkit.launch(headless=headless)
else: else:
browser = await p.firefox.launch(headless=headless) browser = await p.firefox.launch(headless=headless)
# context = browser.new_context(
# 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)
@@ -222,6 +384,7 @@ class LogicAniLife(LogicModuleBase):
# LogicAniLife.headers["Cookie"] = cookie_value # LogicAniLife.headers["Cookie"] = cookie_value
# context.set_extra_http_headers(LogicAniLife.headers) # context.set_extra_http_headers(LogicAniLife.headers)
tracer = HarTracer(context=context, browser_name=p.webkit.name)
page = await context.new_page() page = await context.new_page()
@@ -242,8 +405,10 @@ class LogicAniLife(LogicModuleBase):
await page.goto( await page.goto(
url, wait_until="load", referer=LogicAniLife.headers["Referer"] url, wait_until="load", referer=LogicAniLife.headers["Referer"]
) )
har = await tracer.flush()
# page.wait_for_timeout(10000) # page.wait_for_timeout(10000)
await asyncio.sleep(2.9) await asyncio.sleep(10)
# await page.reload() # await page.reload()
@@ -261,11 +426,12 @@ class LogicAniLife(LogicModuleBase):
return await page.content() return await page.content()
@staticmethod @staticmethod
def get_vod_url(url, headless=False): async def get_vod_url(url: str, headless: bool = False) -> str:
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
from playwright_stealth import stealth_async
import html_to_json import html_to_json
from playwright_har_tracer import HarTracer
import time import time
# scraper = cloudscraper.create_scraper( # scraper = cloudscraper.create_scraper(
@@ -278,6 +444,45 @@ class LogicAniLife(LogicModuleBase):
# cookie_value, user_agent = scraper.get_cookie_string(url) # cookie_value, user_agent = scraper.get_cookie_string(url)
# #
# logger.debug(f"cookie_value:: {cookie_value}") # 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() start = time.time()
ua = ( ua = (
@@ -287,89 +492,97 @@ class LogicAniLife(LogicModuleBase):
) )
# from playwright_stealth import stealth_sync # from playwright_stealth import stealth_sync
with sync_playwright() as p: async with async_playwright() as p:
browser = p.chromium.launch(headless=headless) try:
# browser = p.webkit.launch(headless=headless) # browser = await p.chromium.launch(headless=headless, args=browser_args)
# context = browser.new_context( browser = await p.chromium.launch(headless=headless, args=browser_args)
# user_agent=ua,
# )
LogicAniLife.headers[ # browser = await p.webkit.launch(headless=headless)
"Referer" # context = browser.new_context(
] = "https://anilife.live/g/l?id=14344143-040a-4e40-9399-a7d22d94554b" # user_agent=ua,
print(LogicAniLife.headers) # )
context = browser.new_context(extra_http_headers=LogicAniLife.headers) LogicAniLife.headers[
"Referer"
] = "https://anilife.live/g/l?id=14344143-040a-4e40-9399-a7d22d94554b"
# print(LogicAniLife.headers)
context.add_cookies(LogicAniLife.cookies) # context = await browser.new_context(extra_http_headers=LogicAniLife.headers)
context = await browser.new_context()
await context.set_extra_http_headers(LogicAniLife.headers)
# LogicAniLife.headers["Cookie"] = cookie_value # await context.add_cookies(LogicAniLife.cookies)
# context.set_extra_http_headers(LogicAniLife.headers) # tracer = HarTracer(context=context, browser_name=p.chromium.name)
tracer = HarTracer(context=context, browser_name=p.webkit.name)
page = context.new_page() # LogicAniLife.headers["Cookie"] = cookie_value
# page.set_extra_http_headers(LogicAniLife.headers) # context.set_extra_http_headers(LogicAniLife.headers)
stealth_sync(page) page = await context.new_page()
def set_cookie(req): # await page.set_extra_http_headers(LogicAniLife.headers)
if "cookie" in req.headers:
print(req.headers["cookie"])
cookie = req.headers["cookie"]
# page.on("request", set_cookie) # await stealth_async(page)
# stealth_sync(page) # logger.debug(url)
page.goto(
url, wait_until="networkidle", referer=LogicAniLife.headers["Referer"]
)
# page.wait_for_timeout(10000)
time.sleep(1)
# page.reload()
# time.sleep(10) # page.on("request", set_cookie)
cookies = context.cookies # stealth_sync(page)
# print(cookies) # await page.goto(
# url, wait_until="load", referer=LogicAniLife.headers["Referer"]
# )
# await page.goto(url, wait_until="load")
await page.goto(url, wait_until="domcontentloaded")
# print(page.content()) har = await tracer.flush()
# vod_url = page.evaluate(
# """() => {
# return console.log(vodUrl_1080p) }"""
# )
vod_url = page.evaluate(
"""async () =>{
return _0x55265f(0x99) + alJson[_0x55265f(0x91)]
}"""
)
logger.debug(f"vod_url:: {vod_url}") # page.wait_for_timeout(10000)
await asyncio.sleep(2)
print(f"run at {time.time() - start} sec") # logger.debug(har)
# page.reload()
# html_content = LogicAniLife.get_html_selenium( # time.sleep(10)
# vod_url, "https://anilife.live" # cookies = context.cookies
# ) # print(cookies)
html_content = LogicAniLife.get_html_playwright( # print(page.content())
vod_url, False, referer="https://anilife.live" # vod_url = page.evaluate(
) # """() => {
# return console.log(vodUrl_1080p) }"""
# )
# html_content = LogicAniLife.get_html( # vod_url = page.evaluate(
# vod_url, referer="https://anilife.live" # """async () =>{
# ) # return _0x55265f(0x99) + alJson[_0x55265f(0x91)]
# html_content = LogicAniLife.get_html_requests( # }"""
# vod_url, referer="https://anilife.live" # )
# ) result_har_json = har.to_json()
result_har_dict = har.to_dict()
# logger.debug(result_har_dict)
print(f"html_content:: {html_content}") tmp_video_url = []
output_json = html_to_json.convert(html_content) for i, elem in enumerate(result_har_dict["log"]["entries"]):
resolution = output_json["html"][0]["body"][0]["_value"] if "m3u8" in elem["request"]["url"]:
logger.debug(f"output_json:: {resolution}") logger.debug(elem["request"]["url"])
tmp_video_url.append(elem["request"]["url"])
return vod_url vod_url = tmp_video_url[-1]
logger.debug(f"vod_url:: {vod_url}")
logger.debug(f"run at {time.time() - start} sec")
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)
# 크롬드라이버 경로
driver_path = "./bin/Darwin/chromedriver" if LogicAniLife.os_platform == "Darwin":
# driver = webdriver.Chrome(executable_path=driver_path, chrome_options=options) # 크롬드라이버 경로
driver = webdriver.Chrome( driver_path = "./bin/Darwin/chromedriver"
ChromeDriverManager().install(), chrome_options=options # 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"{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
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 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,368 +1,569 @@
{% extends "base.html" %} {% block content %} {% extends "base.html" %} {% block content %}
<div> <div>
<form id="program_list"> <div id="preloader" class="loader">
{{ macros.setting_input_text_and_buttons('code', '작품 Code', <div class="loader-inner">
[['analysis_btn', '분석'], ['go_anilife_btn', 'Go 애니라이프']], desc='예) <div class="loader-line-wrap">
"https://anilife.live/g/l?id=f6e83ec6-bd25-4d6c-9428-c10522687604" 이나 "f6e83ec6-bd25-4d6c-9428-c10522687604"') }} <div class="loader-line"></div>
</form> </div>
<form id="program_auto_form"> <div class="loader-line-wrap">
<div id="episode_list"></div> <div class="loader-line"></div>
</form> </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">
{{ macros.setting_input_text_and_buttons('code', '작품 Code',
[['analysis_btn', '분석'], ['go_anilife_btn', 'Go 애니라이프']], desc='예)
"https://anilife.live/detail/id/101 예> 원피스 코드: 101"')
}}
</form>
<form id="program_auto_form">
<div id="episode_list"></div>
</form>
</div> </div>
<!--전체--> <!--전체-->
<script type="text/javascript"> <script type="text/javascript">
const package_name = "{{arg['package_name'] }}"; const package_name = "{{arg['package_name'] }}";
const sub = "{{arg['sub'] }}"; const sub = "{{arg['sub'] }}";
const anilife_url = "{{arg['anilife_url']}}"; const anilife_url = "{{arg['anilife_url']}}";
let current_data = null; let current_data = null;
const params = new Proxy(new URLSearchParams(window.location.search), { const params = new Proxy(new URLSearchParams(window.location.search), {
get: (searchParams, prop) => searchParams.get(prop), get: (searchParams, prop) => searchParams.get(prop),
}) })
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 findGetParameter(parameterName) { const loader = document.getElementById("preloader");
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) { const dismissLoadingScreen = async function () {
// e.preventDefault(); console.log("Before the delay")
const code = document.getElementById("code").value // await delay(2.5);
console.log(code) loader.style.display = "none";
$.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) { const wait_seconds = function () {
current_data = data; // REFERENCE: https://www.w3schools.com/jsref/met_win_settimeout.asp
console.log("current_data::", current_data) let result = setTimeout(dismissLoadingScreen, 2500);
str = ''; console.log(result)
tmp = '<div class="form-inline">' };
tmp += m_button('check_download_btn', '선택 다운로드 추가', []); const init = function () {
tmp += m_button('all_check_on_btn', '전체 선택', []);
tmp += m_button('all_check_off_btn', '전체 해제', []);
/*
tmp += '&nbsp;&nbsp;&nbsp;&nbsp;<input id="new_title" name="new_title" class="form-control form-control-sm" value="'+data.title+'">'
tmp += '</div>'
tmp += m_button('apply_new_title_btn', '저장폴더명, 파일명 제목 변경', []);
tmp += m_button('search_tvdb_btn', 'TVDB', []);
tmp = m_button_group(tmp)
*/
str += tmp
// program
str += m_hr_black();
str += m_row_start(0);
tmp = ''
if (data.image != null)
tmp = '<img src="' + data.image + '" class="img-fluid">';
str += m_col(3, tmp)
tmp = ''
tmp += m_row_start(2) + m_col(3, '제목', 'right') + m_col(9, data.title) + 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._dir) + 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._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.date+'('+data.day+')') + m_row_end();
// tmp += m_row_start(2) + m_col(3, '에피소드', 'right') + m_col(9, data.des._total_chapter ? data.des._total_chapter : '') + m_row_end();
// tmp += m_row_start(2) + m_col(3, '등급', 'right') + m_col(9, data.des._grade) + m_row_end();
// tmp += m_row_start(2) + m_col(3, '최근 방영일', 'right') + m_col(9, data.des._recent_date ? data.des._recent_date : '') + m_row_end();
// tmp += m_row_start(2) + m_col(3, '줄거리', 'right') + m_col(9, data.ser_description) + m_row_end();
tmp += "<div>" + data.des1 + "</div>" }
str += m_col(9, tmp)
str += m_row_end();
str += m_hr_black(); function delay(n) {
for (i in data.episode) { return new Promise(function (resolve) {
str += m_row_start(); tmp = ''; setTimeout(resolve, n * 1000);
if (data.episode[i].thumbnail) });
tmp = '<img src="'+ data.episode[i].thumbnail + '" class="img-fluid">' }
str += m_col(3, tmp)
tmp = '<strong>' + data.episode[i].ep_num + '화. ' + data.episode[i].title+ '</strong>';
tmp += '<br>';
tmp += data.episode[i].date + '<br>';
tmp += '<div class="form-inline">' async function myAsyncFunction() {
tmp += '<input id="checkbox_'+i+'" name="checkbox_'+i+'" type="checkbox" checked data-toggle="toggle" data-on="선 택" data-off="-" data-onstyle="success" data-offstyle="danger" data-size="small">&nbsp;&nbsp;&nbsp;&nbsp;' //Do what you want here
tmp += m_button('add_queue_btn', '다운로드 추가', [{'key':'idx', 'value':i}]) console.log("Before the delay")
tmp += '</div>'
str += m_col(9, 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 () { await delay(2.5);
console.log(params.wr_id)
console.log(findGetParameter('wr_id'))
console.log(params.code)
if (params.code === '') {
} else { console.log("After the delay")
document.getElementById("code").value = params.code //Do what you want here too
// {#document.getElementById("analysis_btn").click();#}
}
if ( "{{arg['anilife_current_code']}}" !== "") { }
if (params.code === null) {
console.log('params.code === null')
document.getElementById("code").value = "{{arg['anilife_current_code']}}";
} else if(params.code === '') { // myAsyncFunction();
document.getElementById("code").value = "{{arg['anilife_current_code']}}"; // window.addEventListener("DOMContentLoaded", dismissLoadingScreen);
} else {
console.log('params code exist') // window.addEventListener("DOMContentLoaded", wait_seconds);
console.log(params.code)
document.getElementById("code").value = params.code
analyze(params.wr_id, params.bo_table) function analyze(wr_id, bo_table) {
// document.getElementById("analysis_btn").click(); // e.preventDefault();
// $('#analysis_btn').trigger('click') // e.stopPropagation()
} // e.preventDefault();
// 값이 공백이 아니면 분석 버튼 계속 누름 const code = document.getElementById("code").value
// {#document.getElementById("analysis_btn").click();#} console.log(code)
} else { $.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)
$("#loader").css("display", 'none')
} else {
$.notify('<strong>분석 실패</strong><br>' + ret.log, {type: 'warning'});
}
}
});
}
} function make_program(data) {
current_data = data;
// console.log("current_data::", current_data)
str = '';
tmp = '<div class="form-inline">'
tmp += m_button('check_download_btn', '선택 다운로드 추가', []);
tmp += m_button('all_check_on_btn', '전체 선택', []);
tmp += m_button('all_check_off_btn', '전체 해제', []);
/*
tmp += '&nbsp;&nbsp;&nbsp;&nbsp;<input id="new_title" name="new_title" class="form-control form-control-sm" value="'+data.title+'">'
tmp += '</div>'
tmp += m_button('apply_new_title_btn', '저장폴더명, 파일명 제목 변경', []);
tmp += m_button('search_tvdb_btn', 'TVDB', []);
tmp = m_button_group(tmp)
*/
str += tmp
// program
str += m_hr_black();
str += m_row_start(0);
tmp = ''
if (data.image != null)
tmp = '<img src="' + data.image + '" class="img-fluid">';
str += m_col(3, tmp)
tmp = ''
tmp += m_row_start(2) + m_col(3, '제목', 'right') + m_col(9, data.title) + 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._dir) + 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._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.date+'('+data.day+')') + m_row_end();
// tmp += m_row_start(2) + m_col(3, '에피소드', 'right') + m_col(9, data.des._total_chapter ? data.des._total_chapter : '') + m_row_end();
// tmp += m_row_start(2) + m_col(3, '등급', 'right') + m_col(9, data.des._grade) + m_row_end();
// tmp += m_row_start(2) + m_col(3, '최근 방영일', 'right') + m_col(9, data.des._recent_date ? data.des._recent_date : '') + m_row_end();
// tmp += m_row_start(2) + m_col(3, '줄거리', 'right') + m_col(9, data.ser_description) + m_row_end();
}) tmp += "<div>" + data.des1 + "</div>"
str += m_col(9, tmp)
str += m_row_end();
$(document).ready(function(){ str += m_hr_black();
for (i in data.episode) {
str += m_row_start();
tmp = '';
if (data.episode[i].thumbnail)
tmp = '<img src="' + data.episode[i].thumbnail + '" class="img-fluid">'
str += m_col(3, tmp)
tmp = '<strong>' + data.episode[i].ep_num + '화. ' + data.episode[i].title + '</strong>';
tmp += '<br>';
tmp += data.episode[i].date + '<br>';
console.log('wr_id::', params.wr_id) tmp += '<div class="form-inline">'
tmp += '<input id="checkbox_' + i + '" name="checkbox_' + i + '" 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': 'idx', 'value': i}])
tmp += '</div>'
str += m_col(9, 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 === '') {
$("#analysis_btn").unbind("click").bind('click', function(e){ } else {
e.preventDefault(); document.getElementById("code").value = params.code
e.stopPropagation() document.getElementById("analysis_btn").click();
const code = document.getElementById("code").value }
console.log(code)
$.ajax({ if ("{{arg['anilife_current_code']}}" !== "") {
url: '/' + package_name + '/ajax/' + sub + '/analysis', if (params.code === null) {
type: "POST", console.log('params.code === null')
cache: false, document.getElementById("code").value = "{{arg['anilife_current_code']}}";
data: {code:code},
dataType: "json", } else if (params.code === '') {
success: function (ret) { document.getElementById("code").value = "{{arg['anilife_current_code']}}";
if (ret.ret === 'success' && ret.data != null) { } else {
// {#console.log(ret.code)#}
console.log(ret.data) console.log('params code exist')
make_program(ret.data) console.log(params.code)
} else { document.getElementById("code").value = params.code
$.notify('<strong>분석 실패</strong><br>' + ret.log, {type: 'warning'});
} 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 () {
$("#loader").css("display", 'none')
// console.log('wr_id::', params.wr_id)
$("body").on('click', '#go_anilife_btn', function(e){ });
e.preventDefault();
window.open("{{arg['anilife_url']}}", "_blank");
});
$("body").on('click', '#all_check_on_btn', function(e){ $("#analysis_btn").unbind("click").bind('click', function (e) {
e.preventDefault(); e.preventDefault();
$('input[id^="checkbox_"]').bootstrapToggle('on') e.stopPropagation()
}); $("#loader").css("display", 'block')
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) {
$("#loader").css("display", 'none')
if (ret.ret === 'success' && ret.data != null) {
// {#console.log(ret.code)#}
console.log(ret.data)
$("body").on('click', '#all_check_off_btn', function(e){ make_program(ret.data)
e.preventDefault(); dismissLoadingScreen()
$('input[id^="checkbox_"]').bootstrapToggle('off') } else {
}); $.notify('<strong>분석 실패</strong><br>' + ret.log, {type: 'warning'});
}
}
});
});
$("body").on('click', '#add_queue_btn', function(e){
$("body").on('click', '#go_anilife_btn', function (e) {
e.preventDefault();
window.open("{{arg['anilife_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(); e.preventDefault();
data = current_data.episode[$(this).data('idx')]; data = current_data.episode[$(this).data('idx')];
console.log('data:::>', data) console.log('data:::>', data)
$.ajax({ $.ajax({
url: '/' + package_name + '/ajax/' + sub + '/add_queue', url: '/' + package_name + '/ajax/' + sub + '/add_queue',
type: "POST", type: "POST",
cache: false, cache: false,
data: {data:JSON.stringify(data)}, data: {data: JSON.stringify(data)},
dataType: "json", dataType: "json",
success: function (data) { success: function (data) {
console.log('#add_queue_btn::data >>', data) console.log('#add_queue_btn::data >>', data)
if (data.ret == 'enqueue_db_append' || data.ret == 'enqueue_db_exist') { if (data.ret == 'enqueue_db_append' || data.ret == 'enqueue_db_exist') {
$.notify('<strong>다운로드 작업을 추가 하였습니다.</strong>', {type: 'success'}); $.notify('<strong>다운로드 작업을 추가 하였습니다.</strong>', {type: 'success'});
} else if (data.ret == 'queue_exist') { } else if (data.ret == 'queue_exist') {
$.notify('<strong>이미 큐에 있습니다. 삭제 후 추가하세요.</strong>', {type: 'warning'}); $.notify('<strong>이미 큐에 있습니다. 삭제 후 추가하세요.</strong>', {type: 'warning'});
} else if (data.ret == 'db_completed') { } else if (data.ret == 'db_completed') {
$.notify('<strong>DB에 완료 기록이 있습니다.</strong>', {type: 'warning'}); $.notify('<strong>DB에 완료 기록이 있습니다.</strong>', {type: 'warning'});
} else { } else {
$.notify('<strong>추가 실패</strong><br>' + ret.log, {type: 'warning'}); $.notify('<strong>추가 실패</strong><br>' + ret.log, {type: 'warning'});
}
} }
}
}); });
}); });
$("body").on('click', '#check_download_btn', function(e){ $("body").on('click', '#check_download_btn', function (e) {
e.preventDefault(); e.preventDefault();
all = $('input[id^="checkbox_"]'); all = $('input[id^="checkbox_"]');
let data = []; let data = [];
let idx; let idx;
for (let i in all) { for (let i in all) {
if (all[i].checked) { if (all[i].checked) {
idx = parseInt(all[i].id.split('_')[1]) idx = parseInt(all[i].id.split('_')[1])
data.push(current_data.episode[idx]); data.push(current_data.episode[idx]);
} }
} }
if (data.length == 0) { if (data.length == 0) {
$.notify('<strong>선택하세요.</strong>', {type: 'warning'}); $.notify('<strong>선택하세요.</strong>', {type: 'warning'});
return; return;
} }
$.ajax({ $.ajax({
url: '/' + package_name + '/ajax/' + sub + '/add_queue_checked_list', url: '/' + package_name + '/ajax/' + sub + '/add_queue_checked_list',
type: "POST", type: "POST",
cache: false, cache: false,
data: {data:JSON.stringify(data)}, data: {data: JSON.stringify(data)},
dataType: "json", dataType: "json",
success: function (data) { success: function (data) {
$.notify('<strong>백그라운드로 작업을 추가합니다.</strong>', {type: 'success'}); $.notify('<strong>백그라운드로 작업을 추가합니다.</strong>', {type: 'success'});
} }
}); });
}); });
</script> </script>
<style> <style>
button.code-button { button.code-button {
min-width: 82px !important; min-width: 82px !important;
} }
.tooltip {
position: relative;
display: block;
}
[data-tooltip-text]:hover { .tooltip {
position: relative; position: relative;
} display: block;
}
[data-tooltip-text]:after { [data-tooltip-text]:hover {
-webkit-transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out; position: relative;
-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); [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;
-webkit-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4); background-color: rgba(0, 0, 0, 0.8);
-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; -webkit-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
-moz-border-radius: 5px; -moz-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
border-radius: 5px; box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
color: #ffffff; -webkit-border-radius: 5px;
font-size: 12px; -moz-border-radius: 5px;
margin-bottom: 10px; border-radius: 5px;
padding: 7px 12px;
position: absolute;
width: auto;
min-width: 50px;
max-width: 300px;
word-wrap: break-word;
z-index: 9999; 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;
opacity: 0; z-index: 9999;
left: -9999px;
top: 90%;
content: attr(data-tooltip-text); opacity: 0;
} left: -9999px;
top: 90%;
[data-tooltip-text]:hover:after { content: attr(data-tooltip-text);
top: 230%; }
left: 0;
opacity: 1;
}
[data-tooltip-text]:hover {
position: relative;
}
[data-tooltip-text]:after { [data-tooltip-text]:hover:after {
-webkit-transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out; top: 230%;
-moz-transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out; left: 0;
transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out; opacity: 1;
}
background-color: rgba(0, 0, 0, 0.8); [data-tooltip-text]:hover {
position: relative;
}
-webkit-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4); [data-tooltip-text]:after {
-moz-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4); -webkit-transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out;
box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4); -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;
-webkit-border-radius: 5px; background-color: rgba(0, 0, 0, 0.8);
-moz-border-radius: 5px;
border-radius: 5px;
color: #ffffff; -webkit-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
font-size: 12px; -moz-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
margin-bottom: 10px; box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
padding: 7px 12px;
position: absolute;
width: auto;
min-width: 50px;
max-width: 300px;
word-wrap: break-word;
z-index: 9999; -webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
opacity: 0; color: #ffffff;
left: -9999px; font-size: 12px;
top: -210% !important; margin-bottom: 10px;
padding: 7px 12px;
position: absolute;
width: auto;
min-width: 50px;
max-width: 300px;
word-wrap: break-word;
content: attr(data-tooltip-text); z-index: 9999;
}
[data-tooltip-text]:hover:after { opacity: 0;
top: 130%; left: -9999px;
left: 0; top: -210% !important;
opacity: 1;
}
#airing_list { content: attr(data-tooltip-text);
display: none; }
}
.cut-text { [data-tooltip-text]:hover:after {
text-overflow: ellipsis; top: 130%;
overflow: hidden; left: 0;
white-space: nowrap; opacity: 1;
width: 100%; }
}
#screen_movie_list { #airing_list {
margin-top: 10px; display: none;
} }
.cut-text {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
width: 100%;
}
#screen_movie_list {
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,46 +1,67 @@
{% extends "base.html" %} {% block content %} {% extends "base.html" %} {% block content %}
<!--<div id="preloader"></div>-->
<div class="input-group mb-2"> <div id="preloader" class="loader">
<input <div class="loader-inner">
id="input_search" <div class="loader-line-wrap">
type="search" <div class="loader-line"></div>
class="form-control rounded" </div>
placeholder="Search" <div class="loader-line-wrap">
aria-label="Search" <div class="loader-line"></div>
aria-describedby="search-addon" </div>
/> <div class="loader-line-wrap">
<button id="btn_search" type="button" class="btn btn-outline-primary"> <div class="loader-line"></div>
search </div>
</button> <div class="loader-line-wrap">
</div> <div class="loader-line"></div>
</div>
<div> <div class="loader-line-wrap">
<div <div class="loader-line"></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>
</div> </div>
<form id="program_auto_form"> </div>
<div id="episode_list"></div> <div id="yommi_wrapper">
</form> <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
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>
</div> </div>
<!--전체--> <!--전체-->
@@ -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
@@ -146,8 +182,8 @@
// {# '<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.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="' + 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 + data.anime_list[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.anime_list[i].code + '" class="btn btn-primary cut-text">' + data.anime_list[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="' +
@@ -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)
request_url = './request?code=' + data.anime_list[i].code + '&amp;wr_id=' + data.anime_list[i].wr_id + '&amp;bo_table=' + bo_table[1] 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]
} else {
request_url = './request?code=' + data.anime_list[i].code
}
} else { } else {
request_url = './request?code=' + data.anime_list[i].code 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">'
@@ -405,7 +445,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}),
@@ -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,366 +1,547 @@
{% 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',
[['analysis_btn', '분석'], ['go_ohli24_btn', 'Go OHLI24']], desc='예) [['analysis_btn', '분석'], ['go_ohli24_btn', 'Go OHLI24']], desc='예)
"https://ohli24.net/c/녹을 먹는 비스코" 이나 "녹을 먹는 비스코"') }} "https://ohli24.net/c/녹을 먹는 비스코" 이나 "녹을 먹는 비스코"') }}
</form> </form>
<form id="program_auto_form"> <form id="program_auto_form">
<div id="episode_list"></div> <div id="episode_list"></div>
</form> </form>
</div> </div>
<!--전체--> <!--전체-->
<script type="text/javascript"> <script type="text/javascript">
const package_name = "{{arg['package_name'] }}"; const package_name = "{{arg['package_name'] }}";
const sub = "{{arg['sub'] }}"; const sub = "{{arg['sub'] }}";
const ohli24_url = "{{arg['ohli24_url']}}"; const ohli24_url = "{{arg['ohli24_url']}}";
let current_data = null; let current_data = null;
const params = new Proxy(new URLSearchParams(window.location.search), { const params = new Proxy(new URLSearchParams(window.location.search), {
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) {
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 findGetParameter(parameterName) { function analyze(wr_id, bo_table) {
let result = null, // e.preventDefault();
tmp = []; const code = document.getElementById("code").value
const items = location.search.substr(1).split("&"); console.log(code)
for (let index = 0; index < items.length; index++) { $.ajax({
tmp = items[index].split("="); url: '/' + package_name + '/ajax/' + sub + '/analysis',
if (tmp[0] === parameterName) result = decodeURIComponent(tmp[1]); type: "POST",
} cache: false,
return result; 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 analyze(wr_id, bo_table) { function make_program(data) {
// e.preventDefault(); current_data = data;
const code = document.getElementById("code").value console.log("current_data::", current_data)
console.log(code) str = '';
$.ajax({ tmp = '<div class="form-inline">'
url: '/' + package_name + '/ajax/' + sub + '/analysis', tmp += m_button('check_download_btn', '선택 다운로드 추가', []);
type: "POST", tmp += m_button('all_check_on_btn', '전체 선택', []);
cache: false, tmp += m_button('all_check_off_btn', '전체 해제', []);
data: {code: code, wr_id: wr_id, bo_table: bo_table}, /*
dataType: "json", tmp += '&nbsp;&nbsp;&nbsp;&nbsp;<input id="new_title" name="new_title" class="form-control form-control-sm" value="'+data.title+'">'
success: function (ret) { tmp += '</div>'
if (ret.ret === 'success' && ret.data != null) { tmp += m_button('apply_new_title_btn', '저장폴더명, 파일명 제목 변경', []);
// {#console.log(ret.code)#} tmp += m_button('search_tvdb_btn', 'TVDB', []);
console.log(ret.data) tmp = m_button_group(tmp)
make_program(ret.data) */
} else { str += tmp
$.notify('<strong>분석 실패</strong><br>' + ret.log, {type: 'warning'}); // program
} str += m_hr_black();
} str += m_row_start(0);
}); tmp = ''
} if (data.image != null)
tmp = '<img src="' + data.image + '" class="img-fluid">';
str += m_col(3, tmp)
tmp = ''
tmp += m_row_start(2) + m_col(3, '제목', 'right') + m_col(9, data.title) + 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._pub) + 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.date + '(' + data.day + ')') + m_row_end();
tmp += m_row_start(2) + m_col(3, '등급', 'right') + m_col(9, data.des._grade) + m_row_end();
tmp += m_row_start(2) + m_col(3, '총화수', 'right') + m_col(9, data.des._total_chapter ? data.des._total_chapter : '') + m_row_end();
tmp += m_row_start(2) + m_col(3, '상영시간', 'right') + m_col(9, data.des._show_time ? data.des._show_time : '') + m_row_end();
tmp += m_row_start(2) + m_col(3, '줄거리', 'right') + m_col(9, data.ser_description) + m_row_end();
str += m_col(9, tmp)
str += m_row_end();
function make_program(data) { str += m_hr_black();
current_data = data; for (i in data.episode) {
console.log("current_data::", current_data) str += m_row_start();
str = ''; tmp = '';
tmp = '<div class="form-inline">' if (data.episode[i].thumbnail)
tmp += m_button('check_download_btn', '선택 다운로드 추가', []); tmp = '<img src="' + data.episode[i].thumbnail + '" class="img-fluid">'
tmp += m_button('all_check_on_btn', '전체 선택', []); str += m_col(3, tmp)
tmp += m_button('all_check_off_btn', '전체 해제', []); tmp = '<strong>' + data.episode[i].title + '</strong>';
/* tmp += '<br>';
tmp += '&nbsp;&nbsp;&nbsp;&nbsp;<input id="new_title" name="new_title" class="form-control form-control-sm" value="'+data.title+'">' tmp += data.episode[i].date + '<br>';
tmp += '</div>'
tmp += m_button('apply_new_title_btn', '저장폴더명, 파일명 제목 변경', []);
tmp += m_button('search_tvdb_btn', 'TVDB', []);
tmp = m_button_group(tmp)
*/
str += tmp
// program
str += m_hr_black();
str += m_row_start(0);
tmp = ''
if (data.image != null)
tmp = '<img src="' + data.image + '" class="img-fluid">';
str += m_col(3, tmp)
tmp = ''
tmp += m_row_start(2) + m_col(3, '제목', 'right') + m_col(9, data.title) + 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._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._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.des._grade) + m_row_end();
tmp += m_row_start(2) + m_col(3, '총화수', 'right') + m_col(9, data.des._total_chapter ? data.des._total_chapter : '') + m_row_end();
tmp += m_row_start(2) + m_col(3, '상영시간', 'right') + m_col(9, data.des._show_time ? data.des._show_time : '') + m_row_end();
tmp += m_row_start(2) + m_col(3, '줄거리', 'right') + m_col(9, data.ser_description) + m_row_end();
str += m_col(9, tmp)
str += m_row_end();
str += m_hr_black(); tmp += '<div class="form-inline">'
for (i in data.episode) { tmp += '<input id="checkbox_' + i + '" name="checkbox_' + i + '" type="checkbox" checked data-toggle="toggle" data-on="선 택" data-off="-" data-onstyle="success" data-offstyle="danger" data-size="small">&nbsp;&nbsp;&nbsp;&nbsp;'
str += m_row_start(); tmp = ''; tmp += m_button('add_queue_btn', '다운로드 추가', [{'key': 'idx', 'value': i}])
if (data.episode[i].thumbnail) tmp += '</div>'
tmp = '<img src="'+ data.episode[i].thumbnail + '" class="img-fluid">' str += m_col(9, tmp)
str += m_col(3, tmp) str += m_row_end();
tmp = '<strong>' + data.episode[i].title+ '</strong>'; if (i != data.length - 1) str += m_hr(0);
tmp += '<br>'; }
tmp += data.episode[i].date + '<br>'; document.getElementById("episode_list").innerHTML = str;
$('input[id^="checkbox_"]').bootstrapToggle()
}
tmp += '<div class="form-inline">' $(function () {
tmp += '<input id="checkbox_'+i+'" name="checkbox_'+i+'" type="checkbox" checked data-toggle="toggle" data-on="선 택" data-off="-" data-onstyle="success" data-offstyle="danger" data-size="small">&nbsp;&nbsp;&nbsp;&nbsp;' console.log(params.wr_id)
tmp += m_button('add_queue_btn', '다운로드 추가', [{'key':'idx', 'value':i}]) console.log(findGetParameter('wr_id'))
tmp += '</div>' console.log(params.code)
str += m_col(9, tmp) if (params.code === '') {
str += m_row_end();
if (i != data.length -1) str += m_hr(0);
}
document.getElementById("episode_list").innerHTML = str;
$('input[id^="checkbox_"]').bootstrapToggle()
}
$(function () { } else {
console.log(params.wr_id) document.getElementById("code").value = params.code
console.log(findGetParameter('wr_id')) // {#document.getElementById("analysis_btn").click();#}
console.log(params.code) }
if (params.code === '') {
} else { if ("{{arg['ohli24_current_code']}}" !== "") {
document.getElementById("code").value = params.code if (params.code === null) {
// {#document.getElementById("analysis_btn").click();#} console.log('params.code === null')
} document.getElementById("code").value = "{{arg['ohli24_current_code']}}";
if ( "{{arg['ohli24_current_code']}}" !== "") { } else if (params.code === '') {
if (params.code === null) { document.getElementById("code").value = "{{arg['ohli24_current_code']}}";
console.log('params.code === null') } else {
document.getElementById("code").value = "{{arg['ohli24_current_code']}}";
} else if(params.code === '') { console.log('params code exist')
document.getElementById("code").value = "{{arg['ohli24_current_code']}}"; console.log(params.code)
} else { document.getElementById("code").value = params.code
console.log('params code exist') analyze(params.wr_id, params.bo_table)
console.log(params.code) // document.getElementById("analysis_btn").click();
document.getElementById("code").value = params.code // $('#analysis_btn').trigger('click')
}
// 값이 공백이 아니면 분석 버튼 계속 누름
// {#document.getElementById("analysis_btn").click();#}
} else {
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 () {
$(document).ready(function(){ console.log('wr_id::', params.wr_id)
console.log('wr_id::', params.wr_id) });
}); $("#analysis_btn").unbind("click").bind('click', function (e) {
e.preventDefault();
$("#analysis_btn").unbind("click").bind('click', function(e){ e.stopPropagation()
e.preventDefault(); const code = document.getElementById("code").value
e.stopPropagation() console.log(code)
const code = document.getElementById("code").value $.ajax({
console.log(code) url: '/' + package_name + '/ajax/' + sub + '/analysis',
$.ajax({ type: "POST",
url: '/' + package_name + '/ajax/' + sub + '/analysis', cache: false,
type: "POST", data: {code: code},
cache: false, dataType: "json",
data: {code:code}, success: function (ret) {
dataType: "json", if (ret.ret === 'success' && ret.data != null) {
success: function (ret) { // {#console.log(ret.code)#}
if (ret.ret === 'success' && ret.data != null) { console.log(ret.data)
// {#console.log(ret.code)#} make_program(ret.data)
console.log(ret.data) } else {
make_program(ret.data) $.notify('<strong>분석 실패</strong><br>' + ret.log, {type: 'warning'});
} else { }
$.notify('<strong>분석 실패</strong><br>' + ret.log, {type: 'warning'}); }
} });
} });
});
});
$("body").on('click', '#go_ohli24_btn', function(e){ $("body").on('click', '#go_ohli24_btn', function (e) {
e.preventDefault(); e.preventDefault();
window.open("{{arg['ohli24_url']}}", "_blank"); window.open("{{arg['ohli24_url']}}", "_blank");
}); });
$("body").on('click', '#all_check_on_btn', function(e){ $("body").on('click', '#all_check_on_btn', function (e) {
e.preventDefault(); e.preventDefault();
$('input[id^="checkbox_"]').bootstrapToggle('on') $('input[id^="checkbox_"]').bootstrapToggle('on')
}); });
$("body").on('click', '#all_check_off_btn', function(e){ $("body").on('click', '#all_check_off_btn', function (e) {
e.preventDefault(); e.preventDefault();
$('input[id^="checkbox_"]').bootstrapToggle('off') $('input[id^="checkbox_"]').bootstrapToggle('off')
}); });
$("body").on('click', '#add_queue_btn', function(e){ $("body").on('click', '#add_queue_btn', function (e) {
e.preventDefault(); e.preventDefault();
data = current_data.episode[$(this).data('idx')]; data = current_data.episode[$(this).data('idx')];
console.log('data:::>', data) console.log('data:::>', data)
$.ajax({ $.ajax({
url: '/' + package_name + '/ajax/' + sub + '/add_queue', url: '/' + package_name + '/ajax/' + sub + '/add_queue',
type: "POST", type: "POST",
cache: false, cache: false,
data: {data:JSON.stringify(data)}, data: {data: JSON.stringify(data)},
dataType: "json", dataType: "json",
success: function (data) { success: function (data) {
console.log('#add_queue_btn::data >>', data) console.log('#add_queue_btn::data >>', data)
if (data.ret == 'enqueue_db_append' || data.ret == 'enqueue_db_exist') { if (data.ret == 'enqueue_db_append' || data.ret == 'enqueue_db_exist') {
$.notify('<strong>다운로드 작업을 추가 하였습니다.</strong>', {type: 'success'}); $.notify('<strong>다운로드 작업을 추가 하였습니다.</strong>', {type: 'success'});
} else if (data.ret == 'queue_exist') { } else if (data.ret == 'queue_exist') {
$.notify('<strong>이미 큐에 있습니다. 삭제 후 추가하세요.</strong>', {type: 'warning'}); $.notify('<strong>이미 큐에 있습니다. 삭제 후 추가하세요.</strong>', {type: 'warning'});
} else if (data.ret == 'db_completed') { } else if (data.ret == 'db_completed') {
$.notify('<strong>DB에 완료 기록이 있습니다.</strong>', {type: 'warning'}); $.notify('<strong>DB에 완료 기록이 있습니다.</strong>', {type: 'warning'});
} else { } else {
$.notify('<strong>추가 실패</strong><br>' + ret.log, {type: 'warning'}); $.notify('<strong>추가 실패</strong><br>' + ret.log, {type: 'warning'});
}
} }
}
}); });
}); });
$("body").on('click', '#check_download_btn', function(e){ $("body").on('click', '#check_download_btn', function (e) {
e.preventDefault(); e.preventDefault();
all = $('input[id^="checkbox_"]'); all = $('input[id^="checkbox_"]');
let data = []; let data = [];
let idx; let idx;
for (let i in all) { for (let i in all) {
if (all[i].checked) { if (all[i].checked) {
idx = parseInt(all[i].id.split('_')[1]) idx = parseInt(all[i].id.split('_')[1])
data.push(current_data.episode[idx]); data.push(current_data.episode[idx]);
} }
} }
if (data.length == 0) { if (data.length == 0) {
$.notify('<strong>선택하세요.</strong>', {type: 'warning'}); $.notify('<strong>선택하세요.</strong>', {type: 'warning'});
return; return;
} }
$.ajax({ $.ajax({
url: '/' + package_name + '/ajax/' + sub + '/add_queue_checked_list', url: '/' + package_name + '/ajax/' + sub + '/add_queue_checked_list',
type: "POST", type: "POST",
cache: false, cache: false,
data: {data:JSON.stringify(data)}, data: {data: JSON.stringify(data)},
dataType: "json", dataType: "json",
success: function (data) { success: function (data) {
$.notify('<strong>백그라운드로 작업을 추가합니다.</strong>', {type: 'success'}); $.notify('<strong>백그라운드로 작업을 추가합니다.</strong>', {type: 'success'});
} }
}); });
}); });
</script> </script>
<style> <style>
button.code-button { button.code-button {
min-width: 82px !important; min-width: 82px !important;
} }
.tooltip {
position: relative;
display: block;
}
[data-tooltip-text]:hover { .tooltip {
position: relative; position: relative;
} display: block;
}
[data-tooltip-text]:after { [data-tooltip-text]:hover {
-webkit-transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out; position: relative;
-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); [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;
-webkit-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4); background-color: rgba(0, 0, 0, 0.8);
-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; -webkit-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
-moz-border-radius: 5px; -moz-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
border-radius: 5px; box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
color: #ffffff; -webkit-border-radius: 5px;
font-size: 12px; -moz-border-radius: 5px;
margin-bottom: 10px; border-radius: 5px;
padding: 7px 12px;
position: absolute;
width: auto;
min-width: 50px;
max-width: 300px;
word-wrap: break-word;
z-index: 9999; 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;
opacity: 0; z-index: 9999;
left: -9999px;
top: 90%;
content: attr(data-tooltip-text); opacity: 0;
} left: -9999px;
top: 90%;
[data-tooltip-text]:hover:after { content: attr(data-tooltip-text);
top: 230%; }
left: 0;
opacity: 1;
}
[data-tooltip-text]:hover {
position: relative;
}
[data-tooltip-text]:after { [data-tooltip-text]:hover:after {
-webkit-transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out; top: 230%;
-moz-transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out; left: 0;
transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out; opacity: 1;
}
background-color: rgba(0, 0, 0, 0.8); [data-tooltip-text]:hover {
position: relative;
}
-webkit-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4); [data-tooltip-text]:after {
-moz-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4); -webkit-transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out;
box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4); -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;
-webkit-border-radius: 5px; background-color: rgba(0, 0, 0, 0.8);
-moz-border-radius: 5px;
border-radius: 5px;
color: #ffffff; -webkit-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
font-size: 12px; -moz-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
margin-bottom: 10px; box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
padding: 7px 12px;
position: absolute;
width: auto;
min-width: 50px;
max-width: 300px;
word-wrap: break-word;
z-index: 9999; -webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
opacity: 0; color: #ffffff;
left: -9999px; font-size: 12px;
top: -210% !important; margin-bottom: 10px;
padding: 7px 12px;
position: absolute;
width: auto;
min-width: 50px;
max-width: 300px;
word-wrap: break-word;
content: attr(data-tooltip-text); z-index: 9999;
}
[data-tooltip-text]:hover:after { opacity: 0;
top: 130%; left: -9999px;
left: 0; top: -210% !important;
opacity: 1;
}
#airing_list { content: attr(data-tooltip-text);
display: none; }
}
.cut-text { [data-tooltip-text]:hover:after {
text-overflow: ellipsis; top: 130%;
overflow: hidden; left: 0;
white-space: nowrap; opacity: 1;
width: 100%; }
}
#screen_movie_list { #airing_list {
margin-top: 10px; 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%;
}
.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 %}