Guest User

Untitled

a guest
Jun 21st, 2024
185
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.43 KB | None | 0 0
  1. # This code is generated by ChatGPT 3.5
  2. # compile .exe by Pyinstaller
  3. #pyinstaller test.py --onefile --noconsole
  4. import tkinter
  5. import tkinter.font
  6. from tkinter import ttk
  7. import tkinter.filedialog
  8. import tkinter.simpledialog
  9.  
  10. import configparser
  11. import subprocess
  12. import re
  13. import os
  14. import shutil
  15. import threading
  16. import winsound
  17. import time
  18. from smartcard.util import toHexString
  19. from smartcard.util import toBytes
  20. from smartcard.System import readers as get_readers
  21.  
  22. # dumptsGUI.ini
  23. def read_ini():
  24. config = configparser.ConfigParser()
  25. config.read('dumptsGUI.ini')
  26. default_path = config.get('Paths', 'default_path', fallback='')
  27. mpc_hc_path = config.get('Paths', 'mpc_hc_path', fallback='')
  28. mkv_path = config.get('Paths', 'mkv_path', fallback='')
  29. return default_path, mpc_hc_path, mkv_path
  30.  
  31. def write_ini(default_output_path, mpc_hc_path, mkv_path):
  32. config = configparser.ConfigParser()
  33. config['Paths'] = {'default_path': default_output_path,
  34. 'mpc_hc_path': mpc_hc_path,
  35. 'mkv_path': mkv_path}
  36. with open('dumptsGUI.ini', 'w') as configfile:
  37. config.write(configfile)
  38.  
  39. def sanitize_filename(filename):
  40. # 許可する文字:英数字、ハイフン、アンダースコア、ドット、ひらがな、カタカナ、漢字、全角スペース、全角英字数字、全角カッコ、全角カギカッコ
  41. allowed_chars = re.compile(r'[^a-zA-Z0-9._\-\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\u3000\uFF10-\uFF19\uFF08\uFF09\u300C\u300D\uFF21-\uFF3A\uFF41-\uFF5A]')
  42. sanitized_name = allowed_chars.sub('_', filename)
  43. return sanitized_name
  44. def rename_files_in_directory(directory, filename):
  45. sanitized_name = sanitize_filename(filename)
  46. old_path = filename
  47. new_path = sanitized_name
  48. if old_path != new_path:
  49. os.rename(os.path.join(directory, old_path), os.path.join(directory, new_path))
  50. label4['text'] =f'Rename(expand): {filename} -> {sanitized_name}'
  51. else:
  52. label4['text'] =f'No change needed: {filename}'
  53. return new_path
  54.  
  55. # Program START
  56. if not os.path.exists('dumptsGUI.ini'):
  57. write_ini('', '', '')
  58. # Load paths from ini file
  59. default_path, mpc_hc_path, mkv_path = read_ini()
  60.  
  61. readers = get_readers()
  62. print(readers)
  63.  
  64. # Main window
  65. main_win = tkinter.Tk()
  66. main_win.title("DumpTS GUI, code generated by ChatGPT")
  67. main_win.geometry("700x380")
  68.  
  69. # Main frame
  70. main_frm = ttk.Frame(main_win)
  71. main_frm.grid(column=0, row=0, sticky=tkinter.NSEW, padx=5, pady=10)
  72.  
  73. if len(readers)!=0:
  74. conn = readers[0].createConnection()
  75. try:
  76. conn.connect()
  77. recv_data=conn.getATR()
  78. print(toHexString(recv_data))
  79.  
  80. # widget line 1
  81. label1 = ttk.Label(main_frm,text=readers, foreground='orange', background='black')
  82.  
  83.  
  84. # widget line 2
  85. label2 = ttk.Label(main_frm,text=toHexString(recv_data), foreground='orange', background='black')
  86.  
  87. if toHexString(recv_data[:4]) == '3B F0 13 00':
  88. # 4バイトが一致する場合の処理
  89. label2 ['text']= toHexString(recv_data)
  90. pass
  91. else:
  92. label2 ['text']= "Error: Confirm/Re-insert IC card"
  93. except:
  94. print('No card')
  95. label1 = ttk.Label(main_frm,text='No card', foreground='red', background='black')
  96. label2 = ttk.Label(main_frm,text=' ', foreground='orange', background='black')
  97.  
  98. else:
  99. label1 = ttk.Label(main_frm,text='No IC readers', foreground='red', background='black')
  100. label2 = ttk.Label(main_frm,text=' ', foreground='orange', background='black')
  101.  
  102.  
  103.  
  104. def btnReconnect_click():
  105. global readers,conn
  106. readers = get_readers()
  107. conn = readers[0].createConnection()
  108. conn.connect()
  109. recv_data=conn.getATR()
  110. label1 ['text'] =readers
  111. if toHexString(recv_data[:4]) == '3B F0 13 00':
  112. # 4バイトが一致する場合の処理
  113. label2 ['text']= toHexString(recv_data)
  114. pass
  115. else:
  116. label2 ['text']= "Error: Confirm/Re-insert IC card"
  117. main_win.mainloop()
  118.  
  119. def select_file_and_run():
  120. global selected_file, AACmatches, HEVCmatches
  121. # ファイル選択ダイアログを表示し、ユーザからファイル名を取得
  122. selected_file = tkinter.filedialog.askopenfilename()
  123. directory = os.path.dirname(selected_file)
  124. if selected_file:
  125. selected_filename =rename_files_in_directory(directory, os.path.basename(selected_file) )
  126. selected_file= os.path.join(directory, selected_filename)
  127. # 選択されたファイル名とファイルパスを表示
  128. label_selected_file['text'] = f"Selected File: {selected_filename}\nFile Path: {selected_file}"
  129.  
  130. # Dumpts.exeを実行し、選択されたファイル名を引数に渡す
  131. result = subprocess.run(["Dumpts.exe", selected_file, "--MAXMB=100", "--CID=1", "--showinfo"], stdout=subprocess.PIPE)
  132.  
  133. if result.stdout is not None:
  134. # 出力を取得して処理する
  135. output_lines = result.stdout.decode('utf-8').splitlines()
  136. last_25_lines = '\n'.join(output_lines[-26:])
  137. label5['text'] = last_25_lines
  138.  
  139. # パターンにマッチする部分を検索
  140. pattern = r"CID: (0x[0-9A-F]+), packet_id: (0x[0-9A-F]+).*HEVC Video Stream"
  141. HEVCmatches = re.findall(pattern, last_25_lines)
  142. cid, packet_id = HEVCmatches[0]
  143. label5['text'] = f"HEVC Video Stream: CID: {cid}, packet_id: {packet_id}\n"
  144.  
  145. pattern = r"CID: (0x[0-9A-F]+), packet_id: (0x[0-9A-F]+).*MPEG-4 AAC Audio Stream"
  146. AACmatches = re.findall(pattern, last_25_lines)
  147. for match in AACmatches:
  148. cid, packet_id = match[0], match[1]
  149. label5['text'] += f"MPEG-4 AAC Audio Stream: CID: {cid}, packet_id: {packet_id}\n"
  150. else:
  151. label5['text'] = "Error: Unable to retrieve output from Dumpts.exe"
  152.  
  153. def btnGetKey_click():
  154. global selected_file, AACmatches, HEVCmatches
  155. result = subprocess.run(["Dumpts.exe", "8k.mmts", "--MAXMB=100", "--CID=1", "--showinfo"], stdout=subprocess.PIPE)
  156.  
  157. if result.stdout is not None:
  158. output_lines = result.stdout.decode('utf-8').splitlines() # バイナリデータをUTF-8でデコードして行に分割
  159. last_25_lines = '\n'.join(output_lines[-26:]) # 最後の25行を取得
  160. label5['text'] = last_25_lines
  161. # パターンにマッチする部分を検索
  162. # テキストからCIDとpacket_idを抽出する正規表現パターン
  163. pattern = r"CID: (0x[0-9A-F]+), packet_id: (0x[0-9A-F]+).*HEVC Video Stream"
  164. # 正規表現パターンにマッチする全てのCIDとpacket_idのペアを抽出
  165. HEVCmatches = re.findall(pattern, last_25_lines)
  166. # HEVC Video StreamとMPEG-4 AAC Audio StreamのCIDとpacket_idの値を取得
  167. cid, packet_id = HEVCmatches[0]
  168. print(f"HEVC Video Stream: CID: {cid}, packet_id: {packet_id}")
  169. pattern = r"CID: (0x[0-9A-F]+), packet_id: (0x[0-9A-F]+).*MPEG-4 AAC Audio Stream"
  170. # 正規表現パターンにマッチする全てのCIDとpacket_idのペアを抽出
  171. AACmatches = re.findall(pattern, last_25_lines)
  172. for match in AACmatches:
  173. cid, packet_id = match[0], match[1]
  174. print(f"MPEG-4 AAC Audio Stream: CID: {cid}, packet_id: {packet_id}")
  175.  
  176.  
  177. else:
  178. label5['text'] = "Error: Unable to retrieve output from AA.exe"
  179. main_win.mainloop()
  180.  
  181. def btnWriteID_click():
  182. global AACmatches, HEVCmatches,output_filename, default_path, mpc_hc_path
  183.  
  184. # 選択されたファイルがない場合は処理を中止
  185. if not selected_file:
  186. label5['text'] = "Error: No file selected"
  187. return
  188. # プログラムの実行場所を取得
  189. current_directory = os.getcwd()
  190. # デフォルトのパスを使用するか、iniファイルから読み込んだパスを使用するかを決定する
  191. current_directory = default_path if default_path else current_directory
  192. default_output_path = os.path.join(current_directory, f"out_{os.path.basename(selected_file)}")
  193. # ファイル名の入力を取得
  194. output_filename = default_output_path#tkinter.simpledialog.askstring("Input", "Enter the output filename:", initialvalue=default_output_path)
  195. if not output_filename:
  196. label5['text'] = "Error: No output filename entered"
  197. return
  198.  
  199. # mmtsファイルの頭の〇〇MBをSkipして処理する。デフォルト値は0 MB
  200. input_value = numeric_input.get()
  201. if input_value.strip(): # 空でない文字列であるかどうかを確認
  202. skip_bytes = int(input_value)
  203. else:
  204. # エラー処理またはデフォルト値の設定などを行う
  205. skip_bytes = int(0) # 例えば、デフォルト値として0を設定
  206.  
  207.  
  208. # Dumpts.exe 実行のためのパケット ID リストを初期化
  209. packet_ids = []
  210.  
  211. # HEVC パケット ID を取得
  212. for cid, packet_id in HEVCmatches:
  213. packet_ids.append(packet_id)
  214.  
  215. # AAC パケット ID を取得
  216. for cid, packet_id in AACmatches:
  217. packet_ids.append(packet_id)
  218. # パケット ID を & でつなげる
  219. packet_ids_str = "&".join(packet_ids)
  220.  
  221. process = subprocess.Popen(["Dumpts.exe", selected_file, f"--SKIPMB={skip_bytes}", f"--CID={cid}", f"--pid={packet_ids_str}", f"--output={output_filename}"], stdout=subprocess.PIPE)
  222. label4['text'] = "DumpTS.exe is running..."
  223.  
  224. # パスをiniファイルに保存
  225. write_ini(current_directory, mpc_hc_path)
  226.  
  227. # ファイルサイズの変化をチェックするスレッドを開始
  228. check_size_thread = threading.Thread(target=check_file_size)
  229. check_size_thread.start()
  230.  
  231. def check_file_size():
  232. global output_filename, HEVCmatches
  233. output_filename_without_extension = output_filename.rsplit('.', 1)[0]
  234. # 映像ファイルのパスを生成
  235. video_file_path = f"{output_filename_without_extension}_{HEVCmatches[0][1]}.{output_filename.rsplit('.', 1)[1]}"
  236. time.sleep(10)
  237. # 初期のファイルサイズを取得
  238. initial_size = os.path.getsize(video_file_path)
  239.  
  240. while True:
  241. # 10秒待機
  242. time.sleep(10)
  243. # 現在のファイルサイズを取得
  244. current_size = os.path.getsize(video_file_path)
  245. # ファイルサイズが変化しなくなった場合
  246. if current_size == initial_size:
  247. # "DumpTS.exe Completed"とラベルを更新
  248. label4['text'] = "DumpTS.exe Completed"
  249. # 効果音を鳴らす
  250. winsound.PlaySound("SystemExit", winsound.SND_ALIAS)
  251. break
  252. else:
  253. initial_size =current_size
  254.  
  255.  
  256. def playFile_click():
  257. global output_filename, HEVCmatches, AACmatches, default_path, mpc_hc_path
  258. if output_filename and HEVCmatches and AACmatches:
  259. try:
  260. output_filename_without_extension = output_filename.rsplit('.', 1)[0]
  261. # 映像ファイルのパスを生成
  262. video_file_path = f"{output_filename_without_extension}_{HEVCmatches[0][1]}.{output_filename.rsplit('.', 1)[1]}"
  263.  
  264. # 音声ファイルのパスを生成(AACmatchesの2つ目のパケットIDを使用)
  265. original_audio_file_path = f"{output_filename_without_extension}_{AACmatches[0][1]}.{output_filename.rsplit('.', 1)[1]}"
  266. #renamed_audio_file_path = f"{output_filename_without_extension}_{AACmatches[0][1]}.dts"
  267. #shutil.copyfile(original_audio_file_path, renamed_audio_file_path)
  268. mpc_hc_path_ini=mpc_hc_path
  269. # mpc-hc64.exe のパスを取得
  270. mpc_hc_path = "C:\\Program Files\\MPC-HC\\mpc-hc64.exe"
  271. # デフォルトのパスを使用するか、iniファイルから読み込んだパスを使用するかを決定する
  272. mpc_hc_path = mpc_hc_path_ini if mpc_hc_path_ini else mpc_hc_path
  273.  
  274. # mpc-hc64.exe を実行し、映像ファイルと音声ファイルのパスを引数として渡す
  275. subprocess.Popen([mpc_hc_path, video_file_path])#subprocess.run([mpc_hc_path, video_file_path, f"/dub \"{renamed_audio_file_path}\""])
  276. #subprocess.Popen([mpc_hc_path, original_audio_file_path ])
  277.  
  278. # 実行成功時のメッセージを表示
  279. play_file_label['text'] = "MPC-HC has been executed successfully"
  280. mpc_hc_path_label['text'] = f"MPC-HC Location: {mpc_hc_path}"
  281. except FileNotFoundError:
  282. # ファイルが見つからない場合のエラーメッセージを表示
  283. play_file_label['text'] = "Error: MPC-HC not found"
  284. else:
  285. # 必要なファイルやマッチが見つからない場合のエラーメッセージを表示
  286. play_file_label['text'] = "Error: Missing output filename or matches"
  287. mpc_hc_path_label['text'] = ""
  288.  
  289. def launch_mkv_tool():
  290. global mkv_path
  291. mkv_path_ini=mkv_path
  292. mkv_path = "C:\\Program Files\\MKVToolNix\\mkvtoolnix-gui.exe"
  293. mkv_path = mkv_path_ini if mkv_path_ini else mkv_path
  294. mkv_path_label.config(text=mkv_path)
  295. subprocess.Popen([mkv_path])
  296.  
  297. mkv_path_label = ttk.Label(main_frm, text='', foreground='white', background='black')
  298. mkv_path_label.grid(column=1, row=7, sticky=tkinter.EW, padx=5)
  299.  
  300. # ファイル処理ボタンの作成
  301. button_process_files_to_mkv = ttk.Button(main_frm, text="Launch MKVtoolnix", command=launch_mkv_tool)
  302. button_process_files_to_mkv.grid(column=0, row=7, pady=10)
  303.  
  304. mpc_hc_path_label= ttk.Label(main_frm, text='', foreground='white', background='black')
  305. mpc_hc_path_label.grid(column=1, row=6, sticky=tkinter.EW, padx=5)
  306. button_play_file = ttk.Button(main_frm, text="Play File", command=playFile_click)
  307. button_play_file.grid(column=0, row=5, pady=10)
  308. play_file_label= ttk.Label(main_frm, text='', foreground='white', background='black')
  309. play_file_label.grid(column=1, row=5, sticky=tkinter.EW, padx=5)
  310. # ファイル選択ボタンの作成
  311. button_select_file = ttk.Button(main_frm, text="Select File", command=select_file_and_run)
  312. button_select_file.grid(column=0, row=2, pady=10)
  313. # 選択されたファイルを表示するラベルの作成
  314. label_selected_file = ttk.Label(main_frm, text='', foreground='white', background='black')
  315. label_selected_file.grid(column=1, row=2, sticky=tkinter.EW, padx=5)
  316. # widget line 4
  317. label5 = ttk.Label(main_frm, text='', foreground='white', background='black')
  318.  
  319. # widget line 1
  320. label3 = ttk.Label(main_frm,text='Card Reader')
  321.  
  322. # widget line 2
  323. buttonA = ttk.Button(
  324. main_frm, text = 'Re-analyze file', command=btnGetKey_click)
  325.  
  326. # widget line 3
  327. buttonB = ttk.Button(
  328. main_frm, text = 'DumpTS', command=btnWriteID_click)
  329.  
  330. # widget line 3
  331. label4 = ttk.Label(main_frm, text='Select mmts file, then click DumpTS', foreground='white', background='black')
  332.  
  333. # widget line 4
  334. buttonC = ttk.Button(
  335. main_frm, text = 'Connect IC card', command=btnReconnect_click)
  336.  
  337.  
  338. label3.grid(column=0, row=0, pady=10)
  339. label1.grid(column=1, row=0, sticky=tkinter.EW, padx=5)
  340. buttonA.grid(column=0, row=4)
  341. label2.grid(column=1, row=1, sticky=tkinter.EW, padx=5)
  342. buttonB.grid(column=0, row=3, pady=10)
  343. label4.grid(column=1, row=3, sticky=tkinter.EW, padx=5)
  344. buttonC.grid(column=0, row=1, pady=10)
  345. label5.grid(column=1, row=4, sticky=tkinter.EW, padx=5)
  346.  
  347. # 数値入力フィールドを追加
  348. label_numeric_input = ttk.Label(main_frm, text="(MB, Option):SKIP the first XXXMB of mmts file, if file can't play")
  349. label_numeric_input.grid(column=1, row=8, sticky=tkinter.EW, padx=5)
  350. numeric_input = ttk.Spinbox(main_frm, from_=0, to=10000)
  351. numeric_input.grid(column=0, row=8, pady=10)
  352.  
  353. # place settings
  354. main_win.columnconfigure(0, weight=1)
  355. main_win.rowconfigure(0, weight=1)
  356. main_frm.columnconfigure(1, weight=1)
  357. main_win.mainloop()
  358.  
  359.  
  360.  
Advertisement
Add Comment
Please, Sign In to add comment