Refactor: Ohli24 UI refinement and mobile responsiveness fixes

This commit is contained in:
2026-01-05 02:45:40 +09:00
parent bda7d16c1c
commit 883b8d172b
11 changed files with 75 additions and 40 deletions

View File

@@ -1,5 +1,5 @@
title: "애니 다운로더"
version: "0.5.35"
version: "0.5.36"
package_name: "anime_downloader"
developer: "projectdx"
description: "anime downloader"

View File

@@ -9,10 +9,10 @@ from datetime import datetime
import requests
# from flaskfarm.lib.plugin import get_model_setting
from flaskfarm.lib.support.expand.ffmpeg import SupportFfmpeg
from support.expand.ffmpeg import SupportFfmpeg
# from flaskfarm.lib.system.setup import SystemModelSetting
from flaskfarm.lib.tool import ToolUtil
from tool import ToolUtil
# from flaskfarm.lib.system.setup import P as SM
# from flaskfarm.lib.system.mod_setting import ModuleSetting as SM

View File

@@ -690,7 +690,7 @@ class LogicAniLife(AnimeModuleBase):
"msg": "%s 개의 에피소드를 큐에 추가 하였습니다." % count,
}
socketio.emit(
"notify", notify, namespace="/framework", broadcast=True
"notify", notify, namespace="/framework"
)
thread = threading.Thread(target=func, args=())
thread.daemon = True

View File

@@ -1,5 +1,5 @@
from flask import render_template, request, jsonify
from flaskfarm.lib.plugin import PluginModuleBase
from plugin import PluginModuleBase
import framework
import os, traceback, time, json
from datetime import datetime
@@ -177,7 +177,7 @@ class AnimeModuleBase(PluginModuleBase):
namespace = f"/{self.P.package_name}/{self.name}/queue"
# 큐 페이지 소켓에 직접 emit
socketio.emit(refresh_type, data, namespace=namespace, broadcast=True)
socketio.emit(refresh_type, data, namespace=namespace)
except Exception as e:
self.P.logger.error(f"socketio_callback error: {e}")

View File

