Skip to content

Commit

Permalink
1.76
Browse files Browse the repository at this point in the history
  • Loading branch information
DoobyDouglas committed Jun 28, 2023
1 parent edd000b commit a5ff35c
Show file tree
Hide file tree
Showing 8 changed files with 345 additions and 180 deletions.
9 changes: 9 additions & 0 deletions HARDSUBBER.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[OPTIONS]
audio = False
subs_extract = False
subs_cleaner = False
convert_to_mp4 = False
subs_lang = Saudi Arabia
resolution = ORIGINAL
bitrate = 2500

Binary file removed HardSubber.exe
Binary file not shown.
308 changes: 128 additions & 180 deletions HardSubber.py
Original file line number Diff line number Diff line change
@@ -1,164 +1,28 @@
from PIL import Image, ImageTk
from tkinter import filedialog
from typing import Tuple
from typing import Tuple, Dict
import subprocess
import tkinter
import os
import pysubs2
import configparser
import tkinter.messagebox
from threading import Thread
from typing import Dict
import sys
import tkinter.ttk as ttk
from ttkbootstrap import Style
import json
from configs import (
get_config,
get_value,
save_options,
SUBS_LANGS_DICT,
RESOLUTIONS_LIST,
)
from fileworks import choice_files
# pyinstaller --noconfirm --onefile --noconsole --add-data 'background.png;.' HardSubber.py


def get_config() -> configparser.ConfigParser:
config = configparser.ConfigParser()
config.read('config.ini')
if 'OPTIONS' not in config:
config['OPTIONS'] = {}
return config


def get_value(name: str) -> bool:
config = get_config()
if config['OPTIONS'][name] == 'True':
return True
return False


def check_config() -> None:
if get_value('audiovideo') and get_value('video'):
tkinter.messagebox.showinfo(
'Выбраны оба параметра для выходного файла',
'Выберите только один'
)
raise SystemExit


def save_options(checkboxes: dict) -> None:
config = get_config()
for option, var in checkboxes.items():
config['OPTIONS'][option] = str(var.get())
with open('config.ini', 'w') as config_file:
config.write(config_file)


def comparator(sub: str) -> bool:
if (
'text' not in sub
and 'sign' not in sub
and 'надпись' not in sub
and 'caption' not in sub
and 'title' not in sub
and 'song' not in sub
and 'screen' not in sub
and 'typedigital' not in sub
and 'phonetics' not in sub
):
return True
return False


def subs_extract(video_path, folder) -> str:
subs_path = f'{folder}subs.ass'
copy = ''
while os.path.exists(subs_path):
copy += 'copy'
subs_path = f'{folder}subs_{copy}.ass'
command = f'ffmpeg -i "{video_path}" -map 0:s:m:language:rus "{subs_path}"'
subprocess.call(command, shell=True)
return subs_path


def subs_edit(path: str) -> None:
subs = pysubs2.load(path)
to_delete = []
search_char = '{'
if subs.events[0].name:
for i, sub in enumerate(subs.events):
if comparator(sub.name.lower()) and search_char not in sub.text:
to_delete.append(i)
if subs.events[0].style:
for i, sub in enumerate(subs.events):
if comparator(sub.style.lower()) and search_char not in sub.text:
if i not in to_delete:
to_delete.append(i)
else:
to_delete = [
i for i, line in enumerate(subs) if search_char not in line.text
]
to_delete.sort()
for i in reversed(to_delete):
del subs[i]
subs.save(path)


def name_generator(file: str, ext: str) -> str:
ext = ext.replace('.', '')
name = file.split('/')[-1]
name = (''.join(i for i in name if i.isalnum())).lower()
name = name.replace(ext, '')
return name


