Update app.py
Browse files
app.py
CHANGED
|
@@ -79,6 +79,7 @@ def generate_ass_file(data: ProcessRequest, output_path: str):
|
|
| 79 |
border_style = 1
|
| 80 |
back_color = "&H00000000"
|
| 81 |
|
|
|
|
| 82 |
if s.backType == 'solid':
|
| 83 |
border_style = 3
|
| 84 |
outline = hex_to_ass(s.outlineColor, "00")
|
|
@@ -88,13 +89,13 @@ def generate_ass_file(data: ProcessRequest, output_path: str):
|
|
| 88 |
else:
|
| 89 |
border_style = 1
|
| 90 |
|
| 91 |
-
#
|
| 92 |
-
# بنابراین فونت سایز 100 یعنی تقریبا 1/10 ارتفاع تصویر.
|
| 93 |
header = f"""[Script Info]
|
| 94 |
ScriptType: v4.00+
|
| 95 |
PlayResX: 1080
|
| 96 |
PlayResY: 1920
|
| 97 |
WrapStyle: 1
|
|
|
|
| 98 |
|
| 99 |
[V4+ Styles]
|
| 100 |
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
|
|
@@ -330,10 +331,23 @@ async def interface():
|
|
| 330 |
.segment-row:focus-within { border-right-color: var(--accent); background: rgba(255,255,255,0.06); }
|
| 331 |
|
| 332 |
.seg-time { font-size: 0.75rem; color: var(--text-muted); margin-bottom: 5px; font-family: monospace; }
|
|
|
|
|
|
|
| 333 |
.seg-input {
|
| 334 |
-
width: 100%;
|
| 335 |
-
|
| 336 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 337 |
}
|
| 338 |
|
| 339 |
.control-group { margin-bottom: 18px; }
|
|
@@ -373,14 +387,18 @@ async def interface():
|
|
| 373 |
|
| 374 |
/* --- RESULT SECTION INLINE --- */
|
| 375 |
#inlineResult {
|
| 376 |
-
margin-
|
| 377 |
-
|
| 378 |
-
|
|
|
|
|
|
|
| 379 |
text-align: center;
|
| 380 |
display: none;
|
| 381 |
-
animation:
|
| 382 |
}
|
| 383 |
-
|
|
|
|
|
|
|
| 384 |
.dl-btn {
|
| 385 |
display: inline-block; margin-top: 15px; padding: 12px 30px;
|
| 386 |
background: var(--success); color: white; text-decoration: none;
|
|
@@ -436,6 +454,13 @@ async def interface():
|
|
| 436 |
<div class="settings-panel card">
|
| 437 |
<h2 style="color: var(--primary); margin-top:0;">🎨 استایل و خروجی</h2>
|
| 438 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 439 |
<div class="preview-box">
|
| 440 |
<div id="livePreview" class="preview-text">متن نمونه</div>
|
| 441 |
</div>
|
|
@@ -468,9 +493,9 @@ async def interface():
|
|
| 468 |
</div>
|
| 469 |
|
| 470 |
<div class="control-group">
|
| 471 |
-
<div class="control-label"><span>سایز متن</span> <span id="lblSize">
|
| 472 |
-
<!--
|
| 473 |
-
<input type="range" id="rngSize" min="30" max="
|
| 474 |
</div>
|
| 475 |
|
| 476 |
<div class="control-group">
|
|
@@ -479,15 +504,9 @@ async def interface():
|
|
| 479 |
</div>
|
| 480 |
|
| 481 |
<button class="btn btn-primary" onclick="startRender()">
|
| 482 |
-
<i class="fa-solid fa-wand-magic-sparkles"></i> ساخت
|
| 483 |
</button>
|
| 484 |
|
| 485 |
-
<!-- INLINE RESULT AREA -->
|
| 486 |
-
<div id="inlineResult">
|
| 487 |
-
<h3 style="color: var(--success);">✅ ویدیو آماده شد!</h3>
|
| 488 |
-
<video id="finalPlayer" controls class="result-video"></video>
|
| 489 |
-
<a id="dlBtn" href="#" download class="dl-btn">دانلود ویدیو</a>
|
| 490 |
-
</div>
|
| 491 |
</div>
|
| 492 |
|
| 493 |
<!-- TEXT EDITOR -->
|
|
@@ -532,7 +551,6 @@ async def interface():
|
|
| 532 |
|
| 533 |
renderSegments();
|
| 534 |
|
| 535 |
-
// Switch view
|
| 536 |
document.getElementById('view-upload').classList.remove('active');
|
| 537 |
document.getElementById('view-editor').classList.add('active');
|
| 538 |
updatePreview();
|
|
@@ -553,17 +571,11 @@ async def interface():
|
|
| 553 |
const div = document.createElement('div');
|
| 554 |
div.className = 'segment-row';
|
| 555 |
div.innerHTML = `
|
| 556 |
-
<div class="seg-time">${formatTime(seg.start)} - ${formatTime(seg.end)}</div>
|
| 557 |
<textarea class="seg-input" rows="1" oninput="updateSegment(${idx}, this)">${seg.text}</textarea>
|
| 558 |
`;
|
| 559 |
container.appendChild(div);
|
| 560 |
});
|
| 561 |
-
|
| 562 |
-
// Auto resize
|
| 563 |
-
document.querySelectorAll('.seg-input').forEach(tx => {
|
| 564 |
-
tx.style.height = 'auto';
|
| 565 |
-
tx.style.height = (tx.scrollHeight) + 'px';
|
| 566 |
-
});
|
| 567 |
}
|
| 568 |
|
| 569 |
function updateSegment(idx, el) {
|
|
@@ -605,8 +617,8 @@ async def interface():
|
|
| 605 |
document.getElementById('lblSize').innerText = size;
|
| 606 |
|
| 607 |
txt.style.fontFamily = font;
|
| 608 |
-
//
|
| 609 |
-
txt.style.fontSize = (size /
|
| 610 |
txt.style.color = color;
|
| 611 |
txt.style.bottom = (pos / 6) + 'px';
|
| 612 |
|
|
@@ -630,9 +642,7 @@ async def interface():
|
|
| 630 |
|
| 631 |
// --- RENDER ---
|
| 632 |
async function startRender() {
|
| 633 |
-
|
| 634 |
-
document.getElementById('inlineResult').style.display = 'none';
|
| 635 |
-
showLoader("در حال رندر ویدیو...");
|
| 636 |
|
| 637 |
const payload = {
|
| 638 |
file_id: appState.fileId,
|
|
@@ -662,11 +672,11 @@ async def interface():
|
|
| 662 |
const resultBox = document.getElementById('inlineResult');
|
| 663 |
resultBox.style.display = 'block';
|
| 664 |
|
| 665 |
-
//
|
| 666 |
document.getElementById('finalPlayer').src = data.url + "?t=" + Date.now();
|
| 667 |
document.getElementById('dlBtn').href = data.url;
|
| 668 |
|
| 669 |
-
//
|
| 670 |
resultBox.scrollIntoView({behavior: 'smooth'});
|
| 671 |
|
| 672 |
} catch(e) {
|
|
|
|
| 79 |
border_style = 1
|
| 80 |
back_color = "&H00000000"
|
| 81 |
|
| 82 |
+
# تنظیمات دقیقتر کادر برای دیده شدن بهتر
|
| 83 |
if s.backType == 'solid':
|
| 84 |
border_style = 3
|
| 85 |
outline = hex_to_ass(s.outlineColor, "00")
|
|
|
|
| 89 |
else:
|
| 90 |
border_style = 1
|
| 91 |
|
| 92 |
+
# تغییر مهم: ScaledBorderAndShadow برای اینکه در رزولوشنهای بالا حاشیه محو نشود
|
|
|
|
| 93 |
header = f"""[Script Info]
|
| 94 |
ScriptType: v4.00+
|
| 95 |
PlayResX: 1080
|
| 96 |
PlayResY: 1920
|
| 97 |
WrapStyle: 1
|
| 98 |
+
ScaledBorderAndShadow: yes
|
| 99 |
|
| 100 |
[V4+ Styles]
|
| 101 |
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
|
|
|
|
| 331 |
.segment-row:focus-within { border-right-color: var(--accent); background: rgba(255,255,255,0.06); }
|
| 332 |
|
| 333 |
.seg-time { font-size: 0.75rem; color: var(--text-muted); margin-bottom: 5px; font-family: monospace; }
|
| 334 |
+
|
| 335 |
+
/* اصلاح استایل تکست باکس برای دیده شدن متن */
|
| 336 |
.seg-input {
|
| 337 |
+
width: 100%;
|
| 338 |
+
background: rgba(0, 0, 0, 0.2); /* پسزمینه تیره */
|
| 339 |
+
border: 1px solid var(--border); /* کادر مشخص */
|
| 340 |
+
border-radius: 8px;
|
| 341 |
+
color: #fff; /* متن سفید */
|
| 342 |
+
font-size: 1.1rem;
|
| 343 |
+
font-family: inherit;
|
| 344 |
+
resize: vertical;
|
| 345 |
+
padding: 10px;
|
| 346 |
+
min-height: 60px;
|
| 347 |
+
}
|
| 348 |
+
.seg-input:focus {
|
| 349 |
+
border-color: var(--primary);
|
| 350 |
+
background: rgba(0, 0, 0, 0.3);
|
| 351 |
}
|
| 352 |
|
| 353 |
.control-group { margin-bottom: 18px; }
|
|
|
|
| 387 |
|
| 388 |
/* --- RESULT SECTION INLINE --- */
|
| 389 |
#inlineResult {
|
| 390 |
+
margin-bottom: 20px; /* فاصله از دکمه */
|
| 391 |
+
padding: 20px;
|
| 392 |
+
border: 2px solid var(--success);
|
| 393 |
+
border-radius: 16px;
|
| 394 |
+
background: rgba(16, 185, 129, 0.05);
|
| 395 |
text-align: center;
|
| 396 |
display: none;
|
| 397 |
+
animation: slideDown 0.5s ease;
|
| 398 |
}
|
| 399 |
+
@keyframes slideDown { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: translateY(0); } }
|
| 400 |
+
|
| 401 |
+
.result-video { width: 100%; border-radius: 12px; margin-top: 10px; box-shadow: 0 10px 30px rgba(0,0,0,0.3); }
|
| 402 |
.dl-btn {
|
| 403 |
display: inline-block; margin-top: 15px; padding: 12px 30px;
|
| 404 |
background: var(--success); color: white; text-decoration: none;
|
|
|
|
| 454 |
<div class="settings-panel card">
|
| 455 |
<h2 style="color: var(--primary); margin-top:0;">🎨 استایل و خروجی</h2>
|
| 456 |
|
| 457 |
+
<!-- INLINE RESULT AREA (MOVED UP) -->
|
| 458 |
+
<div id="inlineResult">
|
| 459 |
+
<h3 style="color: var(--success); margin:0;">✅ ویدیو آماده شد!</h3>
|
| 460 |
+
<video id="finalPlayer" controls class="result-video"></video>
|
| 461 |
+
<a id="dlBtn" href="#" download class="dl-btn">دانلود ویدیو</a>
|
| 462 |
+
</div>
|
| 463 |
+
|
| 464 |
<div class="preview-box">
|
| 465 |
<div id="livePreview" class="preview-text">متن نمونه</div>
|
| 466 |
</div>
|
|
|
|
| 493 |
</div>
|
| 494 |
|
| 495 |
<div class="control-group">
|
| 496 |
+
<div class="control-label"><span>سایز متن</span> <span id="lblSize">100</span></div>
|
| 497 |
+
<!-- افزایش بازه برای فونتهای بزرگ -->
|
| 498 |
+
<input type="range" id="rngSize" min="30" max="300" value="100" oninput="updatePreview()">
|
| 499 |
</div>
|
| 500 |
|
| 501 |
<div class="control-group">
|
|
|
|
| 504 |
</div>
|
| 505 |
|
| 506 |
<button class="btn btn-primary" onclick="startRender()">
|
| 507 |
+
<i class="fa-solid fa-wand-magic-sparkles"></i> شروع ساخت / بروزرسانی
|
| 508 |
</button>
|
| 509 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 510 |
</div>
|
| 511 |
|
| 512 |
<!-- TEXT EDITOR -->
|
|
|
|
| 551 |
|
| 552 |
renderSegments();
|
| 553 |
|
|
|
|
| 554 |
document.getElementById('view-upload').classList.remove('active');
|
| 555 |
document.getElementById('view-editor').classList.add('active');
|
| 556 |
updatePreview();
|
|
|
|
| 571 |
const div = document.createElement('div');
|
| 572 |
div.className = 'segment-row';
|
| 573 |
div.innerHTML = `
|
| 574 |
+
<div class="seg-time">${formatTime(seg.start)} -> ${formatTime(seg.end)}</div>
|
| 575 |
<textarea class="seg-input" rows="1" oninput="updateSegment(${idx}, this)">${seg.text}</textarea>
|
| 576 |
`;
|
| 577 |
container.appendChild(div);
|
| 578 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 579 |
}
|
| 580 |
|
| 581 |
function updateSegment(idx, el) {
|
|
|
|
| 617 |
document.getElementById('lblSize').innerText = size;
|
| 618 |
|
| 619 |
txt.style.fontFamily = font;
|
| 620 |
+
// تقسیم بر ۵ برای واقعیتر شدن پیشنمایش
|
| 621 |
+
txt.style.fontSize = (size / 5) + 'px';
|
| 622 |
txt.style.color = color;
|
| 623 |
txt.style.bottom = (pos / 6) + 'px';
|
| 624 |
|
|
|
|
| 642 |
|
| 643 |
// --- RENDER ---
|
| 644 |
async function startRender() {
|
| 645 |
+
showLoader("در حال ساخت ویدیو...");
|
|
|
|
|
|
|
| 646 |
|
| 647 |
const payload = {
|
| 648 |
file_id: appState.fileId,
|
|
|
|
| 672 |
const resultBox = document.getElementById('inlineResult');
|
| 673 |
resultBox.style.display = 'block';
|
| 674 |
|
| 675 |
+
// اضافه کردن زمان برای جلوگیری از کش
|
| 676 |
document.getElementById('finalPlayer').src = data.url + "?t=" + Date.now();
|
| 677 |
document.getElementById('dlBtn').href = data.url;
|
| 678 |
|
| 679 |
+
// اسکرول به نتیجه
|
| 680 |
resultBox.scrollIntoView({behavior: 'smooth'});
|
| 681 |
|
| 682 |
} catch(e) {
|