diff --git a/mod_anilife.py b/mod_anilife.py index 9e8cdbe..7f97b62 100644 --- a/mod_anilife.py +++ b/mod_anilife.py @@ -669,6 +669,20 @@ class LogicAniLife(PluginModuleBase): except Exception as img_err: logger.error(f"Image proxy error for {image_url}: {img_err}") return Response("Proxy error", status=500) + elif sub == "add_whitelist": + try: + params = request.get_json() + logger.debug(f"add_whitelist params: {params}") + if params and "data_code" in params: + code = params["data_code"] + ret = LogicAniLife.add_whitelist(code) + else: + ret = LogicAniLife.add_whitelist() + return jsonify(ret) + except Exception as e: + logger.error(f"Exception: {e}") + logger.error(traceback.format_exc()) + return jsonify({"ret": False, "log": str(e)}) except Exception as e: P.logger.error("Exception:%s", e) P.logger.error(traceback.format_exc()) diff --git a/mod_linkkf.py b/mod_linkkf.py index 575dd85..04f4a41 100644 --- a/mod_linkkf.py +++ b/mod_linkkf.py @@ -274,7 +274,19 @@ class LogicLinkkf(PluginModuleBase): elif sub == "db_remove": return jsonify({"ret": "not_implemented"}) elif sub == "add_whitelist": - return jsonify({"ret": "not_implemented"}) + try: + params = request.get_json() + logger.debug(f"add_whitelist params: {params}") + if params and "data_code" in params: + code = params["data_code"] + ret = LogicLinkkf.add_whitelist(code) + else: + ret = LogicLinkkf.add_whitelist() + return jsonify(ret) + except Exception as e: + logger.error(f"Exception: {e}") + logger.error(traceback.format_exc()) + return jsonify({"ret": False, "log": str(e)}) elif sub == "command": # command = queue_command와 동일 cmd = request.form.get("cmd", "") @@ -975,44 +987,58 @@ class LogicLinkkf(PluginModuleBase): def get_search_result(self, query, page, cate): try: - _query = urllib.parse.quote(query) - url = f"{P.ModelSetting.get('linkkf_url')}/search/-------------.html?wd={_query}&page={page}" - - logger.info("get_search_result()::url> %s", url) - data = {"ret": "success", "page": page} - response_data = LogicLinkkf.get_html(url, timeout=10) - tree = html.fromstring(response_data) - - # linkkf 검색 결과는 일반 목록과 동일한 구조 - tmp_items = tree.xpath('//div[@class="myui-vodlist__box"]') - - data["episode_count"] = len(tmp_items) - data["episode"] = [] - - if tree.xpath('//div[@id="wp_page"]//text()'): - data["total_page"] = tree.xpath('//div[@id="wp_page"]//text()')[-1] + # API URL: https://linkkf.5imgdarr.top/api/search.php + api_url = "https://linkkf.5imgdarr.top/api/search.php" + params = { + "keyword": query, + "page": page, + "limit": 20 + } + logger.info(f"get_search_result API: {api_url}, params: {params}") + + headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36", + "Referer": "https://linkkf.live/" + } + + response = requests.get(api_url, params=params, headers=headers, timeout=10) + result_json = response.json() + + data = {"ret": "success", "page": page, "episode": []} + + if result_json.get("status") == "success": + items = result_json.get("data", []) + pagination = result_json.get("pagination", {}) + + data["total_page"] = pagination.get("total_pages", 0) + data["episode_count"] = pagination.get("total_results", 0) + + for item in items: + entity = {} + entity["code"] = str(item.get("postid")) + entity["title"] = item.get("name") + + thumb = item.get("thumb") + if thumb: + if thumb.startswith("http"): + entity["image_link"] = thumb + else: + entity["image_link"] = f"https://rez1.ims1.top/350x/{thumb}" + else: + entity["image_link"] = "" + + entity["chapter"] = item.get("postnoti") or item.get("seasontype") or "" + entity["link"] = f"https://linkkf.live/{entity['code']}" + + data["episode"].append(entity) else: - data["total_page"] = 0 - - for item in tmp_items: - entity = {} - entity["link"] = item.xpath(".//a/@href")[0] - entity["code"] = re.search(r"[0-9]+", entity["link"]).group() - entity["title"] = item.xpath('.//a[@class="text-fff"]//text()')[ - 0 - ].strip() - entity["image_link"] = item.xpath("./a/@data-original")[0] - entity["chapter"] = ( - item.xpath("./a/span//text()")[0].strip() - if len(item.xpath("./a/span//text()")) > 0 - else "" - ) - data["episode"].append(entity) + data["total_page"] = 0 + data["episode_count"] = 0 return data except Exception as e: - P.logger.error(f"Exception: {str(e)}") - P.logger.error(traceback.format_exc()) + logger.error(f"Exception: {str(e)}") + logger.error(traceback.format_exc()) return {"ret": "exception", "log": str(e)} def get_series_info(self, code): diff --git a/search_result.html b/search_result.html new file mode 100644 index 0000000..ee20aa3 --- /dev/null +++ b/search_result.html @@ -0,0 +1,810 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ Linkkf +
+ + + +
+
+ +
+ +
+ +
+ + + + + +
+
+ + + + +
+
+ × + +
+

