feat: Enhance loading indicator UI with custom spinners and improve download cancellation logic for custom downloaders.

This commit is contained in:
2025-12-29 20:42:59 +09:00
parent 6b9432ca4d
commit 8ecb8f33ce
7 changed files with 257 additions and 8 deletions

View File

@@ -632,10 +632,18 @@ class FfmpegQueue(object):
ret["ret"] = "notify" ret["ret"] = "notify"
ret["log"] = "다운로드중 상태가 아닙니다." ret["log"] = "다운로드중 상태가 아닙니다."
else: else:
idx = entity.ffmpeg_arg["data"]["idx"] # ffmpeg_arg가 있는 경우에만 ffmpeg 모듈로 중지
import ffmpeg if entity.ffmpeg_arg is not None and entity.ffmpeg_arg.get("data") is not None:
try:
ffmpeg.Ffmpeg.stop_by_idx(idx) idx = entity.ffmpeg_arg["data"].get("idx")
if idx is not None:
import ffmpeg
ffmpeg.Ffmpeg.stop_by_idx(idx)
except Exception as e:
logger.debug(f"ffmpeg stop error (non-critical): {e}")
# 커스텀 다운로더의 경우 cancel 플래그만 설정
entity.cancel = True
entity.ffmpeg_status_kor = "취소"
entity.refresh_status() entity.refresh_status()
ret["ret"] = "refresh" ret["ret"] = "refresh"
elif cmd == "reset": elif cmd == "reset":
@@ -643,11 +651,20 @@ class FfmpegQueue(object):
with self.download_queue.mutex: with self.download_queue.mutex:
self.download_queue.queue.clear() self.download_queue.queue.clear()
for _ in self.entity_list: for _ in self.entity_list:
# 다운로드중 상태인 경우에만 중지 시도
if _.ffmpeg_status == 5: if _.ffmpeg_status == 5:
import ffmpeg # ffmpeg_arg가 있는 경우에만 ffmpeg 모듈로 중지
if _.ffmpeg_arg is not None and _.ffmpeg_arg.get("data") is not None:
idx = _.ffmpeg_arg["data"]["idx"] try:
ffmpeg.Ffmpeg.stop_by_idx(idx) import ffmpeg
idx = _.ffmpeg_arg["data"].get("idx")
if idx is not None:
ffmpeg.Ffmpeg.stop_by_idx(idx)
except Exception as e:
logger.debug(f"ffmpeg stop error (non-critical): {e}")
# 커스텀 다운로더의 경우 cancel 플래그만 설정
_.cancel = True
_.ffmpeg_status_kor = "취소"
self.entity_list = [] self.entity_list = []
ret["ret"] = "refresh" ret["ret"] = "refresh"
elif cmd == "delete_completed": elif cmd == "delete_completed":

View File

@@ -259,4 +259,43 @@
} }
</script> </script>
<style>
/* 로딩 인디케이터 오버라이드 */
#loading {
background: rgba(15, 23, 42, 0.85) !important;
backdrop-filter: blur(8px) !important;
}
#loading img {
display: none !important;
}
#loading::after {
content: '';
width: 50px;
height: 50px;
border: 4px solid rgba(96, 165, 250, 0.2);
border-top-color: #60a5fa;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
#modal_loading img {
display: none !important;
}
#modal_loading::after {
content: '';
width: 40px;
height: 40px;
border: 3px solid rgba(96, 165, 250, 0.2);
border-top-color: #60a5fa;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
</style>
{% endblock %} {% endblock %}

View File

@@ -933,5 +933,43 @@
transform: rotate(360deg); transform: rotate(360deg);
} }
} }
/* 로딩 인디케이터 오버라이드 */
#loading {
background: rgba(15, 23, 42, 0.85) !important;
backdrop-filter: blur(8px) !important;
}
#loading img {
display: none !important;
}
#loading::after {
content: '';
width: 50px;
height: 50px;
border: 4px solid rgba(96, 165, 250, 0.2);
border-top-color: #60a5fa;
border-radius: 50%;
animation: loader-spin 0.8s linear infinite;
}
@keyframes loader-spin {
to { transform: rotate(360deg); }
}
#modal_loading img {
display: none !important;
}
#modal_loading::after {
content: '';
width: 40px;
height: 40px;
border: 3px solid rgba(96, 165, 250, 0.2);
border-top-color: #60a5fa;
border-radius: 50%;
animation: loader-spin 0.8s linear infinite;
}
</style> </style>
{% endblock %} {% endblock %}