def choice_files(master: tkinter.Tk) -> Tuple[str, str, str, str, str]:
try:
video = filedialog.askopenfilename(title='Выберите видео')
if video:
filename = os.path.basename(video)
folder = video.replace(filename, '')
video_ext = os.path.splitext(video)[-1]
name = name_generator(video, video_ext)
video_path = f'{folder}{name}{video_ext}'
copy = ''
while os.path.exists(video_path):
copy += 'copy'
video_path = f'{folder}{name}_{copy}{video_ext}'
os.rename(video, video_path)
video = os.path.basename(video_path)
if get_value('subs_extract') and video_ext == '.mkv':
master.nametowidget('pb').start()
subs_path = subs_extract(video_path, folder)
subs_ext = '.ass'
master.nametowidget('pb').stop()
else:
subs = filedialog.askopenfilename(title='Выберите субтитры')
if subs:
filename = os.path.basename(subs)
subs_ext = os.path.splitext(subs)[-1]
name = name_generator(subs, subs_ext)
subs_path = f'{folder}{name}{subs_ext}'
copy = ''
while os.path.exists(subs_path):
copy += 'copy'
subs_path = f'{folder}{name}_{copy}{subs_ext}'
os.rename(subs, subs_path)
else:
return None, None, None, None, None
if subs_ext == '.ass':
subs_edit(subs_path)
subs = os.path.basename(subs_path)
else:
return None, None, None, None, None
except PermissionError:
tkinter.messagebox.showerror(
'Отказано в доступе',
f'Отказано в доступе к "{folder}". '
'Попробуйте воспользоваться не системным диском '
'или не его корневым разделом.'
)
except OSError:
tkinter.messagebox.showerror(
'Файлы находятся на разных дисках',
f'Переместите файлы "{video}" и "{subs}" на один диск.'
)
return video_ext, subs_ext, folder, video, subs


def hardsubber(master: tkinter.Tk) -> None:
config = get_config()
video_ext, subs_ext, folder, video, subs = choice_files(master)
if video_ext and subs_ext and folder and video and subs:
master.nametowidget('pb').start()
Expand All @@ -168,24 +32,32 @@ def hardsubber(master: tkinter.Tk) -> None:
param = 'ass'
else:
param = 'subtitles'
if get_value('audiovideo'):
if get_value('audio'):
sound_param = ' '
elif get_value('video'):
else:
sound_param = ' -an '
if config['OPTIONS']['bitrate']:
bitrate = f" -b {config['OPTIONS']['bitrate']}k "
else:
bitrate = ' '
if config['OPTIONS']['resolution'] != 'ORIGINAL':
resolution = f" -s {config['OPTIONS']['resolution']} "
else:
resolution = ' '
if get_value('convert_to_mp4'):
video_ext = '.mp4'
command = (
f'{disk}: && cd {folder_path} && ffmpeg -i {video} -vf '
f'{param}={subs} -vcodec libx264 -b 1500k -s 1280x720 '
f'{param}={subs} -vcodec libx264'
f'{bitrate}{resolution}'
f'-acodec copy{sound_param}new_file{video_ext}'
)
subprocess.call(command, shell=True)
master.nametowidget('pb').stop()


def main(checkboxes: Dict, master: tkinter.Tk) -> None:
save_options(checkboxes)
check_config()
save_options(checkboxes, master)
master.nametowidget('start').config(state='disabled')
hardsubber(master)
master.nametowidget('start').config(state='normal')
Expand All @@ -205,35 +77,108 @@ def resource_path(path):
return os.path.join(base_path, path)


def get_subs_langs():
if not os.path.exists('subs_langs.json'):
with open('subs_langs.json', 'w+') as json_file:
data = {}
for key, value in SUBS_LANGS_DICT.items():
data[key] = value
json.dump(data, json_file)
with open('subs_langs.json', 'r') as json_file:
data = json.load(json_file)
return data


def menu_setup(menu, key):
if key == 'subs_lang':
LIST = SUBS_LANGS_LIST
else:
LIST = RESOLUTIONS_LIST
try:
if config['OPTIONS'][key] in LIST:
menu.set(config['OPTIONS'][key])
else:
menu.set(LIST[0])
except KeyError:
menu.set(LIST[0])


def set_geometry(master: tkinter.Tk):
width = 300
height = 236
s_width = master.winfo_screenwidth()
s_height = master.winfo_screenheight()
upper = s_height // 5
x = (s_width - width) // 2
y = (s_height - height) // 2
return f'{width}x{height}+{x}+{y - upper}'


