#!/usr/bin/python import tkinter as tk import random import os import pytube import string printable = set(string.printable) import pygame from tkinter import filedialog, simpledialog import subprocess MUSIC_DIR = './music' PYTUBE_STATUS_MAX_TIME = 10 STATUS_BG_COLOR = '#ffc984' STATUS_BG_COLOR2 = '#e58100' CTRL_BG_COLOR = '#78ffc4' CTRL_BG_COLOR2 = '#00bf6b' TEXT_COLOR = 'white' TEXT_COLOR2 = 'white' PLAYLIST_BG_COLOR = '#9abdff' PLAYLIST_BG_COLOR2 = '#2d76ff' PYTUBE_BG_COLOR = '#ffaac0' PYTUBE_BG_COLOR2 = '#ff386b' FRAME_SX_W = 800 FRAME_DX_W = 500 STATUS_H = 150 CTRL_H = 100 #50 PLS_H = 300 PYTUBE_H = STATUS_H + CTRL_H + PLS_H FONT_FRAME = ("clean", 20, "bold") FONT_CTRL_FRAME = ("clean", 15, "bold") FONT_STATUS = ("clean", 16, "bold") FONT_BUTTONS = ("clean", 16, "bold") FONT_LIST = ("clean", 12, "bold") HOW_MANY_SEARCH = 25 class celaigia: def __init__(self, root): self.root = root self.root.title("MusicPlayer") self.root.geometry(f"{FRAME_SX_W+FRAME_DX_W}x{PYTUBE_H}") pygame.init() self.mixer = pygame.mixer self.mixer.init() self.track = tk.StringVar() self.status = tk.StringVar() self.pystatus = tk.StringVar() self.playlist_folder = tk.StringVar() self.playlist_folder.set('music/default') # Crea status frame self.StatusFrame = tk.LabelFrame(self.root, text="Quid Accidit Plaier", font=FONT_FRAME,bg=STATUS_BG_COLOR, fg=TEXT_COLOR2, bd=5, relief=tk.GROOVE) self.StatusFrame.place(x=0, y=0, width=FRAME_SX_W, height=STATUS_H) self.songtrack = tk.Label(self.StatusFrame, textvariable=self.track, width=20, font=FONT_STATUS,bg=STATUS_BG_COLOR, fg=TEXT_COLOR).place(x=0,y=0, width=int(FRAME_SX_W/2) ,height=int(STATUS_H/2)) self.trackstatus = tk.Label(self.StatusFrame, textvariable=self.status, font=FONT_STATUS,bg=STATUS_BG_COLOR, fg=TEXT_COLOR).place(x=int(FRAME_SX_W/2),y=0, width=int(FRAME_SX_W/2) ,height=int(STATUS_H*0.5)) self.pytubestatus = tk.Label(self.StatusFrame, textvariable=self.pystatus, font=FONT_STATUS,bg=STATUS_BG_COLOR, fg=TEXT_COLOR).place(x=0,y=int(STATUS_H/2), width=FRAME_SX_W ,height=int(STATUS_H/2)) self.StatusFrame.after(1*PYTUBE_STATUS_MAX_TIME, clear_on_after(self.pystatus)) # Crea frame per bottoni controlli player self.controlFrame = tk.LabelFrame(self.root, text="Controlly Plaier", font=FONT_CTRL_FRAME, bg=CTRL_BG_COLOR, fg=TEXT_COLOR2, bd=5, relief=tk.GROOVE) self.controlFrame.place(x=0, y=STATUS_H, width=FRAME_SX_W, height=CTRL_H) self.sonabtn = tk.Button(self.controlFrame, text="sona", command=self.play, width=8, height=1,font=FONT_BUTTONS, fg=TEXT_COLOR, bg=CTRL_BG_COLOR2).grid(row=0, column=0, padx=10,pady=5) self.sonatuttebtn = tk.Button(self.controlFrame, text="sona\ntutte", command=self.play_all, width=8, height=1,font=FONT_BUTTONS, fg=TEXT_COLOR, bg=CTRL_BG_COLOR2).grid(row=0, column=4, padx=10, pady=5) self.sonatutterandom = tk.Button(self.controlFrame, text="shuffle\nbaby", command=lambda: self.play_all(shuffle=True), width=8, height=1,font=FONT_BUTTONS, fg=TEXT_COLOR, bg=CTRL_BG_COLOR2).grid(row=0, column=5,padx=10, pady=5) self.pausabtn = tk.Button(self.controlFrame, text="pausa", command=self.pause, width=8, height=1, font=FONT_BUTTONS, fg=TEXT_COLOR, bg=CTRL_BG_COLOR2).grid(row=0, column=1, padx=10, pady=5) self.menopausabtn = tk.Button(self.controlFrame, text="menopausa", command=self.unpause, width=8, height=1, font=FONT_BUTTONS, fg=TEXT_COLOR, bg=CTRL_BG_COLOR2).grid(row=0, column=2, padx=10, pady=5) self.stoppabtn = tk.Button(self.controlFrame, text="stoppa", command=self.stop, width=8, height=1, font=FONT_BUTTONS, fg=TEXT_COLOR, bg=CTRL_BG_COLOR2).grid(row=0, column=3, padx=10,pady=5) # Crea Playlist Frame self.playlistFrame = tk.LabelFrame(self.root, text="Playlist", font=FONT_FRAME, bg=PLAYLIST_BG_COLOR, fg=TEXT_COLOR2, bd=5, relief=tk.GROOVE) self.playlistFrame.place(x=0, y= STATUS_H + CTRL_H, width=FRAME_SX_W, height=PLS_H) self.cur_playlist = tk.Label(self.playlistFrame, textvariable=self.playlist_folder, width=20, font=FONT_STATUS,bg=PLAYLIST_BG_COLOR , fg=TEXT_COLOR).place(x=0, y= int(PLS_H*3/4), width=int(FRAME_SX_W/2), height=int(PLS_H/4)) self.playlist = tk.Listbox(self.playlistFrame, selectbackground="gold", selectmode=tk.SINGLE, font=FONT_LIST, bg=PLAYLIST_BG_COLOR , fg=TEXT_COLOR, bd=5, relief=tk.GROOVE) self.playlist.place(x=0, y=0 ,width=FRAME_SX_W,height=int(PLS_H*3/4)) self.create_playlist_btn = tk.Button(self.playlistFrame, text="Crea\nPlaylist", font=FONT_BUTTONS,bg=PLAYLIST_BG_COLOR2, fg=TEXT_COLOR,width=40, height=5,command=self.create_playlist) self.create_playlist_btn.place(x=int(FRAME_SX_W/2), y=int(PLS_H*3/4)-5, width = int(FRAME_SX_W/6), height=int(PLS_H/4)) self.choose_playlist_btn = tk.Button(self.playlistFrame, text="Carica\nPlaylist",font=FONT_BUTTONS, bg=PLAYLIST_BG_COLOR2, fg=TEXT_COLOR,width=40, height=5, command=lambda: self.choose_playlist(kind='scratch')) self.choose_playlist_btn.place(x=int(FRAME_SX_W*2/3) , y = int(PLS_H*3/4)-5, width= int(FRAME_SX_W/6), height=int(PLS_H/4)) self.add_playlist_btn = tk.Button(self.playlistFrame, text="Aggiungi\nPlaylist",font=FONT_BUTTONS, bg=PLAYLIST_BG_COLOR2, fg=TEXT_COLOR,width=40, height=5,command=lambda: self.choose_playlist(kind='add')) self.add_playlist_btn.place(x=int(FRAME_SX_W*5/6), y=int(PLS_H*3/4)-5, width= int(FRAME_SX_W/6), height=int(PLS_H/4)) # Crea pytube frame self.pytubeFrame = tk.LabelFrame(self.root, text="Pytube", font=FONT_FRAME, bg=PYTUBE_BG_COLOR,fg=TEXT_COLOR2, bd=5, relief=tk.GROOVE) self.pytubeFrame.place(x=FRAME_SX_W, y=0, width=FRAME_DX_W, height=PYTUBE_H) tk.Label(self.pytubeFrame, text='cerca suittubo qua sotto,\n seleziona + invio per scarècar \nnella cartella/playlist curiente',font=FONT_STATUS,fg=TEXT_COLOR, bg=PYTUBE_BG_COLOR).place(x=0, y=0, width=FRAME_DX_W, height=int(PYTUBE_H/6)) self.search_entry = tk.Entry(self.pytubeFrame) self.search_entry.bind('', self.ytsearch) self.search_entry.place(x=0, y=int(PYTUBE_H/6),width=FRAME_DX_W,height=int(PYTUBE_H/6)) self.search_list = tk.Listbox(self.pytubeFrame, font=FONT_LIST,fg=TEXT_COLOR, bg=PYTUBE_BG_COLOR, selectmode=tk.SINGLE) pos = 0 for _ in range(HOW_MANY_SEARCH): item = ' x x x y y y z z z' self.search_list.insert(pos, item) pos += 1 self.search_list.bind('', self.ytdownload) self.search_list.place(x=0,y=int(PYTUBE_H/3),width=FRAME_DX_W,height=int(PYTUBE_H*2/3)) # usa db dio db self.track_paths = {} self.update_playlist(kind='scratch') def create_playlist(self): self.playlist_folder.set(MUSIC_DIR + '/' + tk.simpledialog.askstring(parent=self.playlistFrame, prompt="nome playlist:",title='acchitta playlist')) self.update_playlist(kind='scratch') def choose_playlist(self,kind): self.playlist_folder.set(tk.filedialog.askdirectory(parent=self.playlistFrame, initialdir=MUSIC_DIR,title='scegli una playlist (aka una cartella)')) self.update_playlist(kind) def update_playlist(self,kind, folder=None): if folder==None: folder = self.playlist_folder.get() if not os.path.isdir(self.playlist_folder.get()): os.makedirs(self.playlist_folder.get()) if kind =='add': for track in os.listdir(folder): if ismusic(track) & (track not in self.playlist.get(0,tk.END)): self.playlist.insert(tk.END, track) self.track_paths[track] = f"{folder}/{track}" elif kind == 'scratch': self.playlist.delete(0,tk.END) pos = 0 for track in os.listdir(folder): if ismusic(track): self.playlist.insert(pos, track) self.track_paths[track] = f"{folder}/{track}" pos += 1 def play_all(self, shuffle=False): if shuffle: songtracks = list(self.playlist.get(0,tk.END)) random.shuffle(songtracks) self.playlist.delete(0,tk.END) for i,track in enumerate(songtracks): self.playlist.insert(i,track) del songtracks self.play(self.track_paths[self.playlist.get(0)]) for ti in self.playlist.get(1,tk.END): self.mixer.music.queue(self.track_paths[ti]) def play(self,what='selezionato'): if what=='selezionato': self.track.set(self.playlist.get(tk.ACTIVE)) else: self.track.set(what.split('/')[-1]) self.status.set("- sta sònando") self.mixer.music.load(self.track_paths[self.track.get()]) self.mixer.music.play() def stop(self): self.track.set('') self.status.set("stop, dimenticami stupidu") self.mixer.music.stop() def pause(self): self.status.set("- la meccanica non mi interessa, siamo in pausa") self.mixer.music.pause() def unpause(self): self.status.set("- sta sònando") self.mixer.music.unpause() def ytsearch(self,event): self.search_list.delete(0, 2) # entrambi gli estremi compresi.. self.yt_results = {pulisci_stringa(r.title): r.watch_url for r in pytube.Search(self.search_entry.get()).results[:HOW_MANY_SEARCH]} pos = 0 self.pystatus.set(f'cerco: {self.search_entry.get()}') for item in self.yt_results.keys(): try: self.search_list.insert(pos, item) pos += 1 except: 1 def ytdownload(self,event): #wannabe: scegli formato (wav,ogg ecc) e tipo (audio/video) name = self.search_list.get(tk.ACTIVE) url = self.yt_results[name] stream = pytube.YouTube(url).streams.filter(only_audio=True).first() self.pystatus.set(f'scarico: {self.search_entry.get()}') stream.download(self.playlist_folder.get(),filename=f"{name}.mp4") if os.path.isfile(f"{self.playlist_folder.get()}/{name}.mp4"): tmp_file = f'{self.playlist_folder.get()}/{name}.mp4' self.pystatus.set(f'converto: {self.search_entry.get()}') bash(f"ffmpeg -i {tmp_file} -vn -acodec libvorbis -y {tmp_file[:-4]}.ogg") bash(f"rm {self.playlist_folder.get()}/{name}.mp4") self.pystatus.set('') self.playlist.insert(tk.END,name) self.track_paths[name]=f"{self.playlist_folder}/{name}" def pulisci_stringa(s,kind='printable'): if kind=='printable': s = ''.join(filter(lambda x: x in '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ', s)) else: print(f'ma che kind stai a dì {kind}',flush=True) return s.replace(' ','_') def ismusic(file): return file.split('.')[-1] in ['mp3', 'ogg', 'flac', 'wav'] def clear_on_after(var): var.set("") def bash(cmd): subprocess.call(['/bin/bash', '-c', cmd]) if __name__ == '__main__': app = tk.Tk() celaigia(app) app.mainloop()