View File

@@ -307,4 +307,43 @@ function status_html(data) {
} }
</script> </script>
<style>
/* 로딩 인디케이터 오버라이드 */
#loading {
background: rgba(15, 23, 42, 0.85) !important;
backdrop-filter: blur(8px) !important;
}
#loading img {
display: none !important;
}
#loading::after {
content: '';
width: 50px;
height: 50px;
border: 4px solid rgba(96, 165, 250, 0.2);
border-top-color: #60a5fa;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
#modal_loading img {
display: none !important;
}
#modal_loading::after {
content: '';
width: 40px;
height: 40px;
border: 3px solid rgba(96, 165, 250, 0.2);
border-top-color: #60a5fa;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
</style>
{% endblock %} {% endblock %}

View File

@@ -934,5 +934,43 @@
z-index: 99999; z-index: 99999;
opacity: 0.5; opacity: 0.5;
} }
/* 로딩 인디케이터 오버라이드 */
#loading {
background: rgba(15, 23, 42, 0.85) !important;
backdrop-filter: blur(8px) !important;
}
#loading img {
display: none !important;
}
#loading::after {
content: '';
width: 50px;
height: 50px;
border: 4px solid rgba(96, 165, 250, 0.2);
border-top-color: #60a5fa;
border-radius: 50%;
animation: loader-spin 0.8s linear infinite;
}
@keyframes loader-spin {
to { transform: rotate(360deg); }
}
#modal_loading img {
display: none !important;
}
#modal_loading::after {
content: '';
width: 40px;
height: 40px;
border: 3px solid rgba(96, 165, 250, 0.2);
border-top-color: #60a5fa;
border-radius: 50%;
animation: loader-spin 0.8s linear infinite;
}
</style> </style>
{% endblock %} {% endblock %}

View File

@@ -361,6 +361,45 @@
font-size: 15px; font-size: 15px;
} }
} }
/* 로딩 인디케이터 오버라이드 */
#loading {
background: rgba(15, 23, 42, 0.85) !important;
backdrop-filter: blur(8px) !important;
}
#loading img {
display: none !important;
}
#loading::after {
content: '';
width: 50px;
height: 50px;
border: 4px solid rgba(96, 165, 250, 0.2);
border-top-color: #60a5fa;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* 모달 로딩 인디케이터 오버라이드 */
#modal_loading img {
display: none !important;
}
#modal_loading::after {
content: '';
width: 40px;
height: 40px;
border: 3px solid rgba(96, 165, 250, 0.2);
border-top-color: #60a5fa;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
</style> </style>
<script src="{{ url_for('.static', filename='js/sjva_ui14.js') }}"></script> <script src="{{ url_for('.static', filename='js/sjva_ui14.js') }}"></script>

View File

@@ -1023,5 +1023,44 @@
background-color: #0dcaf0 !important; background-color: #0dcaf0 !important;
border-color: #0dcaf0 !important; border-color: #0dcaf0 !important;
} }
/* 로딩 인디케이터 오버라이드 */
#loading {
background: rgba(15, 23, 42, 0.85) !important;
backdrop-filter: blur(8px) !important;
}
#loading img {
display: none !important;
}
#loading::after {
content: '';
width: 50px;
height: 50px;
border: 4px solid rgba(96, 165, 250, 0.2);
border-top-color: #60a5fa;
border-radius: 50%;
animation: loader-spin 0.8s linear infinite;
}
@keyframes loader-spin {
to { transform: rotate(360deg); }
}
/* 모달 로딩 인디케이터 오버라이드 */
#modal_loading img {
display: none !important;
}
#modal_loading::after {
content: '';
width: 40px;
height: 40px;
border: 3px solid rgba(96, 165, 250, 0.2);
border-top-color: #60a5fa;
border-radius: 50%;
animation: loader-spin 0.8s linear infinite;
}
</style> </style>
{% endblock %} {% endblock %}