@@ -22,7 +22,7 @@ from bs4 import BeautifulSoup
# third-party
from flask import jsonify, render_template, request
from flaskfarm.lib.support.expand.ffmpeg import SupportFfmpeg
from support.expand.ffmpeg import SupportFfmpeg
# sjva 공용
from framework import db, path_data, scheduler
@@ -479,7 +479,7 @@ class LogicLinkkf(AnimeModuleBase):
"""
logger.info(f">>> socketio_callback called: {refresh_type}, {data.get('percent', 'N/A')}%")
try:
from flaskfarm.lib.framework.init_main import socketio
from framework import socketio
# FlaskFarm의 기존 패턴: /framework namespace로 emit
# queue 페이지의 소켓이 이 메시지를 받아서 처리

View File

@@ -530,7 +530,7 @@ class LogicOhli24(AnimeModuleBase):
"type": "success",
"msg": "%s 개의 에피소드를 큐에 추가 하였습니다." % count,
}
socketio.emit("notify", notify, namespace="/framework", broadcast=True)
socketio.emit("notify", notify, namespace="/framework")
thread = threading.Thread(target=func, args=())
thread.daemon = True
@@ -2091,7 +2091,7 @@ class LogicOhli24(AnimeModuleBase):
+ args["data"]["save_fullpath"],
"url": "/ffmpeg/download/list",
}
# socketio.emit("notify", data, namespace='/framework', broadcast=True)
# socketio.emit("notify", data, namespace='/framework')
refresh_type = "add"
elif args["type"] == "last":
entity = self.queue.get_entity_by_entity_id(args['data']['callback_id'])
@@ -2099,7 +2099,7 @@ class LogicOhli24(AnimeModuleBase):
if args["status"] == SupportFfmpeg.Status.WRONG_URL:
if entity: entity.download_failed("WRONG_URL")
data = {"type": "warning", "msg": "잘못된 URL입니다"}
socketio.emit("notify", data, namespace="/framework", broadcast=True)
socketio.emit("notify", data, namespace="/framework")
refresh_type = "add"
elif args["status"] == SupportFfmpeg.Status.WRONG_DIRECTORY:
if entity: entity.download_failed("WRONG_DIRECTORY")
@@ -2107,7 +2107,7 @@ class LogicOhli24(AnimeModuleBase):
"type": "warning",
"msg": "잘못된 디렉토리입니다.<br>" + args["data"]["save_fullpath"],
}
socketio.emit("notify", data, namespace="/framework", broadcast=True)
socketio.emit("notify", data, namespace="/framework")
refresh_type = "add"
elif args["status"] == SupportFfmpeg.Status.ERROR or args["status"] == SupportFfmpeg.Status.EXCEPTION:
if entity: entity.download_failed("ERROR/EXCEPTION")
@@ -2115,7 +2115,7 @@ class LogicOhli24(AnimeModuleBase):
"type": "warning",
"msg": "다운로드 시작 실패.<br>" + args["data"]["save_fullpath"],
}
socketio.emit("notify", data, namespace="/framework", broadcast=True)
socketio.emit("notify", data, namespace="/framework")
refresh_type = "add"
elif args["status"] == SupportFfmpeg.Status.USER_STOP:
if entity: entity.download_failed("USER_STOP")
@@ -2124,7 +2124,7 @@ class LogicOhli24(AnimeModuleBase):
"msg": "다운로드가 중지 되었습니다.<br>" + args["data"]["save_fullpath"],
"url": "/ffmpeg/download/list",
}
socketio.emit("notify", data, namespace="/framework", broadcast=True)
socketio.emit("notify", data, namespace="/framework")
refresh_type = "last"
elif args["status"] == SupportFfmpeg.Status.COMPLETED:
logger.debug("download completed........")
@@ -2134,7 +2134,7 @@ class LogicOhli24(AnimeModuleBase):
"url": "/ffmpeg/download/list",
}
socketio.emit("notify", data, namespace="/framework", broadcast=True)
socketio.emit("notify", data, namespace="/framework")
refresh_type = "last"
elif args["status"] == SupportFfmpeg.Status.TIME_OVER:
@@ -2144,7 +2144,7 @@ class LogicOhli24(AnimeModuleBase):
"msg": "시간초과로 중단 되었습니다.<br>" + args["data"]["save_fullpath"],
"url": "/ffmpeg/download/list",
}
socketio.emit("notify", data, namespace="/framework", broadcast=True)
socketio.emit("notify", data, namespace="/framework")
refresh_type = "last"
elif args["status"] == SupportFfmpeg.Status.PF_STOP:
if entity: entity.download_failed("PF_STOP")
@@ -2153,7 +2153,7 @@ class LogicOhli24(AnimeModuleBase):
"msg": "PF초과로 중단 되었습니다.<br>" + args["data"]["save_fullpath"],
"url": "/ffmpeg/download/list",
}
socketio.emit("notify", data, namespace="/framework", broadcast=True)
socketio.emit("notify", data, namespace="/framework")
refresh_type = "last"
elif args["status"] == SupportFfmpeg.Status.FORCE_STOP:
if entity: entity.download_failed("FORCE_STOP")
@@ -2162,7 +2162,7 @@ class LogicOhli24(AnimeModuleBase):
"msg": "강제 중단 되었습니다.<br>" + args["data"]["save_fullpath"],
"url": "/ffmpeg/download/list",
}
socketio.emit("notify", data, namespace="/framework", broadcast=True)
socketio.emit("notify", data, namespace="/framework")
refresh_type = "last"
elif args["status"] == SupportFfmpeg.Status.HTTP_FORBIDDEN:
if entity: entity.download_failed("HTTP_FORBIDDEN")
@@ -2171,7 +2171,7 @@ class LogicOhli24(AnimeModuleBase):
"msg": "403에러로 중단 되었습니다.<br>" + args["data"]["save_fullpath"],
"url": "/ffmpeg/download/list",
}
socketio.emit("notify", data, namespace="/framework", broadcast=True)
socketio.emit("notify", data, namespace="/framework")
refresh_type = "last"
elif args["status"] == SupportFfmpeg.Status.ALREADY_DOWNLOADING:
# Already downloading usually means logic error or race condition, maybe not fail DB?
@@ -2181,7 +2181,7 @@ class LogicOhli24(AnimeModuleBase):
"msg": "임시파일폴더에 파일이 있습니다.<br>" + args["data"]["temp_fullpath"],
"url": "/ffmpeg/download/list",
}
socketio.emit("notify", data, namespace="/framework", broadcast=True)
socketio.emit("notify", data, namespace="/framework")
refresh_type = "last"
elif args["type"] == "normal":
if args["status"] == SupportFfmpeg.Status.DOWNLOADING:
@@ -2791,25 +2791,25 @@ class Ohli24QueueEntity(AnimeQueueEntity):
# data = {'type': 'info',
# 'msg': '다운로드중 Duration(%s)' % args['data']['duration_str'] + '<br>' + args['data'][
# 'save_fullpath'], 'url': '/ffmpeg/download/list'}
# socketio.emit("notify", data, namespace='/framework', broadcast=True)
# socketio.emit("notify", data, namespace='/framework')
# refresh_type = 'add'
# elif args['type'] == 'last':
# if args['status'] == SupportFfmpeg.Status.WRONG_URL:
# data = {'type': 'warning', 'msg': '잘못된 URL입니다'}
# socketio.emit("notify", data, namespace='/framework', broadcast=True)
# socketio.emit("notify", data, namespace='/framework')
# refresh_type = 'add'
# elif args['status'] == SupportFfmpeg.Status.WRONG_DIRECTORY:
# data = {'type': 'warning', 'msg': '잘못된 디렉토리입니다.<br>' + args['data']['save_fullpath']}
# socketio.emit("notify", data, namespace='/framework', broadcast=True)
# socketio.emit("notify", data, namespace='/framework')
# refresh_type = 'add'
# elif args['status'] == SupportFfmpeg.Status.ERROR or args['status'] == SupportFfmpeg.Status.EXCEPTION:
# data = {'type': 'warning', 'msg': '다운로드 시작 실패.<br>' + args['data']['save_fullpath']}
# socketio.emit("notify", data, namespace='/framework', broadcast=True)
# socketio.emit("notify", data, namespace='/framework')
# refresh_type = 'add'
# elif args['status'] == SupportFfmpeg.Status.USER_STOP:
# data = {'type': 'warning', 'msg': '다운로드가 중지 되었습니다.<br>' + args['data']['save_fullpath'],
# 'url': '/ffmpeg/download/list'}
# socketio.emit("notify", data, namespace='/framework', broadcast=True)
# socketio.emit("notify", data, namespace='/framework')
# refresh_type = 'last'
# elif args['status'] == SupportFfmpeg.Status.COMPLETED:
# logger.debug('ffmpeg download completed......')
@@ -2818,32 +2818,32 @@ class Ohli24QueueEntity(AnimeQueueEntity):
# 'url': '/ffmpeg/download/list'}
#
#
# socketio.emit("notify", data, namespace='/framework', broadcast=True)
# socketio.emit("notify", data, namespace='/framework')
# refresh_type = 'last'
# elif args['status'] == SupportFfmpeg.Status.TIME_OVER:
# data = {'type': 'warning', 'msg': '시간초과로 중단 되었습니다.<br>' + args['data']['save_fullpath'],
# 'url': '/ffmpeg/download/list'}
# socketio.emit("notify", data, namespace='/framework', broadcast=True)
# socketio.emit("notify", data, namespace='/framework')
# refresh_type = 'last'
# elif args['status'] == SupportFfmpeg.Status.PF_STOP:
# data = {'type': 'warning', 'msg': 'PF초과로 중단 되었습니다.<br>' + args['data']['save_fullpath'],
# 'url': '/ffmpeg/download/list'}
# socketio.emit("notify", data, namespace='/framework', broadcast=True)
# socketio.emit("notify", data, namespace='/framework')
# refresh_type = 'last'
# elif args['status'] == SupportFfmpeg.Status.FORCE_STOP:
# data = {'type': 'warning', 'msg': '강제 중단 되었습니다.<br>' + args['data']['save_fullpath'],
# 'url': '/ffmpeg/download/list'}
# socketio.emit("notify", data, namespace='/framework', broadcast=True)
# socketio.emit("notify", data, namespace='/framework')
# refresh_type = 'last'
# elif args['status'] == SupportFfmpeg.Status.HTTP_FORBIDDEN:
# data = {'type': 'warning', 'msg': '403에러로 중단 되었습니다.<br>' + args['data']['save_fullpath'],
# 'url': '/ffmpeg/download/list'}
# socketio.emit("notify", data, namespace='/framework', broadcast=True)
# socketio.emit("notify", data, namespace='/framework')
# refresh_type = 'last'
# elif args['status'] == SupportFfmpeg.Status.ALREADY_DOWNLOADING:
# data = {'type': 'warning', 'msg': '임시파일폴더에 파일이 있습니다.<br>' + args['data']['temp_fullpath'],
# 'url': '/ffmpeg/download/list'}
# socketio.emit("notify", data, namespace='/framework', broadcast=True)
# socketio.emit("notify", data, namespace='/framework')
# refresh_type = 'last'
# elif args['type'] == 'normal':
# if args['status'] == SupportFfmpeg.Status.DOWNLOADING:

View File

@@ -1,2 +0,0 @@
# -*- coding: utf-8 -*-
from flaskfarm.lib.plugin import *

View File

@@ -73,8 +73,18 @@
flex-wrap: wrap; /* allow wrap on small screens */
justify-content: center;
width: auto !important; /* Prevent full width */
margin-bottom: 20px;
margin-top: 50px !important; /* Mobile spacing */
margin-bottom: 5px; /* Reduced for modularity */
margin-top: 50px !important; /* Mobile spacing - fallback for first menu */
}
/* Tighten spacing between 2nd and 3rd level menus */
#menu_module_div ul.nav.nav-pills.bg-light {
margin-bottom: 5px !important;
}
#menu_page_div ul.nav.nav-pills.bg-light {
margin-top: 0 !important;
margin-bottom: 20px !important;
}
ul.nav.nav-pills .nav-item {

View File

@@ -98,7 +98,7 @@ body {
color: #94a3b8;
}
/* Nav Pills Customization */
/* Nav Pills Customization (Shared styling, overrides in mobile_custom.css) */
ul.nav.nav-pills.bg-light {
background-color: rgba(30, 41, 59, 0.6) !important;
backdrop-filter: blur(10px);
@@ -110,7 +110,7 @@ ul.nav.nav-pills.bg-light {
flex-wrap: wrap;
justify-content: center;
width: auto !important;
margin-bottom: 20px;
margin-bottom: 5px; /* Default for modular stacking */
}
ul.nav.nav-pills .nav-link {
@@ -155,6 +155,29 @@ ul.nav.nav-pills .nav-link.active {
border: none !important;
}
/* Responsive Input Group for Search */
.input-group-responsive {
height: 50px;
}
.input-group-responsive .form-control {
height: 100% !important;
font-size: 1.1rem;
}
.input-group-responsive .btn {
height: 100% !important;
}
@media (max-width: 768px) {
.input-group-responsive {
height: 42px;
}
.input-group-responsive .form-control {
font-size: 0.95rem;
}
}
.btn-search { background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%); color: white !important; }
.btn-reset { background: rgba(148, 163, 184, 0.1); color: #94a3b8 !important; }

View File

@@ -1,6 +1,7 @@
{% extends "base.html" %} {% block content %}
<link rel="stylesheet" href="{{ url_for('.static', filename='css/mobile_custom.css') }}"/>
<link rel="stylesheet" href="{{ url_for('.static', filename='css/' ~ arg['sub'] ~ '.css') }}"/>
<link rel="stylesheet" href="{{ url_for('.static', filename='css/video_modal.css') }}"/>
<div id="preloader">
<div class="demo">
@@ -59,6 +60,9 @@
</form>
</div>
<!--전체-->
<!-- Video Modal Component -->
{% include 'anime_downloader/components/video_modal.html' %}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css">
<script src="{{ url_for('.static', filename='js/sjva_ui14.js') }}"></script>
@@ -188,7 +192,7 @@
// Standard Actions
if (data.first_exist_filepath) {
str += `<button type="button" class="btn btn-success btn-sm mr-2" onclick="play_video('${data.first_exist_filepath.replace(/\\/g, '\\\\')}', '${data.first_exist_filename}')"><i class="fa fa-play"></i> 재생</button>`;
str += `<button type="button" class="btn btn-success btn-sm mr-2 btn-watch" data-path="${data.first_exist_filepath.replace(/\\/g, '\\\\')}"><i class="fa fa-play"></i> 보기</button>`;
}
str += `<button id="check_download_btn" class="btn btn-primary btn-sm"><i class="fa fa-download"></i> 선택 다운로드</button>`;
str += `<button id="all_check_on_btn" class="btn btn-outline-light btn-sm">전체 선택</button>`;

View File

@@ -36,7 +36,7 @@
<div class="row align-items-center">
<div class="col-md-8 mx-auto">
<div class="input-group input-group-lg">
<div class="input-group input-group-responsive">
<input
id="input_search"
type="search"
@@ -119,7 +119,7 @@
const wait3seconds = function () {
// REFERENCE: https://www.w3schools.com/jsref/met_win_settimeout.asp
const result = setTimeout(dismissLoadingScreen, 2000);
const result = setTimeout(dismissLoadingScreen, 1000);
};
window.addEventListener("load", wait3seconds);