config = get_config()
master = tkinter.Tk(className='HARDSUBBER.main')
width = 330
height = 125
s_width = master.winfo_screenwidth()
s_height = master.winfo_screenheight()
upper = s_height // 5
x = (s_width - width) // 2
y = (s_height - height) // 2
master.geometry(f'{width}x{height}+{x}+{y - upper}')
master.resizable(width=False, height=False)
master.title('HARDSUBBER v1.71')
master.geometry(set_geometry(master))
master.resizable(False, False)
master.title('HARDSUBBER v1.76')
img = Image.open(resource_path('background.png'))
tk_img = ImageTk.PhotoImage(img)
background_label = tkinter.Label(master, image=tk_img)
background_label.place(x=0, y=0, relwidth=1, relheight=1)
checkbox_style = ttk.Style()
checkbox_style.configure('TCheckbutton', background='#ffc0cb')
button_style = ttk.Style()
button_style.configure('TButton', background='#ffc0cb')

style = Style(theme='pulse')
style.configure('TCheckbutton', background='#ffc0cb')
style.configure('TButton', background='#ffc0cb', foreground='black')
style.configure('TLabel', background='#ffc0cb')
style.configure('Horizontal.TProgressbar', thickness=27)

subs_extract_ = ttk.Label(master, text='Select subtitles to extract:')
subs_extract_.grid(row=0, column=0, sticky=tkinter.W, padx=6, pady=6)
select_resolution = ttk.Label(master, text='Select resolution:')
select_resolution.grid(row=1, column=0, sticky=tkinter.W, padx=6, pady=6)
enter_bitrate = ttk.Label(master, text='Enter bitrate:')
enter_bitrate.grid(row=2, column=0, sticky=tkinter.W, padx=6, pady=6)

SUBS_LANGS_LIST = list(get_subs_langs().keys())

subs_menu = ttk.Combobox(
master,
values=SUBS_LANGS_LIST,
name='subs_menu',
state='readonly',
width=12,
)
subs_menu.place(relx=0.5, rely=1.0, anchor="s", x=95, y=-204)
menu_setup(subs_menu, 'subs_lang')

resolution_menu = ttk.Combobox(
master,
values=RESOLUTIONS_LIST,
name='resolution_menu',
state='readonly',
width=12,
)
resolution_menu.place(relx=0.5, rely=1.0, anchor="s", x=95, y=-173)
menu_setup(resolution_menu, 'resolution')

bitrate_entry = ttk.Entry(
master,
name='bitrate_entry',
width=14,
)
bitrate_entry.place(relx=0.5, rely=1.0, anchor="s", x=95, y=-142)
if config['OPTIONS']['bitrate']:
bitrate_entry.insert(1, config['OPTIONS']['bitrate'])

OPTIONS = [
'audiovideo',
'video',
'audio',
'subs_extract',
'subs_cleaner',
'convert_to_mp4',
]
config = get_config()

checkboxes = {}
if 'OPTIONS' not in config:
config['OPTIONS'] = {}

for i, option in enumerate(OPTIONS):
var = tkinter.BooleanVar()
if option in config['OPTIONS']:
Expand All @@ -244,29 +189,32 @@ def resource_path(path):
master,
text=option,
variable=var,
padding=7,
padding=6,
)
checkbox.grid(
row=i,
row=i + 3,
column=0,
sticky=tkinter.W
)
checkboxes[option] = var

save_button = ttk.Button(
master,
name='start',
text='START',
width=6,
command=lambda: on_save_click(checkboxes, master),
)
save_button.place(relx=0.5, rely=1.0, anchor="center", y=-65, x=2)
progressbar = ttk.Progressbar(master, mode='determinate', name='pb')
progressbar.grid(
row=0,
column=1,
padx=0,
pady=3,
sticky='we'
save_button.grid(row=7, column=0, padx=6, sticky=tkinter.W)

progressbar = ttk.Progressbar(
master,
mode='determinate',
name='pb',
length=224,
style='Horizontal.TProgressbar',
)
progressbar.place(relx=0.5, rely=1.0, anchor="center", y=-21, x=32)

if __name__ == '__main__':
master.mainloop()
Binary file modified background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit a5ff35c

Please sign in to comment.