36f83ff72c
Introduced Python scripts for SRT subtitle checking and fixing, and added comprehensive documentation covering advanced features such as protocol detection, subtitle/audio/quality management, keyboard shortcuts, and touch gestures. Updated local settings to allow new build and Python commands, added TypeScript definitions for FLV, and implemented RTMP/FLV protocol support in the player. Removed CHANGELOG.md and made various improvements to styles and example app.
282 lines
10 KiB
Python
282 lines
10 KiB
Python
import re
|
||
from datetime import datetime, timedelta
|
||
|
||
def comprehensive_srt_check(file_path):
|
||
"""Kapsamlı SRT format kontrolü - tüm olası hataları yakalar."""
|
||
|
||
errors = []
|
||
warnings = []
|
||
|
||
with open(file_path, 'r', encoding='utf-8') as f:
|
||
lines = f.readlines()
|
||
|
||
i = 0
|
||
subtitle_count = 0
|
||
prev_end_time = None
|
||
|
||
while i < len(lines):
|
||
# Boş satırları atla
|
||
while i < len(lines) and lines[i].strip() == '':
|
||
i += 1
|
||
|
||
if i >= len(lines):
|
||
break
|
||
|
||
subtitle_count += 1
|
||
start_line = i + 1
|
||
|
||
# ===== 1. ALTYAZI NUMARASI KONTROLÜ =====
|
||
line_num = i + 1
|
||
line_content = lines[i].strip()
|
||
|
||
if not line_content:
|
||
errors.append(f"Satir {line_num}: Bos satir, altyazi numarasi bekleniyor")
|
||
i += 1
|
||
continue
|
||
|
||
if not line_content.isdigit():
|
||
errors.append(f"Satir {line_num}: Altyazi numarasi olmali, bulunan: '{line_content[:50]}'")
|
||
# Sonraki geçerli numarayı bulmaya çalış
|
||
while i < len(lines) and not lines[i].strip().isdigit():
|
||
i += 1
|
||
if i >= len(lines):
|
||
break
|
||
else:
|
||
actual_number = int(line_content)
|
||
if actual_number != subtitle_count:
|
||
warnings.append(f"Satir {line_num}: Numara sırası bozuk - beklenen: {subtitle_count}, bulunan: {actual_number}")
|
||
|
||
i += 1
|
||
|
||
# ===== 2. ZAMAN DAMGASI KONTROLÜ =====
|
||
if i >= len(lines):
|
||
errors.append(f"Altyazi {subtitle_count}: Zaman damgasi eksik (dosya sonu)")
|
||
break
|
||
|
||
line_num = i + 1
|
||
timestamp_line = lines[i].strip()
|
||
|
||
if not timestamp_line:
|
||
errors.append(f"Satir {line_num}: Bos satir, zaman damgasi bekleniyor")
|
||
i += 1
|
||
continue
|
||
|
||
# Zaman damgası formatını detaylı kontrol et
|
||
if '-->' not in timestamp_line:
|
||
errors.append(f"Satir {line_num}: '-->' ayirici bulunamadi: '{timestamp_line[:50]}'")
|
||
i += 1
|
||
continue
|
||
|
||
parts = timestamp_line.split('-->')
|
||
if len(parts) != 2:
|
||
errors.append(f"Satir {line_num}: Gecersiz zaman damgasi formati: '{timestamp_line[:50]}'")
|
||
i += 1
|
||
continue
|
||
|
||
start_time_str = parts[0].strip()
|
||
end_time_str = parts[1].strip()
|
||
|
||
# Başlangıç zamanı kontrolü
|
||
start_errors = validate_timestamp(start_time_str, "baslangic")
|
||
if start_errors:
|
||
for err in start_errors:
|
||
errors.append(f"Satir {line_num} {err}: '{start_time_str}'")
|
||
|
||
# Bitiş zamanı kontrolü
|
||
end_errors = validate_timestamp(end_time_str, "bitis")
|
||
if end_errors:
|
||
for err in end_errors:
|
||
errors.append(f"Satir {line_num} {err}: '{end_time_str}'")
|
||
|
||
# Zamanları parse et ve mantıksal kontroller yap
|
||
if not start_errors and not end_errors:
|
||
start_ms = parse_timestamp_to_ms(start_time_str)
|
||
end_ms = parse_timestamp_to_ms(end_time_str)
|
||
|
||
if start_ms is None or end_ms is None:
|
||
errors.append(f"Satir {line_num}: Zaman parse edilemedi: '{timestamp_line}'")
|
||
else:
|
||
# Başlangıç >= Bitiş kontrolü
|
||
if start_ms >= end_ms:
|
||
errors.append(f"Satir {line_num}: Baslangic zamani bitis zamanindan buyuk/esit: {start_time_str} >= {end_time_str}")
|
||
|
||
# Negatif zaman kontrolü
|
||
if start_ms < 0 or end_ms < 0:
|
||
errors.append(f"Satir {line_num}: Negatif zaman degeri: '{timestamp_line}'")
|
||
|
||
# Çok uzun altyazı kontrolü (>10 saniye)
|
||
duration_ms = end_ms - start_ms
|
||
if duration_ms > 10000:
|
||
warnings.append(f"Satir {line_num}: Cok uzun altyazi suresi ({duration_ms/1000:.1f} saniye): {start_time_str} --> {end_time_str}")
|
||
|
||
# Çok kısa altyazı kontrolü (<0.1 saniye)
|
||
if duration_ms < 100:
|
||
warnings.append(f"Satir {line_num}: Cok kisa altyazi suresi ({duration_ms}ms): {start_time_str} --> {end_time_str}")
|
||
|
||
# Önceki altyazı ile çakışma kontrolü
|
||
if prev_end_time is not None and start_ms < prev_end_time:
|
||
time_overlap = prev_end_time - start_ms
|
||
warnings.append(f"Satir {line_num}: Onceki altyazi ile cakisma ({time_overlap}ms): {start_time_str}")
|
||
|
||
prev_end_time = end_ms
|
||
|
||
i += 1
|
||
|
||
# ===== 3. METİN İÇERİĞİ KONTROLÜ =====
|
||
text_lines = []
|
||
text_start_line = i + 1
|
||
|
||
while i < len(lines) and lines[i].strip() != '':
|
||
# Bir sonraki satır numara mı kontrol et (yeni altyazı başlangıcı)
|
||
if (i + 1 < len(lines) and
|
||
lines[i].strip().isdigit() and
|
||
'-->' in lines[i + 1]):
|
||
break
|
||
|
||
text_lines.append(lines[i].rstrip())
|
||
i += 1
|
||
|
||
if not text_lines:
|
||
warnings.append(f"Altyazi {subtitle_count} (satir {start_line}): Metin icerigi bos")
|
||
else:
|
||
# Metin kontrolü
|
||
full_text = ' '.join([t.strip() for t in text_lines])
|
||
|
||
# Çok uzun metin kontrolü
|
||
if len(full_text) > 200:
|
||
warnings.append(f"Altyazi {subtitle_count}: Cok uzun metin ({len(full_text)} karakter)")
|
||
|
||
# HTML tag kontrolü
|
||
if re.search(r'<[^>]+>', full_text):
|
||
warnings.append(f"Altyazi {subtitle_count}: HTML/XML tag iceriyor (bazi oynaticilar desteklemeyebilir)")
|
||
|
||
# Garip karakterler
|
||
if re.search(r'[\x00-\x08\x0B-\x0C\x0E-\x1F]', full_text):
|
||
warnings.append(f"Altyazi {subtitle_count}: Kontrol karakterleri iceriyor")
|
||
|
||
return errors, warnings, subtitle_count
|
||
|
||
|
||
def validate_timestamp(time_str, time_type):
|
||
"""Tek bir zaman damgasını (HH:MM:SS,mmm) doğrular."""
|
||
errors = []
|
||
|
||
# Format: HH:MM:SS,mmm
|
||
pattern = r'^(\d{2}):(\d{2}):(\d{2}),(\d{3})$'
|
||
match = re.match(pattern, time_str)
|
||
|
||
if not match:
|
||
# Hangi kısım hatalı bul
|
||
if ',' not in time_str and '.' not in time_str:
|
||
errors.append(f"({time_type}): Milisaniye ayirici eksik (virgul)")
|
||
elif '.' in time_str:
|
||
errors.append(f"({time_type}): Milisaniye ayirici nokta olmamali, virgul olmali")
|
||
elif time_str.count(':') != 2:
|
||
errors.append(f"({time_type}): ':' ayirici sayisi yanlis (2 olmali)")
|
||
else:
|
||
# Rakam sayısı kontrolü
|
||
parts = time_str.replace(',', ':').replace('.', ':').split(':')
|
||
if len(parts) == 4:
|
||
hours, mins, secs, ms = parts
|
||
if len(hours) != 2:
|
||
errors.append(f"({time_type}): Saat 2 haneli olmali")
|
||
if len(mins) != 2:
|
||
errors.append(f"({time_type}): Dakika 2 haneli olmali")
|
||
if len(secs) != 2:
|
||
errors.append(f"({time_type}): Saniye 2 haneli olmali")
|
||
if len(ms) != 3:
|
||
errors.append(f"({time_type}): Milisaniye 3 haneli olmali")
|
||
else:
|
||
errors.append(f"({time_type}): Format hatasi (HH:MM:SS,mmm olmali)")
|
||
return errors
|
||
|
||
# Değer aralığı kontrolü
|
||
hours, mins, secs, ms = match.groups()
|
||
hours, mins, secs, ms = int(hours), int(mins), int(secs), int(ms)
|
||
|
||
if hours > 23:
|
||
warnings = [] # Videolar 24 saatten uzun olabilir, warning olarak işaretle
|
||
if mins > 59:
|
||
errors.append(f"({time_type}): Dakika 59'dan buyuk olamaz ({mins})")
|
||
if secs > 59:
|
||
errors.append(f"({time_type}): Saniye 59'dan buyuk olamaz ({secs})")
|
||
if ms > 999:
|
||
errors.append(f"({time_type}): Milisaniye 999'dan buyuk olamaz ({ms})")
|
||
|
||
return errors
|
||
|
||
|
||
def parse_timestamp_to_ms(time_str):
|
||
"""Zaman damgasını milisaniyeye çevirir."""
|
||
try:
|
||
# Format: HH:MM:SS,mmm
|
||
pattern = r'^(\d{2}):(\d{2}):(\d{2}),(\d{3})$'
|
||
match = re.match(pattern, time_str)
|
||
|
||
if not match:
|
||
return None
|
||
|
||
hours, mins, secs, ms = match.groups()
|
||
total_ms = (int(hours) * 3600 + int(mins) * 60 + int(secs)) * 1000 + int(ms)
|
||
return total_ms
|
||
except:
|
||
return None
|
||
|
||
|
||
def print_results(errors, warnings, subtitle_count, file_path):
|
||
"""Sonuçları yazdır."""
|
||
print(f"Dosya: {file_path}")
|
||
print(f"Toplam altyazi sayisi: {subtitle_count}")
|
||
print(f"\n{'='*70}")
|
||
|
||
if errors:
|
||
print(f"\nHATALAR ({len(errors)} adet):")
|
||
print("="*70)
|
||
for i, error in enumerate(errors[:100], 1):
|
||
print(f" {i}. {error}")
|
||
if len(errors) > 100:
|
||
print(f"\n ... ve {len(errors) - 100} hata daha")
|
||
else:
|
||
print("\nKritik hata bulunamadi!")
|
||
|
||
if warnings:
|
||
print(f"\nUYARILAR ({len(warnings)} adet):")
|
||
print("="*70)
|
||
for i, warning in enumerate(warnings[:50], 1):
|
||
print(f" {i}. {warning}")
|
||
if len(warnings) > 50:
|
||
print(f"\n ... ve {len(warnings) - 50} uyari daha")
|
||
else:
|
||
print("\nUyari bulunamadi!")
|
||
|
||
print(f"\n{'='*70}")
|
||
|
||
if not errors and not warnings:
|
||
print("\nSonuc: SRT dosyasi MUKEMMEL durumda!")
|
||
elif not errors:
|
||
print(f"\nSonuc: Format dogru ama {len(warnings)} uyari var")
|
||
else:
|
||
print(f"\nSonuc: {len(errors)} HATA, {len(warnings)} uyari")
|
||
|
||
return errors, warnings
|
||
|
||
|
||
if __name__ == "__main__":
|
||
import sys
|
||
|
||
file_path = sys.argv[1] if len(sys.argv) > 1 else "public/ses.srt"
|
||
|
||
print("\nKAPSAMLI SRT FORMAT KONTROLU")
|
||
print("="*70)
|
||
print("\nKontrol edilen hususlar:")
|
||
print(" - Altyazi numara sirasi")
|
||
print(" - Zaman damgasi formati (HH:MM:SS,mmm)")
|
||
print(" - Baslangic/bitis zaman mantigi")
|
||
print(" - Altyazi cakismalari")
|
||
print(" - Altyazi sureleri")
|
||
print(" - Metin icerigi")
|
||
print("="*70)
|
||
|
||
errors, warnings, subtitle_count = comprehensive_srt_check(file_path)
|
||
print_results(errors, warnings, subtitle_count, file_path)
|