カラオケで穴埋めクイズ風に歌詞を隠しつつを歌うというのが面白かったので作りました。
※Pythonで作成したプログラムをWindows実行用にPyinstallerでexe化していますが、
ウィルス対策ソフトによってマルウェアなどに分類されてしまうことがあるそうです。
当然、そのような機能は実装していませんが。。。
■ファイル
https://drive.google.com/file/d/1wKf-ZSTDrIE2CUmj81Ls_6uaudk7Uy_v/view?usp=drive_link
【exeファイルの使い方】
- ダウンロードしたzipを解凍して、「quiz_creater.exe」を起動します。
※セキュリティの警告が表示される場合は、「詳細情報→実行する」 - URLに歌ネットの歌詞ページのURLを貼り付けて、GETボタンを押下するとテキストエリアに歌詞が表示されます。
- テキストエリアの歌詞から、穴埋めにしたいところを選択するとテキストボックスが追加されます。
- テキストボックス右側のDELボタンを押下すると穴埋めが解除されます。
- SAVEボタンを押下するとファイル保存ダイアログが表示されるので、HTMLファイルを出力したいフォルダとファイル名を設定してください。
【HTMLについて】
- HTMLを起動すると穴埋め状態で表示されます。
- ブラウザがChromeなら、F11キーを押下することで全画面表示になるかと思います。
- 画面内をクリックすることで、上から順番に穴埋め箇所が解除されます。
コードも載せておきます。
import os import tkinter as tk from tkinter import filedialog import requests from bs4 import BeautifulSoup import copy replace_list = {} replace_list_index = 0 class ReplaceItem : def __init__(self, text_box, start_index, end_index, id_index) : self.text_box = text_box self.start_index = start_index self.end_index = end_index self.id_index = id_index def get_text(self) : result = "<span id=\"text" + str(self.id_index) + "\" style=\"background-color:#000;color:#000\">" + self.text_box.get() + "</span>" return result def replace_text(event): global replace_list global replace_list_index # テキストエリアからテキストを取得 text = text_area.get("1.0", "end-1c") # テキストの長さが0の場合、何もせずに終了 if len(text) == 0: return # テキストエリアで選択されたテキストの開始位置と終了位置を取得 try: start_index = text_area.index(tk.SEL_FIRST) end_index = text_area.index(tk.SEL_LAST) except ValueError: # テキストが選択されていない場合、何もせずに終了 return selected_text = text_area.get(start_index, end_index) # フレームを作成してテキストボックスとボタンを横に並べる frame = tk.Frame(window) frame.pack(fill=tk.X, expand=True) # テキストボックスを配置 text_box = tk.Entry(frame) text_box.insert(0, selected_text) text_box.pack(fill=tk.X, expand=True, side = 'left') # 置換アイテムリストに追加 id_index = replace_list_index + 1 - 1 replace_list[replace_list_index] = ReplaceItem(text_box, start_index, end_index, id_index) replace_list_index = replace_list_index + 1 # 削除ボタンを配置 del_button = tk.Button(frame, text="DEL") del_button.configure(command=lambda: del_text_box(frame, text_box, del_button, text_area, start_index, end_index, id_index)) del_button.pack(side = 'right') # テキストエリアを更新 text_area.delete(start_index, end_index) text_area.insert(start_index, "■" * len(selected_text)) # テキストボックスを削除する関数 def del_text_box(frame, text_box, del_button, text_area, start_index, end_index, del_index) : text_area.delete(start_index, end_index) text_area.insert(start_index, text_box.get()) text_box.destroy() del_button.destroy() frame.destroy() replace_list.pop(del_index) # 歌詞を取得 def getKashi(text_box, text_area) : response = requests.get(text_box.get()) if response.status_code == 200: # Beautiful Soupを使用してHTMLを解析 soup = BeautifulSoup(response.text, 'html.parser') # 歌詞がどの要素に格納されているかを調査し、適切な要素を選択 # 例: 歌詞が <div class="lyrics"> タグの中にある場合 lyrics_element = soup.find('div', id='kashi_area') if lyrics_element: # 歌詞テキストを取得 lyrics_text = "\n".join(lyrics_element.stripped_strings) # 歌詞を表示またはファイルに保存 text_area.insert(tk.END, lyrics_text) else: print("歌詞が見つかりませんでした。") else: print("URLにアクセスできませんでした。") # HTML出力 def createHtml(text_area) : global replace_list # スクリプトのディレクトリを取得 script_directory = os.path.dirname(os.path.abspath(__file__)) # ファイル保存ダイアログを表示 file_path = filedialog.asksaveasfilename(initialdir=script_directory, defaultextension=".html", filetypes=[("HTMLファイル", "*.html")]) if not file_path: return # ファイル名(拡張子を除く)を取得 filename = os.path.splitext(os.path.basename(file_path))[0] # 出力文字列を生成 store_text = text_area.get("1.0", "end-1c") sorted_items = sorted(replace_list.items(), key=lambda item: (int(item[1].start_index.split(".")[0]), int(item[1].start_index.split(".")[1])), reverse=True) index_strs = [] for key, item in sorted_items : text_area.delete(item.start_index, item.end_index) text_area.insert(item.start_index, item.get_text()) index_strs.append(str(item.id_index)) output_str = text_area.get("1.0", "end-1c").replace("\n", "<br/>\n") text_area.delete("1.0", "end") text_area.insert("1.0", store_text) # HTMLを成形 html_str = "<html>\n" html_str = html_str + " <head>\n" html_str = html_str + " <title>\n" html_str = html_str + " " + filename + "\n" html_str = html_str + " </title>\n" html_str = html_str + " <script>\n" html_str = html_str + " var list = [" + ", ".join(list(reversed(index_strs))) + "];\n" html_str = html_str + " var currentIndex = 0;\n" html_str = html_str + "\n" html_str = html_str + " function changeStyles() {\n" html_str = html_str + " if (currentIndex < list.length) {\n" html_str = html_str + " var elementId = \"text\" + list[currentIndex];\n" html_str = html_str + " var element = document.getElementById(elementId);\n" html_str = html_str + "\n" html_str = html_str + " if (element) {\n" html_str = html_str + " element.style.backgroundColor = \"transparent\"; // 背景色を無色に設定\n" html_str = html_str + " element.style.color = \"black\"; // 文字色を黒色に設定\n" html_str = html_str + " }\n" html_str = html_str + "\n" html_str = html_str + " currentIndex++;\n" html_str = html_str + " }\n" html_str = html_str + " }\n" html_str = html_str + "\n" html_str = html_str + " window.addEventListener(\"click\", changeStyles);\n" html_str = html_str + " </script>\n" html_str = html_str + " </head>\n" html_str = html_str + " <body>\n" html_str = html_str + output_str + "\n" html_str = html_str + " </body>\n" html_str = html_str + "</html>\n" with open(file_path, 'w') as file: file.write(html_str) print(f"ファイル '{file_path}' に保存しました") # Tkinterウィンドウの作成 window = tk.Tk() window.title("Text Replacement") # テキストエリアを作成 text_area = tk.Text(window) text_area.pack(fill=tk.BOTH, expand=True, side = 'top') # 画面の伸長に合わせてサイズを変更 # フレームを作成 frame = tk.Frame(window) frame.pack(fill=tk.X, expand=False) # ラベルを作成 label1 = tk.Label(frame, text="URL:") label1.pack(side = 'left') # テキストボックスを作成 text_box = tk.Entry(frame) text_box.insert(0, "https://www.uta-net.com/song/344723/") text_box.pack(fill=tk.X, expand=True, side = 'left') # GETボタンを作成 up_button = tk.Button(frame, text="GET", command=lambda: getKashi(text_box, text_area)) up_button.pack(side = 'right') # SAVEボタンを作成 save_button = tk.Button(frame, text="SAVE", command=lambda: createHtml(text_area)) save_button.pack(side = 'right') # テキスト選択時のイベントハンドラを設定 text_area.bind("<ButtonRelease-1>", replace_text) # プログラムの実行 window.mainloop()