日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

【记录】python3 tkinterUI编辑器应用之索尼walkmanA35播放列表编辑工具

發布時間:2024/3/13 python 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【记录】python3 tkinterUI编辑器应用之索尼walkmanA35播放列表编辑工具 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

tkinterUI編輯器應用(二)

  • 前言
  • 一、工具使用說明
  • 二、分析播放列表文件
  • 三、tinytag讀取歌曲信息
  • 四、treeview列表模式時點擊標題進行排序
  • 五、主文件代碼,其他代碼這里就不展示了


前言

幾年前買了個A35播放器,在播放器里編輯播放列表比較麻煩,在電腦上編輯的話貌似需要下載一個官方的什么軟件,我只需要一個編輯播放列表的工具,于是就自己用python寫了一個,最近完成了tkinterUI編輯器,于是決定用編輯器重寫一下。
我只有A35,不知道A55,A105這些支不支持
我沒有mac,所以只支持windows,python版本是3.4,工具如下:

ui的讀取創建是通過我之前寫的編輯器處理的,可從這里查看編輯器的代碼與使用方法

這個工具的所有代碼可以在這里下載


一、工具使用說明

  • 將播放器連接電腦
  • 打開工具,工具會直接讀取所有播放列表
  • edit菜單中create_song_list可以創建播放列表
  • edit菜單中delete_song_list可以刪除播放列表,鼠標右鍵點擊播放列表也可以彈出菜單進行刪除
  • edit菜單中add_songs可以添加歌曲到選中的播放列表
  • edit菜單中delete_songs可以刪除播放列表中選中的歌曲,鼠標右鍵歌曲也可以彈出菜單進行刪除
  • 點擊index,title,artist,album,duration可以進行排序
  • 二、分析播放列表文件

  • 先在播放器里新建一個播放列表,然后添加幾首歌,添加時發現只能添加同一個盤里面的歌曲,添加后連接到電腦發現在WALKMAN(F:)盤的MUSIC目錄里多了一個后綴為.m3u的文件,這個就是播放列表文件,工具只需要操作這個文件就行,文件內容如下:#EXTM3U #EXTINF:, test/fate hf - Aimer - 花の唄 (花之歌).flac #EXTINF:, 八度空間/(01) [周杰倫] 半獸人.flac #EXTINF:, 不能說的秘密/(25) [周杰倫] 不能能的秘密.flac
  • 開始研究m3u文件,發現只有第一行是"#EXTM3U",所以應該是每個播放列表第一行都應該是這個,然后每首歌之間有一行"#EXTINF:,",每首歌存儲的是這首歌所在的相對路徑,這樣就分析完了
  • 三、tinytag讀取歌曲信息

  • 其實這個工具只需要讀取文件名就可以了,但是最近我在研究treeview,所以需要讀取一下歌曲的數據進行顯示,百度后發現tinytag這個庫可以讀取歌曲信息
  • pip install tinytag進行安裝
  • from tinytag import TinyTag導入模塊,tag = TinyTag.get(song_path)獲取歌曲信息,之后可以使用tag.artist, tag.album, tag.duration等等獲取屬性
  • 使用這個庫的時候發現如果播放列表里歌曲比較多的話,第一次讀取會比較慢
  • 四、treeview列表模式時點擊標題進行排序

    最近在研究treeview,這里記錄一下如何進行排序,代碼如下:

    def sort_song_list(self, col, reverse):"""歌曲排序:param col: 要排序的列:param reverse: 是否倒序:return: None"""l = []for child in self.song_list.tree.get_children(''):l.append((self.song_list.tree.set(child, col), child))l.sort(key=lambda t:t[0], reverse=reverse)for index, (val, child) in enumerate(l):self.song_list.tree.move(child, '', index)self.song_list.tree.heading(col, command=partial(self.sort_song_list, col, not reverse))def init_song_list(self):"""初始化播放列表控件:return: None"""columns = ("index", "title", "artist", "album", "duration")self.song_list.tree.configure(columns=columns)for name in columns:self.song_list.tree.column(name, anchor="center", width=170)self.song_list.tree.heading(name, text=name, command=partial(self.sort_song_list, name, False))

    說明:

  • self.song_list.tree就是treeview控件
  • 五、主文件代碼,其他代碼這里就不展示了

    # -*- coding: UTF-8 -*-import osfrom tkinter import * from tinytag import TinyTag from functools import partial from componentMgr import componentMgr from components import create_default_component from tkinter.filedialog import askopenfilenames, asksaveasfilenameM3U_HEAD = '#EXTM3U\n' M3U_NEW_LINE = '#EXTINF:,'class SonySongListEditor(componentMgr):def __init__(self, master, gui_path):componentMgr.__init__(self, master)self.load_from_xml(master, gui_path, True)self.music_path_list = []self.song_index = 0self.right_edit_menu_1 = Noneself.right_edit_menu_2 = Noneself.build_music_path()self.init_frame()@propertydef editor_window(self):return self.master.children.get("sonySongListEditor", None)@propertydef song_list_list(self):return self.editor_window.children.get("songlistlist", None)@propertydef song_list(self):return self.editor_window.children.get("songlist", None)def build_music_path(self):"""創建音樂路徑:return: None"""for i in range(ord("A"), ord("Z") + 1):path = chr(i) + ":\\" + "MUSIC"self.music_path_list.append(path)def init_frame(self):"""初始化窗口:return: None"""self.init_menu()self.init_song_list_list()self.init_song_list()self.scan_music_list()def init_menu(self):"""初始化菜單:return: None"""main_menu = Menu(self.master, tearoff=0, name="menu")edit_menu = Menu(main_menu, tearoff=0, name="edit")edit_menu.add_command(label="create_song_list", command=self.create_song_list)edit_menu.add_command(label="delete_song_list", command=self.delete_song_list)edit_menu.add_command(label="add_songs", command=self.add_songs)edit_menu.add_command(label="delete_songs", command=self.delete_songs)main_menu.add_cascade(label="edit", menu=edit_menu)self.master.config(menu=main_menu)self.right_edit_menu_1 = Menu(self.master, tearoff=0)self.right_edit_menu_1.add_command(label="delete_song_list", command=self.delete_song_list)self.right_edit_menu_2 = Menu(self.master, tearoff=0)self.right_edit_menu_2.add_command(label="delete_songs", command=self.delete_songs)def init_song_list_list(self):"""初始化播放列表列表控件:return: None"""self.song_list_list.set_handle_cancel_select_row(self.cancel_select_song_list)self.song_list_list.set_handle_select_row(self.select_song_list)def cancel_select_song_list(self, index):"""取消選中播放列表:param index: 索引:return: None"""row = self.song_list_list.get_row_by_index(index)if not row:returnrow.configure(state="normal")def select_song_list(self, index):"""選中播放列表:param index: 索引:param event::return:"""row = self.song_list_list.get_row_by_index(index)if not row:returnrow.configure(state="active")data = self.song_list_list.get_data_by_index(index)self.add_songs_from_path(data["list_path"], data["path"])def add_songs_from_path(self, song_list_path, path):"""從給定的路徑讀取歌曲信息:param song_list_path: 歌單路徑:param path: 歌單所在文件夾路徑:return: None"""self.song_list.clear_all_node()all_lines = []self.song_index = 0with open(song_list_path, 'r', encoding='utf-8') as f:line_head = f.readline()if line_head != M3U_HEAD:returnline = f.readline()i = 1while line:if i % 2 == 0:all_lines.append(os.path.join(path, line[:-1]))i += 1line = f.readline()for line in all_lines:self.add_song(line)self.song_list.update_scroll()def add_song(self, song_path):"""添加一首歌曲:param song_path: 歌曲路徑:param index: 歌曲索引:return: None"""tag = TinyTag.get(song_path)title = self.calc_name(tag.title, song_path)self.song_list.add_node("", self.song_index, values=(str(self.song_index), title, tag.artist, tag.album, tag.duration, song_path))self.song_index += 1@staticmethoddef calc_name(title, song_path):"""如果沒有讀取出title則直接讀取名字:param title: 讀取出來的title:param song_path: 歌曲路徑:return: string"""if title:return titleindex = song_path.find("/")return song_path[index:]def sort_song_list(self, col, reverse):"""歌曲排序:param col: 要排序的列:param reverse: 是否倒序:return: None"""l = []for child in self.song_list.tree.get_children(''):l.append((self.song_list.tree.set(child, col), child))l.sort(key=lambda t:t[0], reverse=reverse)for index, (val, child) in enumerate(l):self.song_list.tree.move(child, '', index)self.song_list.tree.heading(col, command=partial(self.sort_song_list, col, not reverse))def init_song_list(self):"""初始化播放列表控件:return: None"""columns = ("index", "title", "artist", "album", "duration")self.song_list.tree.configure(columns=columns)for name in columns:self.song_list.tree.column(name, anchor="center", width=170)self.song_list.tree.heading(name, text=name, command=partial(self.sort_song_list, name, False))self.song_list.set_on_select_tree(self.on_select_song)def on_select_song(self, event):"""選中歌曲時觸發:param event::return: None"""self.right_edit_menu_2.post(event.x_root, event.y_root)def scan_music_list(self):"""掃描歌單:return:None"""self.song_list_list.clear_rows()for path in self.music_path_list:if not os.path.exists(path):continuefor file_name in os.listdir(path):self.scan_music_list_next(path, file_name)self.song_list_list.do_layout_row()self.song_list_list.select_first_row_base()def scan_music_list_next(self, path, file_name):"""掃描歌單下一步:param path: 掃描路徑:param file_name: 文件路徑:return: int"""file_name_base, file_ext = os.path.splitext(file_name)if file_ext != ".m3u":returnlist_path = os.path.join(path, file_name)created_num = self.song_list_list.get_created_row_num()prop = {"text": list_path, "activebackground": "red", "font_anchor": "w", "width": 40,}row, info = create_default_component(self.song_list_list.get_child_master(), "Label", "row_" + str(created_num), prop)row.bind("<ButtonRelease-1>", lambda event:self.song_list_list.set_selected_row(created_num))def right_click(event):self.song_list_list.set_selected_row(created_num)self.right_edit_menu_1.post(event.x_root, event.y_root)row.bind("<ButtonRelease-3>", right_click)data = {"list_path": list_path, "path": path,}self.song_list_list.add_row_base(row, False, data)return created_numdef create_song_list(self):"""創建播放列表:return: None"""file_path = asksaveasfilename(title=u"選擇文件", filetypes=[("m3u files", "m3u"), ], defaultextension=".m3u")if not file_path:returnwith open(file_path, "w", encoding="utf-8") as f:f.writelines(M3U_HEAD)base_path, file_name = os.path.split(file_path)index = self.scan_music_list_next(base_path, file_name)self.song_list_list.do_layout_row()self.song_list_list.set_selected_row(index)def delete_song_list(self):"""刪除播放列表:return: None"""selected = self.song_list_list.get_selected_row()if selected is None:returndata = self.song_list_list.get_data_by_index(selected)os.remove(data["list_path"])self.song_list.clear_all_node()self.song_list_list.delete_row_base(selected)def add_songs(self):"""將歌曲添加到播放列表:return: None"""selected = self.song_list_list.get_selected_row()if selected is None:returndata = self.song_list_list.get_data_by_index(selected)music_files = askopenfilenames(initialdir=data["path"])if not music_files:returnfor music_path in music_files:self.add_song(music_path)self.save_song_list(data["list_path"], data["path"])def delete_songs(self):"""從播放列表中刪除歌曲:return: None"""selected = self.song_list_list.get_selected_row()if selected is None:returnselect_songs = self.song_list.tree.selection()for idx in select_songs:self.song_list.tree.delete(idx)data = self.song_list_list.get_data_by_index(selected)self.save_song_list(data["list_path"], data["path"])def save_song_list(self, song_list, base_path):"""保存播放列表:param song_list: 播放列表路徑:param base_path: 播放列表base路徑:return: None"""with open(song_list, "w", encoding="utf-8") as f:f.writelines(M3U_HEAD)songs = self.get_all_songs()song_list_new = []for song in songs:new_path = self.get_relatively_path(song, base_path)song_list_new.append(M3U_NEW_LINE + '\n')if not new_path.endswith('\n'):new_path += '\n'song_list_new.append(new_path)f.writelines(song_list_new)def get_all_songs(self):"""獲取所有歌曲:return: None"""all_songs = []for item in self.song_list.tree.get_children():item_text = self.song_list.tree.item(item, "values")all_songs.append(item_text[5])return all_songs@staticmethoddef get_relatively_path(music_path, base_path):"""計算相對路徑:param music_path:音樂路徑:param base_path:歌單路徑:return:string"""index = os.path.normpath(music_path).find(os.path.normpath(base_path))if index == -1:raise Exception("音樂文件必須在MUSIC目錄中")return music_path[index + len(base_path) + 1:]def main():root = Tk()path = os.path.join(os.getcwd(), 'SonySongListEditor.xml')SonySongListEditor(root, path)root.mainloop()if __name__ == "__main__":main()

    總結

    以上是生活随笔為你收集整理的【记录】python3 tkinterUI编辑器应用之索尼walkmanA35播放列表编辑工具的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。