로그인

+ + + +

계정이 없으신가요? 회원가입

+
+ + + +

+
+
+ + + +
+원펀맨 애니 자막 Linkkf + + + +
+
+ +
+
+

검색: 원펀맨

+ +
+ +
+ +
+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+ + + + + + + +
+ +
+ + + + + + + + + + + + +
+
+
0.o
+
+ + + + + + + \ No newline at end of file diff --git a/templates/anime_downloader_linkkf_request.html b/templates/anime_downloader_linkkf_request.html index bfbb6bf..05110d5 100644 --- a/templates/anime_downloader_linkkf_request.html +++ b/templates/anime_downloader_linkkf_request.html @@ -1,5 +1,5 @@ {% extends "base.html" %} {% block content %} -
+
@@ -53,6 +53,8 @@ }; const wait3seconds = function () { + // Force parent container to be fluid to allow full width + $("#main_container").removeClass("container").addClass("container-fluid"); // REFERENCE: https://www.w3schools.com/jsref/met_win_settimeout.asp const result = setTimeout(dismissLoadingScreen, 2000); }; @@ -95,76 +97,77 @@ function make_program(data) { current_data = data; - {#$("body").css({"background":"url("+data.poster_url+")"})#} - - // console.log('current_data:: ', data) - str = ""; - tmp = '
'; - tmp += m_button("check_download_btn", "선택 다운로드 추가", []); - tmp += m_button("all_check_on_btn", "전체 선택", []); - tmp += m_button("all_check_off_btn", "전체 해제", []); - tmp += m_button("down_subtitle_btn", "자막만 전체 받기", []) - tmp += - '   '; - tmp += "
"; - tmp += '
'; - tmp += m_button("apply_new_title_btn", "저장폴더명 변경", []); - tmp += - '   '; - tmp += m_button("apply_new_season_btn", "시즌 변경 (숫자만 가능)", []); - tmp += m_button("search_tvdb_btn", "TVDB", []); - tmp += m_button("add_whitelist", "스케쥴링 추가", []); - - tmp += "
"; - tmp = m_button_group(tmp); - str += tmp; - // program - // str += m_hr_black(); - str += "
" - - str += m_row_start(0); - tmp = ""; - if (data.poster_url != null) - tmp = ''; - str += m_col(3, tmp); - tmp = ""; - tmp += m_row_start(0); - tmp += m_col(3, "제목", "right"); - tmp += m_col(9, data.title); - tmp += m_row_end(); - tmp += m_row_start(0); - tmp += m_col(3, "시즌", "right"); - tmp += m_col(9, data.season); - tmp += m_row_end(); - for (i in data.detail) { - tmp += m_row_start(0); - key = Object.keys(data.detail[i])[0]; - value = data.detail[i][key]; - tmp += m_col(3, key, "right"); - tmp += m_col(9, value); - tmp += m_row_end(); - } - - str += m_col(9, tmp); - str += m_row_end(); - - // str += m_hr_black(); - str += "
" - // 에피소드 카드 그리드 레이아웃 + let str = ""; + + // 1. Info Card (Top) + str += `
`; + str += `
`; + + // Poster + str += `
`; + if (data.poster_url) { + str += ``; + } + str += `
`; + + // Details + str += `
`; + str += `

${data.title}

`; + str += `
`; + str += `Season ${data.season}`; + str += `
`; + + // Table for details + str += `
`; + if(data.detail) { + for(let i in data.detail) { + const key = Object.keys(data.detail[i])[0]; + const value = data.detail[i][key]; + str += `
${key}: ${value}
`; + } + } + str += `
`; // End detail row + + // Actions Toolbar + str += `
`; + + // Standard Actions + str += ``; + str += ``; + str += ``; + str += ``; + + // Scheduling (Heart) + str += ``; + + str += `
`; // End Action Toolbar Main + + // Edit Tools (Secondary Toolbar) + str += `
`; + str += `저장 옵션:`; + str += ``; + str += ``; + str += ``; + str += ``; + str += ``; + str += `
`; + + + str += `
`; // End Col-9 + str += `
`; // End Row + str += `
`; // End Card + + // 2. Episode List str += '
'; - for (i in data.episode) { + for (let i in data.episode) { str += '
'; str += '
'; str += '' + (parseInt(i) + 1) + '화'; str += '
'; str += '
'; str += '
' + data.episode[i].title + '
'; - str += '
' + data.episode[i].filename + '
'; + str += '
' + data.episode[i].filename + '
'; str += '
'; str += ''; str += m_button("add_queue_btn", "다운로드", [{key: "idx", value: i}]); @@ -173,6 +176,7 @@ str += '
'; } str += '
'; + document.getElementById("episode_list").innerHTML = str; $('input[id^="checkbox_"]').bootstrapToggle(); } @@ -243,6 +247,33 @@ }); + $("body").on('click', '#add_whitelist', function (e) { + e.preventDefault(); + const code = document.getElementById("code").value || params.code; + const $btn = $(this); + $.ajax({ + url: '/' + package_name + '/ajax/' + sub + '/add_whitelist', + type: "POST", + cache: false, + data: JSON.stringify({data_code: code}), + contentType: "application/json;charset=UTF-8", + dataType: "json", + success: function (ret) { + if (ret.ret) { + $.notify('스케쥴링 목록에 추가하였습니다.', {type: 'success'}); + $btn.html(' 추가됨').removeClass('btn-outline-danger').addClass('btn-danger'); + } else { + if (ret.log == "이미 추가되어 있습니다.") { + $.notify('이미 추가되어 있습니다.', {type: 'warning'}); + $btn.html(' 추가됨').removeClass('btn-outline-danger').addClass('btn-danger'); + } else { + $.notify('추가 실패
' + ret.log, {type: 'warning'}); + } + } + } + }); + }); + $("body").on('click', '#go_ohli24_btn', function (e) { e.preventDefault(); window.open("{{arg['ohli24_url']}}", "_blank"); diff --git a/templates/anime_downloader_linkkf_search.html b/templates/anime_downloader_linkkf_search.html index 2e9d335..9e9200f 100644 --- a/templates/anime_downloader_linkkf_search.html +++ b/templates/anime_downloader_linkkf_search.html @@ -52,7 +52,7 @@
-
+
{#
@@ -174,7 +174,7 @@ dataType: "json", success: (ret) => { current_screen_movie_data = ret - console.log('ret::>', ret) + // console.log('ret::>', ret) if (current_screen_movie_data !== '') { if (type === "ing") { @@ -191,7 +191,7 @@ make_screen_movie_list(ret.data, page) } div_visible = true - console.log(div_visible) + // console.log(div_visible) } next_page = page + 1 } @@ -260,45 +260,44 @@ function make_search_result_list(data, page) { let str = '' let tmp = '' - - console.log(data.anime_list, page) + + let list = data.anime_list || data.episode || []; str += '
'; str += ''; str += '
'; - // str += '
' str += '
'; - for (let i in data.anime_list) { - if (data.anime_list[i].wr_id !== '') { + + for (let i in list) { + let item = list[i]; + if (item.wr_id !== undefined && item.wr_id !== '') { const re = /bo_table=([^&]+)/ - const bo_table = data.anime_list[i].link.match(re) - console.log(bo_table) + const bo_table = item.link.match(re) if (bo_table != null) { - request_url = './request?code=' + data.anime_list[i].code + '&wr_id=' + data.anime_list[i].wr_id + '&bo_table=' + bo_table[1] + request_url = './request?code=' + item.code + '&wr_id=' + item.wr_id + '&bo_table=' + bo_table[1] } else { - request_url = './request?code=' + data.anime_list[i].code + request_url = './request?code=' + item.code } } else { - request_url = './request?code=' + data.anime_list[i].code + request_url = './request?code=' + item.code } tmp = '
'; tmp += '
'; - tmp += ''; + tmp += ''; tmp += '
' - // {#tmp += '
';#} - tmp += '
' + data.anime_list[i].title + '
'; - tmp += '

' + data.anime_list[i].code + '

'; - tmp += '' + data.anime_list[i].title + ''; + tmp += '
' + item.title + '
'; + tmp += '
'; + tmp += '' + item.code + ''; + tmp += ''; + tmp += '
'; + tmp += '' + item.title + ''; tmp += '
'; tmp += '
'; tmp += '
'; str += tmp - } str += '
'; - str += '
'; str += m_hr_black(); if (page > 1) { @@ -321,9 +320,9 @@ let tmp = ""; let new_anime = true; let new_style = '' - console.log('page a: ', page) - console.log(data) - console.log(data.data) + // console.log('page a: ', page) + // console.log(data) + // console.log(data.data) //console.log(data.episode) let page_elem = ""; @@ -341,8 +340,8 @@ str += "
"; str += '
'; for (let i in data.data) { - console.log(i) - console.log(data.data[i]) + // console.log(i) + // console.log(data.data[i]) if (data.data[i].postid === data.latest_anime_code) { new_anime = false } @@ -374,12 +373,10 @@ // tmp += '
'; tmp += '
'; tmp += '
' + data.data[i].postname + "
"; - tmp += - '"; + tmp += '
'; + tmp += '' + data.data[i].postid + ''; + tmp += ''; + tmp += '
'; tmp += '분석 실패
' + ret.log, {type: 'warning'}); @@ -542,8 +539,9 @@ $("body").on("click", "#add_whitelist", function (e) { e.preventDefault(); - let data_code = $(this).attr("data-code"); - console.log(data_code); + let $btn = $(this); + let data_code = $btn.attr("data-code"); + $.ajax({ url: "/" + package_name + "/ajax/" + sub + "/add_whitelist", type: "POST", @@ -553,14 +551,18 @@ dataType: "json", success: function (ret) { if (ret.ret) { - $.notify("추가하였습니다.
", { + $.notify("추가하였습니다. [" + data_code + "]", { type: "success", }); - // make_program(ret); + // 시각적 피드백: 하트 색상 변경 + $btn.addClass('active').css('color', '#ef4444'); } else { - $.notify("추가 실패
" + ret.log, { + $.notify("" + ret.log + "", { type: "warning", }); + if (ret.log === "이미 추가되어 있습니다.") { + $btn.addClass('active').css('color', '#ef4444'); + } } }, }); @@ -579,7 +581,7 @@ $("body").on('click', '#add_queue_btn', function (e) { e.preventDefault(); data = current_data.episode[$(this).data('idx')]; - console.log('data:::>', data) + // console.log('data:::>', data) $.ajax({ url: '/' + package_name + '/ajax/' + sub + '/add_queue', type: "POST", @@ -603,7 +605,7 @@ // const el = document.querySelector('img'); // const observer = lozad(el); // passing a `NodeList` (e.g. `document.querySelectorAll()`) is also valid // observer.observe(); - console.log('scroll 세로크기:', document.body.scrollHeight) + // console.log('scroll 세로크기:', document.body.scrollHeight) const loadNextAnimes = (cate, page, ch) => { // spinner.style.display = "block"; @@ -648,7 +650,7 @@ .then((response) => { // console.log("Success:", JSON.stringify(response)); // {#imagesContainer.appendChild()#} - console.log("return page:::> ", String(response.page)); + // console.log("return page:::> ", String(response.page)); // {#page = response.page#} loader.style.display = "block"; if (current_cate === 'search') { @@ -658,8 +660,8 @@ make_screen_movie_list(response.data, response.page); } - console.log(document.body.scrollHeight) - console.log(ch) + // console.log(document.body.scrollHeight) + // console.log(ch) window.scrollBy({ top: ch + 35, left: 0, @@ -679,9 +681,9 @@ const {scrollTop, scrollHeight, clientHeight} = e.target.scrollingElement; if (Math.round(scrollHeight - scrollTop) <= clientHeight + 170) { {#document.getElementById("spinner").style.display = "block";#} - console.log("loading"); - console.log("now page::> ", page); - console.log("next_page::> ", String(next_page)); + // console.log("loading"); + // console.log("now page::> ", page); + // console.log("next_page::> ", String(next_page)); loadNextAnimes(current_cate, next_page, clientHeight); /*window.scrollBy({ top: e.target.scrollingElement.scrollHeight + 200, @@ -793,400 +795,289 @@ > - - + + {% endblock %} diff --git a/templates/anime_downloader_ohli24_list.html b/templates/anime_downloader_ohli24_list.html index 2e8d9d1..cec98c6 100644 --- a/templates/anime_downloader_ohli24_list.html +++ b/templates/anime_downloader_ohli24_list.html @@ -166,4 +166,44 @@ + {% endblock %} \ No newline at end of file diff --git a/templates/anime_downloader_ohli24_queue.html b/templates/anime_downloader_ohli24_queue.html index e9d2781..6024400 100644 --- a/templates/anime_downloader_ohli24_queue.html +++ b/templates/anime_downloader_ohli24_queue.html @@ -411,11 +411,49 @@ transform: translate(-50%, -50%); width: 40px; height: 40px; - border: 3px solid rgba(96, 165, 250, 0.2); - border-top-color: #60a5fa; + border-color: #60a5fa; border-radius: 50%; animation: spin 0.8s linear infinite; } + + /* Navigation Menu Override */ + ul.nav.nav-pills.bg-light { + background-color: rgba(30, 41, 59, 0.6) !important; + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 50rem !important; + padding: 6px !important; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2) !important; + display: inline-flex !important; + flex-wrap: wrap; + justify-content: center; + width: auto !important; + margin-bottom: 20px; + } + + ul.nav.nav-pills .nav-item { + margin: 0 2px; + } + + ul.nav.nav-pills .nav-link { + border-radius: 50rem !important; + padding: 8px 20px !important; + color: #94a3b8 !important; + font-weight: 600; + transition: all 0.3s ease; + } + + ul.nav.nav-pills .nav-link:hover { + background-color: rgba(255, 255, 255, 0.1); + color: #fff !important; + transform: translateY(-1px); + } + + ul.nav.nav-pills .nav-link.active { + background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important; + color: #fff !important; + box-shadow: 0 4px 12px rgba(37, 99, 235, 0.4); + } diff --git a/templates/anime_downloader_ohli24_request.html b/templates/anime_downloader_ohli24_request.html index e1ab46e..1912fb2 100644 --- a/templates/anime_downloader_ohli24_request.html +++ b/templates/anime_downloader_ohli24_request.html @@ -20,11 +20,24 @@
-
+
- {{ macros.setting_input_text_and_buttons('code', '작품 Code', [['analysis_btn', '분석'], - ['go_ohli24_btn', 'Go OHLI24']], desc='예) "https://ohli24.net/c/녹을 먹는 비스코" 이나 "녹을 - 먹는 비스코"') }} +
+
+ +
+ +
+ + +
+
+
+ + 예) "https://ohli24.net/c/녹을 먹는 비스코" 또는 "녹을 먹는 비스코" +
+
+
@@ -53,6 +66,8 @@ }; const wait3seconds = function () { + // Force parent container to be fluid to allow full width + $("#main_container").removeClass("container").addClass("container-fluid"); // REFERENCE: https://www.w3schools.com/jsref/met_win_settimeout.asp const result = setTimeout(dismissLoadingScreen, 2000); }; @@ -102,50 +117,74 @@ function make_program(data) { current_data = data; - console.log(data) - console.log("current_data::", current_data) - let str = ''; - let tmp = ''; - tmp = '
' - tmp += m_button('check_download_btn', '선택 다운로드 추가', []); - tmp += m_button('all_check_on_btn', '전체 선택', []); - tmp += m_button('all_check_off_btn', '전체 해제', []); - /* - tmp += '    ' - tmp += '
' - 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 += "
" - str += m_row_start(0); - tmp = '' - if (data.image != null) - tmp = ''; - str += m_col(3, tmp) - tmp = '' - var des = data.des || {}; - 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, des._otit || '') + m_row_end(); - tmp += m_row_start(2) + m_col(3, '감독', 'right') + m_col(9, des._dir || '') + m_row_end(); - tmp += m_row_start(2) + m_col(3, '제작사', 'right') + m_col(9, des._pub || '') + m_row_end(); - tmp += m_row_start(2) + m_col(3, '장르', 'right') + m_col(9, des._tag || '') + m_row_end(); - tmp += m_row_start(2) + m_col(3, '분류', 'right') + m_col(9, 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, des._grade || '') + m_row_end(); - tmp += m_row_start(2) + m_col(3, '총화수', 'right') + m_col(9, des._total_chapter || '') + m_row_end(); - tmp += m_row_start(2) + m_col(3, '상영시간', 'right') + m_col(9, 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(); + console.log(data); + + let str = ""; + + // 1. Info Card (Top) + str += `
`; + str += `
`; + + // Poster + str += `
`; + if (data.image) { + str += ``; + } + str += `
`; + + // Details + str += `
`; + str += `

${data.title || ''}

`; + + // Subtitle / Original Title + const des = data.des || {}; + if (des._otit) { + str += `
${des._otit}
`; + } - str += "
" - {#str += m_hr_black();#} - - // 에피소드 카드 그리드 레이아웃 + // Tags (Genre, etc.) + str += `
`; + if (des._tag) str += `${des._tag}`; + if (des._grade) str += `${des._grade}`; + if (data.date || data.day) str += `${data.date || ''} (${data.day || ''})`; + str += `
`; + + // Table for details (Grid) + str += `
`; + // Helper to add detail item + const addDetail = (label, val) => { + if(val) str += `
${label}: ${val}
`; + }; + + addDetail("감독", des._dir); + addDetail("제작사", des._pub); + addDetail("분류", des._classifi); + addDetail("총화수", des._total_chapter); + addDetail("상영시간", des._show_time); + + if (data.ser_description) { + str += `
줄거리:

${data.ser_description}

`; + } + str += `
`; // End detail row + + // Actions Toolbar + str += `
`; + + // Standard Actions + str += ``; + str += ``; + str += ``; + + // Scheduling (Heart) + str += ``; + + str += `
`; // End Action Toolbar + + str += `
`; // End Col-9 + str += `
`; // End Row + str += `
`; // End Card + + // Episode List (Reuse existing logic or standard logic) str += '
'; for (let i in data.episode) { let epThumbSrc = data.episode[i].thumbnail || ''; @@ -177,6 +216,7 @@ str += '
'; } str += '
'; + document.getElementById("episode_list").innerHTML = str; $('input[id^="checkbox_"]').bootstrapToggle() } @@ -267,6 +307,33 @@ }); + $("body").on('click', '#add_whitelist', function (e) { + e.preventDefault(); + const code = document.getElementById("code").value || params.code; + const $btn = $(this); + $.ajax({ + url: '/' + package_name + '/ajax/' + sub + '/add_whitelist', + type: "POST", + cache: false, + data: JSON.stringify({data_code: code}), + contentType: "application/json;charset=UTF-8", + dataType: "json", + success: function (ret) { + if (ret.ret) { + $.notify('스케쥴링 목록에 추가하였습니다.', {type: 'success'}); + $btn.html(' 추가됨').removeClass('btn-outline-danger').addClass('btn-danger'); + } else { + if (ret.log == "이미 추가되어 있습니다.") { + $.notify('이미 추가되어 있습니다.', {type: 'warning'}); + $btn.html(' 추가됨').removeClass('btn-outline-danger').addClass('btn-danger'); + } else { + $.notify('추가 실패
' + ret.log, {type: 'warning'}); + } + } + } + }); + }); + $("body").on('click', '#go_ohli24_btn', function (e) { e.preventDefault(); window.open("{{arg['ohli24_url']}}", "_blank"); @@ -1024,6 +1091,45 @@ border-color: #0dcaf0 !important; } + /* Navigation Menu Override */ + ul.nav.nav-pills.bg-light { + background-color: rgba(30, 41, 59, 0.6) !important; + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 50rem !important; + padding: 6px !important; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2) !important; + display: inline-flex !important; + flex-wrap: wrap; + justify-content: center; + width: auto !important; + margin-bottom: 20px; + } + + ul.nav.nav-pills .nav-item { + margin: 0 2px; + } + + ul.nav.nav-pills .nav-link { + border-radius: 50rem !important; + padding: 8px 20px !important; + color: #94a3b8 !important; + font-weight: 600; + transition: all 0.3s ease; + } + + ul.nav.nav-pills .nav-link:hover { + background-color: rgba(255, 255, 255, 0.1); + color: #fff !important; + transform: translateY(-1px); + } + + ul.nav.nav-pills .nav-link.active { + background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important; + color: #fff !important; + box-shadow: 0 4px 12px rgba(37, 99, 235, 0.4); + } + /* 로딩 인디케이터 오버라이드 */ #loading { background: rgba(15, 23, 42, 0.85) !important; diff --git a/templates/anime_downloader_ohli24_search.html b/templates/anime_downloader_ohli24_search.html index 215bafd..b0a3afc 100644 --- a/templates/anime_downloader_ohli24_search.html +++ b/templates/anime_downloader_ohli24_search.html @@ -19,39 +19,45 @@
-
-
- - +
+ +
+
+
+
+ +
+ +
+
+
+
+ + +
+
+ + + +
+
-
- - - -
-
+
@@ -159,176 +165,153 @@ }) } + // Common card HTML generator to ensure consistency + function generate_card_html(item, linkUrl) { + let tmp = ''; // End wrapper + return tmp; + } + function make_airing_list(data, page) { let str = '' - let tmp = '' - - str += '
'; - str += ''; + + str += '
'; + str += '
방영중 애니메이션
'; + str += ''; str += '
'; - // str += '
' - str += '
'; + + str += ''; - str += tmp - + let item = data.anime_list[i]; + let request_url = './request?code=' + item.code; + str += generate_card_html(item, request_url); } str += '
'; - // str += '
'; + 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 += '
'; - str += ''; + let list = data.anime_list || []; + + str += '
'; + str += '
검색 결과
'; + str += ''; str += '
'; - // str += '
' - str += '
'; - for (let i in data.anime_list) { - if (data.anime_list[i].wr_id !== '') { + + str += '
'; + + for (let i in list) { + let item = list[i]; + let request_url = './request?code=' + item.code; + + if (item.wr_id !== '' && item.wr_id !== undefined) { const re = /bo_table=([^&]+)/ - const bo_table = data.anime_list[i].link.match(re) - console.log(bo_table) + const bo_table = item.link.match(re) if (bo_table != null) { - request_url = './request?code=' + data.anime_list[i].code + '&wr_id=' + data.anime_list[i].wr_id + '&bo_table=' + bo_table[1] - } else { - request_url = './request?code=' + data.anime_list[i].code + request_url += '&wr_id=' + item.wr_id + '&bo_table=' + bo_table[1]; } - } else { - request_url = './request?code=' + data.anime_list[i].code } - - tmp = '
'; - tmp += '
'; - tmp += ''; - tmp += '
' - // {#tmp += '
';#} - tmp += '
' + data.anime_list[i].title + '
'; - tmp += '

' + data.anime_list[i].code + '

'; - tmp += '' + data.anime_list[i].title + ''; - tmp += '
'; - tmp += '
'; - tmp += '
'; - str += tmp - + + str += generate_card_html(item, request_url); } str += '
'; - str += '
'; 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 += '
'; - str += ''; + let str = ''; + + str += '
'; + let title = current_cate === 'movie' ? '극장판' : (current_cate === 'theater' ? '극장판(구)' : '완결 애니메이션'); + str += '
' + title + '
'; + str += ''; str += '
'; - // str += '
' - str += '
'; + + str += '
'; for (let i in data.anime_list) { - - tmp = '
'; - tmp += '
'; - tmp += ''; - tmp += '
' - tmp += '
' + data.anime_list[i].title + '
'; - tmp += '

' + data.anime_list[i].code + '

'; - tmp += '' + data.anime_list[i].title + ''; - tmp += '
'; - tmp += '
'; - tmp += '
'; - str += tmp - + let item = data.anime_list[i]; + let request_url = './request?code=' + item.code; + + str += generate_card_html(item, request_url); } str += '
'; - // str += '
'; 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 () { + // Force parent container to be fluid to allow full width + $("#main_container").removeClass("container").addClass("container-fluid"); // if ( "{{arg['anilife_current_code']}}" !== "" ) { // document.getElementById("code").value = "{{arg['anilife_current_code']}}"; @@ -579,351 +562,164 @@ document.addEventListener("scroll", debounce(onScroll, 300)); - + + {% endblock %} diff --git a/templates/anime_downloader_ohli24_setting.html b/templates/anime_downloader_ohli24_setting.html index e48ce2a..689128e 100644 --- a/templates/anime_downloader_ohli24_setting.html +++ b/templates/anime_downloader_ohli24_setting.html @@ -1,49 +1,242 @@ {% extends "base.html" %} {% block content %} -
- {{ macros.m_button_group([['globalSettingSaveBtn', '설정 저장']])}} - {{ macros.m_row_start('5') }} - {{ macros.m_row_end() }} - - -