#! /usr/bin/python3
from tkinter import *
from youtube_search import YoutubeSearch
import re,random, vlc,datetime, time,yt_dlp
#global vars
ran = song_index = dur = timescale_var = 0
auto = 1
play_index=-1
volume_var= 100
soundquality = 5
soundqualities = "best"
URLlist = playlist = []
#window, player
win = Tk()
win.geometry('610x100')
win.title("Youtube Player")
menubar = Menu(win)
instance = vlc.Instance()
player = instance.media_player_new()
#making the search
def Search(event):
global song_index, URLlist
search_querie = str(SearchBox.get())
song_index = 0
results = YoutubeSearch(search_querie, max_results=40).to_dict()
title=[]
URLlist=[]
resultcount = -1
#the following loop is to optionally select only short songs <5min
for v in results:
duration = v['duration']
if duration != 0:
if duration.count(':') > 1 and dur == 1:
continue
if duration.count(':') == 1:
m, s = duration.split(':')
duration = int(m) * 60 + int(s)
if duration > 300 and dur == 1:
continue
URLlist.append("https://www.youtube.com" + v['url_suffix'])
resultcount+= 1
title.append(re.sub(r"[^a-zA-Z0-9 .,:;+-=!?/()öäßü]", "", v['title']))
btnPlay.focus()
btnL.config(command = (lambda: TitleShift(title, -1, resultcount)))
btnR.config(command = (lambda:TitleShift(title, 1, resultcount)))
btnPlay.config(command = (lambda: NewSong("insert",1)))
btnAddsong.config(command = (lambda: Addsong()))
btnDL.place(x=505, y=2)
btnDL.config(command =(lambda: Download(URLlist[song_index],title[song_index])))
title_label.config(text = title[song_index])
#moving through the songlist
def TitleShift(title,move, resultcount):
win.focus()
global song_index
song_index += move
if song_index < 0:
song_index =resultcount
if song_index > resultcount:
song_index = 0
title_label.config(text = title[song_index])
#this function keeps track of time and moves the timescale
def UpdateTime():
length = player.get_length()
place = player.get_time()
if player.is_playing() == 0 and abs(place-length) < 10000 and len(playlist) > 0 and auto == 1:
NewSong("next", 1)
place = 0
player.set_time(0)
timescale.set(0)
if player.is_playing() == 1:
time_info =str(datetime.timedelta(seconds = round(place/1000))) + " / " + str(datetime.timedelta(seconds = round(length/1000)))
time_label.config(text=time_info)
timescale.set(place)
win.after(1000,lambda:UpdateTime())
def GenerateStreamUrl(URL):
audio = []
ydl_opts = {}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(URL, download=False)
formats = info['formats']
songtitle = info['title']
for i,format in enumerate(formats):
url = format['url']
other = format['resolution']
if other == "audio only":
audio.append(url)
return(audio, songtitle)
#starting the song
def NewSong(question, direction):
win.focus()
#first, the play_index is updated
global play_index
play_index += direction
if play_index > (len(playlist)-1):
play_index = 0
if question == "insert":
playlist.insert(play_index,URLlist[song_index])
else:
if ran == 1 and len(playlist) > 1:
counttemp = play_index
while counttemp == play_index:
play_index = random.randrange(len(playlist)-1)
#then, the song gets initialised
audio = []
ydl_opts = {}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(playlist[play_index], download=False)
formats = info['formats']
songtitle = info['title']
for i,format in enumerate(formats):
url = format['url']
other = format['resolution']
if other == "audio only":
audio.appendGenerateStreamUrl(urlplaylist[play_index])
if soundqualities == "best":
stream = audio[len(audio)-1]
else:
qualities = len(audio)
if soundquality > qualities:
stream = audio[qualities]
else:
stream = audio[soundquality]
#print(stream.quality, int(stream.get_filesize()/10000)/100, "mb")
playurl = stream
media=instance.media_new(playurl)
media.get_mrl()
player.set_media(media)
player.set_time(10000)
timescale.set(10000)
btnPP.place(x=340, y=2)
btnAddsong.place(x=170, y=62)
btnBACK.place(x=295, y=2)
btnBACK2.place(x=240, y=2)
btnFWD.place(x=395, y=2)
btnFWD2.place(x=445, y=2)
timescale.place(x=370, y=68)
player.play()
btnPP.config(text="||")
while player.is_playing() == 0:
time.sleep(1)
timescale.config(to = player.get_length())
win.title(songtitle)
return(0)
#this is to select the next song in the list
def Addsong():
win.focus()
playlist.append(URLlist[song_index])
#next or previous song
def SkipSong(direction):
win.focus()
skip = play_index + direction
if direction == -1 and player.get_time() > 10000:
player.set_time(0)
elif skip >= 0 and skip < len(playlist):
NewSong("next", direction)
#this function is for downloading the song
def Download(song_url, song_title):
outtmpl = song_title + '.%(ext)s'
ydl_opts = {
'format': 'bestaudio/best',
'outtmpl': outtmpl,
'postprocessors': [
{'key': 'FFmpegExtractAudio','preferredcodec': 'mp3',
'preferredquality': '192',
},
{'key': 'FFmpegMetadata'},
],
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info_dict = ydl.extract_info("youtube.com" + song_url, download=True)
#moving through the scale for time
def SetTime(timescale_var):
place = player.get_time()
if abs(int(timescale_var) - place) > 4000:
player.set_time(int(timescale_var))
#this function is for moving back and forth in time of the song
def SkipTime(amount):
win.focus()
time_sum = player.get_time() + amount
time_all = player.get_length()
if time_sum < 0:
time_sum = 0
if time_sum>time_all:
time_sum = time_all
timescale.set(time_sum)
#to pause by keypress (space)
def TogglePause1():
if str(win.focus_get()) != str(".!entry"):
funcPP()
#to pause by keypress or click
def TogglePause2():
win.focus()
pause = player.is_playing()
player.set_pause(pause)
if pause == 1:
btnPP.config(text="|>")
else:
btnPP.config(text="||")
#import all songs from querie
def ImportAll():
playlist.extend(URLlist)
#controlling the volume
def ChangeVolume(volume_var):
player.audio_set_volume(int(volume_var))
#clear playlist
def ClearPlaylist():
global playlist
playlist = []
#setting sound quality
def ChangeQuality(amount):
global soundquality, soundqualities
if amount == "best":
soundqualities = "best"
else:
soundqualities = ""
if amount == 0:
soundquality = 0
elif amount == 1 or amount ==-1:
soundquality += amount
#toggle autoplay
def ToggleAutoplay():
global auto
auto = not(auto)
#toggle limit duration of song
def ToggleDurationLimit():
global dur
dur = not(dur)
#toggling shuffle
def ToggleShuffle():
global ran
ran = not(ran)
btnPP = Button(win, text = "||", command =(lambda: TogglePause2()))
btnBACK = Button(win, text = "<", command =(lambda: SkipTime(-10000)))
btnFWD = Button(win, text = ">", command =(lambda: SkipTime(10000)))
btnBACK2 = Button(win, text = "<<", command =(lambda: SkipSong(-1)))
btnFWD2 = Button(win, text = ">>", command =(lambda: SkipSong(1)))
btnDL = Button(win, text = "↓")
btnL = Button(win, text = "<-")
btnR = Button(win, text = "->")
btnPlay = Button(win, text = "OK")
btnAddsong = Button(win, text = "+")
timescale = Scale(win, from_=0, to=1000, orient=HORIZONTAL,length=200, variable = timescale_var, showvalue=0, command = SetTime)
volume_scale = Scale(win, from_=200, to=0, orient=VERTICAL,length=80, variable = volume_var, showvalue=0, command = ChangeVolume)
volume_scale.place(x=580, y=2)
volume_scale.set(100)
title_label = Label(win, text = "")
title_label.place(x=5, y=36)
time_label = Label(win, text = "")
time_label.place(x=220, y=66)
SearchBox = Entry(win, width=20)
SearchBox.place(x=5, y=5)
SearchBox.bind('<Return>', Search)
btnL.place(x=5, y=62)
btnR.place(x=60, y=62)
btnPlay.place(x=115, y=62)
win.bind_all("<Button-1>", lambda event: event.widget.focus_set())
filemenu = Menu(win, tearoff=0)
filemenu.add_command(label="toggle shuffle", command=ToggleShuffle)
filemenu.add_command(label="toggle limit duration", command=ToggleDurationLimit)
filemenu.add_command(label="toggle autoplay", command=ToggleAutoplay)
editmenu = Menu(menubar, tearoff=0)
editmenu.add_command(label="all results to playlist", command=ImportAll)
editmenu.add_command(label="clear playlist", command=ClearPlaylist)
qualmenu = Menu(menubar, tearoff=0)
qualmenu.add_command(label="quality up", command=(lambda: ChangeQuality(1)))
qualmenu.add_command(label="quality down", command=(lambda: ChangeQuality(-1)))
qualmenu.add_command(label="best quality", command=(lambda: ChangeQuality("best")))
qualmenu.add_command(label="worst quality", command=(lambda: ChangeQuality(0)))
menubar.add_cascade(label="Quality", menu=qualmenu)
menubar.add_cascade(label="Options", menu=filemenu)
menubar.add_cascade(label="Playlists", menu=editmenu)
win.config(menu=menubar)
win.bind('<space>',lambda event:TogglePause1())
win.after(2000, lambda:UpdateTime())
SearchBox.focus()
win.mainloop()
#! /usr/bin/python3
from tkinter import *
from youtube_search import YoutubeSearch
import re,random, vlc,datetime, time,yt_dlp
#global vars
ran = song_index = dur = timescale_var = 0
auto = 1
play_index=-1
volume_var= 100
soundquality = 5
soundqualities = "best"
URLlist = playlist = []
#window, player
win = Tk()
win.geometry('610x100')
win.title("Youtube Player")
menubar = Menu(win)
instance = vlc.Instance()
player = instance.media_player_new()
#making the search
def Search(event):
global song_index, URLlist
search_querie = str(SearchBox.get())
song_index = 0
results = YoutubeSearch(search_querie, max_results=40).to_dict()
title=[]
URLlist=[]
resultcount = -1
#the following loop is to optionally select only short songs <5min
for v in results:
duration = v['duration']
if duration != 0:
if duration.count(':') > 1 and dur == 1:
continue
if duration.count(':') == 1:
m, s = duration.split(':')
duration = int(m) * 60 + int(s)
if duration > 300 and dur == 1:
continue
URLlist.append("https://www.youtube.com" + v['url_suffix'])
resultcount+= 1
title.append(re.sub(r"[^a-zA-Z0-9 .,:;+-=!?/()öäßü]", "", v['title']))
btnPlay.focus()
btnL.config(command = (lambda: TitleShift(title, -1, resultcount)))
btnR.config(command = (lambda:TitleShift(title, 1, resultcount)))
btnPlay.config(command = (lambda: NewSong("insert",1)))
btnAddsong.config(command = (lambda: Addsong()))
btnDL.place(x=505, y=2)
btnDL.config(command =(lambda: Download(URLlist[song_index],title[song_index])))
title_label.config(text = title[song_index])
#moving through the songlist
def TitleShift(title,move, resultcount):
win.focus()
global song_index
song_index += move
if song_index < 0:
song_index =resultcount
if song_index > resultcount:
song_index = 0
title_label.config(text = title[song_index])
#this function keeps track of time and moves the timescale
def UpdateTime():
length = player.get_length()
place = player.get_time()
if player.is_playing() == 0 and abs(place-length) < 10000 and len(playlist) > 0 and auto == 1:
NewSong("next", 1)
if player.is_playing() == 1:
time_info =str(datetime.timedelta(seconds = round(place/1000))) + " / " + str(datetime.timedelta(seconds = round(length/1000)))
time_label.config(text=time_info)
timescale.set(place)
win.after(1000,lambda:UpdateTime())
#starting the song
def NewSong(question, direction):
win.focus()
#first, the play_index is updated
global play_index
play_index += direction
if play_index > (len(playlist)-1):
play_index = 0
if question == "insert":
playlist.insert(play_index,URLlist[song_index])
else:
if ran == 1 and len(playlist) > 1:
counttemp = play_index
while counttemp == play_index:
play_index = random.randrange(len(playlist)-1)
#then, the song gets initialised
audio = []
ydl_opts = {}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(playlist[play_index], download=False)
formats = info['formats']
songtitle = info['title']
for i,format in enumerate(formats):
url = format['url']
other = format['resolution']
if other == "audio only":
audio.append(url)
if soundqualities == "best":
stream = audio[len(audio)-1]
else:
qualities = len(audio)
if soundquality > qualities:
stream = audio[qualities]
else:
stream = audio[soundquality]
#print(stream.quality, int(stream.get_filesize()/10000)/100, "mb")
playurl = stream
media=instance.media_new(playurl)
media.get_mrl()
player.set_media(media)
player.set_time(1000)
timescale.set(1000)
btnPP.place(x=340, y=2)
btnAddsong.place(x=170, y=62)
btnBACK.place(x=295, y=2)
btnBACK2.place(x=240, y=2)
btnFWD.place(x=395, y=2)
btnFWD2.place(x=445, y=2)
timescale.place(x=370, y=68)
player.play()
btnPP.config(text="||")
while player.is_playing() == 0:
time.sleep(1)
timescale.config(to = player.get_length())
win.title(songtitle)
return(0)
#this is to select the next song in the list
def Addsong():
win.focus()
playlist.append(URLlist[song_index])
#next or previous song
def SkipSong(direction):
win.focus()
skip = play_index + direction
if direction == -1 and player.get_time() > 10000:
player.set_time(0)
elif skip >= 0 and skip < len(playlist):
NewSong("next", direction)
#this function is for downloading the song
def Download(song_url, song_title):
outtmpl = song_title + '.%(ext)s'
ydl_opts = {
'format': 'bestaudio/best',
'outtmpl': outtmpl,
'postprocessors': [
{'key': 'FFmpegExtractAudio','preferredcodec': 'mp3',
'preferredquality': '192',
},
{'key': 'FFmpegMetadata'},
],
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info_dict = ydl.extract_info("youtube.com" + song_url, download=True)
#moving through the scale for time
def SetTime(timescale_var):
place = player.get_time()
if abs(int(timescale_var) - place) > 4000:
player.set_time(int(timescale_var))
#this function is for moving back and forth in time of the song
def SkipTime(amount):
win.focus()
time_sum = player.get_time() + amount
time_all = player.get_length()
if time_sum < 0:
time_sum = 0
if time_sum>time_all:
time_sum = time_all
timescale.set(time_sum)
#to pause by keypress (space)
def TogglePause1():
if str(win.focus_get()) != str(".!entry"):
funcPP()
#to pause by keypress or click
def TogglePause2():
win.focus()
pause = player.is_playing()
player.set_pause(pause)
if pause == 1:
btnPP.config(text="|>")
else:
btnPP.config(text="||")
#import all songs from querie
def ImportAll():
playlist.extend(URLlist)
#controlling the volume
def ChangeVolume(volume_var):
player.audio_set_volume(int(volume_var))
#clear playlist
def ClearPlaylist():
global playlist
playlist = []
#setting sound quality
def ChangeQuality(amount):
global soundquality, soundqualities
if amount == "best":
soundqualities = "best"
else:
soundqualities = ""
if amount == 0:
soundquality = 0
elif amount == 1 or amount ==-1:
soundquality += amount
#toggle autoplay
def ToggleAutoplay():
global auto
auto = not(auto)
#toggle limit duration of song
def ToggleDurationLimit():
global dur
dur = not(dur)
#toggling shuffle
def ToggleShuffle():
global ran
ran = not(ran)
btnPP = Button(win, text = "||", command =(lambda: TogglePause2()))
btnBACK = Button(win, text = "<", command =(lambda: SkipTime(-10000)))
btnFWD = Button(win, text = ">", command =(lambda: SkipTime(10000)))
btnBACK2 = Button(win, text = "<<", command =(lambda: SkipSong(-1)))
btnFWD2 = Button(win, text = ">>", command =(lambda: SkipSong(1)))
btnDL = Button(win, text = "↓")
btnL = Button(win, text = "<-")
btnR = Button(win, text = "->")
btnPlay = Button(win, text = "OK")
btnAddsong = Button(win, text = "+")
timescale = Scale(win, from_=0, to=1000, orient=HORIZONTAL,length=200, variable = timescale_var, showvalue=0, command = SetTime)
volume_scale = Scale(win, from_=200, to=0, orient=VERTICAL,length=80, variable = volume_var, showvalue=0, command = ChangeVolume)
volume_scale.place(x=580, y=2)
volume_scale.set(100)
title_label = Label(win, text = "")
title_label.place(x=5, y=36)
time_label = Label(win, text = "")
time_label.place(x=220, y=66)
SearchBox = Entry(win, width=20)
SearchBox.place(x=5, y=5)
SearchBox.bind('<Return>', Search)
btnL.place(x=5, y=62)
btnR.place(x=60, y=62)
btnPlay.place(x=115, y=62)
win.bind_all("<Button-1>", lambda event: event.widget.focus_set())
filemenu = Menu(win, tearoff=0)
filemenu.add_command(label="toggle shuffle", command=ToggleShuffle)
filemenu.add_command(label="toggle limit duration", command=ToggleDurationLimit)
filemenu.add_command(label="toggle autoplay", command=ToggleAutoplay)
editmenu = Menu(menubar, tearoff=0)
editmenu.add_command(label="all results to playlist", command=ImportAll)
editmenu.add_command(label="clear playlist", command=ClearPlaylist)
qualmenu = Menu(menubar, tearoff=0)
qualmenu.add_command(label="quality up", command=(lambda: ChangeQuality(1)))
qualmenu.add_command(label="quality down", command=(lambda: ChangeQuality(-1)))
qualmenu.add_command(label="best quality", command=(lambda: ChangeQuality("best")))
qualmenu.add_command(label="worst quality", command=(lambda: ChangeQuality(0)))
menubar.add_cascade(label="Quality", menu=qualmenu)
menubar.add_cascade(label="Options", menu=filemenu)
menubar.add_cascade(label="Playlists", menu=editmenu)
win.config(menu=menubar)
win.bind('<space>',lambda event:TogglePause1())
win.after(2000, lambda:UpdateTime())
SearchBox.focus()
win.mainloop()
#! /usr/bin/python3
from tkinter import *
from youtube_search import YoutubeSearch
import re,random, vlc,datetime, time,yt_dlp
#global vars
ran = song_index = dur = timescale_var = 0
auto = 1
play_index=-1
volume_var= 100
soundquality = 5
soundqualities = "best"
URLlist = playlist = []
#window, player
win = Tk()
win.geometry('610x100')
win.title("Youtube Player")
menubar = Menu(win)
instance = vlc.Instance()
player = instance.media_player_new()
#making the search
def Search(event):
global song_index, URLlist
search_querie = str(SearchBox.get())
song_index = 0
results = YoutubeSearch(search_querie, max_results=40).to_dict()
title=[]
URLlist=[]
resultcount = -1
#the following loop is to optionally select only short songs <5min
for v in results:
duration = v['duration']
if duration != 0:
if duration.count(':') > 1 and dur == 1:
continue
if duration.count(':') == 1:
m, s = duration.split(':')
duration = int(m) * 60 + int(s)
if duration > 300 and dur == 1:
continue
URLlist.append("https://www.youtube.com" + v['url_suffix'])
resultcount+= 1
title.append(re.sub(r"[^a-zA-Z0-9 .,:;+-=!?/()öäßü]", "", v['title']))
btnPlay.focus()
btnL.config(command = (lambda: TitleShift(title, -1, resultcount)))
btnR.config(command = (lambda:TitleShift(title, 1, resultcount)))
btnPlay.config(command = (lambda: NewSong("insert",1)))
btnAddsong.config(command = (lambda: Addsong()))
btnDL.place(x=505, y=2)
btnDL.config(command =(lambda: Download(URLlist[song_index],title[song_index])))
title_label.config(text = title[song_index])
#moving through the songlist
def TitleShift(title,move, resultcount):
win.focus()
global song_index
song_index += move
if song_index < 0:
song_index =resultcount
if song_index > resultcount:
song_index = 0
title_label.config(text = title[song_index])
#this function keeps track of time and moves the timescale
def UpdateTime():
length = player.get_length()
place = player.get_time()
if player.is_playing() == 0 and abs(place-length) < 10000 and len(playlist) > 0 and auto == 1:
NewSong("next", 1)
place = 0
player.set_time(0)
timescale.set(0)
if player.is_playing() == 1:
time_info =str(datetime.timedelta(seconds = round(place/1000))) + " / " + str(datetime.timedelta(seconds = round(length/1000)))
time_label.config(text=time_info)
timescale.set(place)
win.after(1000,lambda:UpdateTime())
def GenerateStreamUrl(URL):
audio = []
ydl_opts = {}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(URL, download=False)
formats = info['formats']
songtitle = info['title']
for i,format in enumerate(formats):
url = format['url']
other = format['resolution']
if other == "audio only":
audio.append(url)
return(audio, songtitle)
#starting the song
def NewSong(question, direction):
win.focus()
#first, the play_index is updated
global play_index
play_index += direction
if play_index > (len(playlist)-1):
play_index = 0
if question == "insert":
playlist.insert(play_index,URLlist[song_index])
else:
if ran == 1 and len(playlist) > 1:
counttemp = play_index
while counttemp == play_index:
play_index = random.randrange(len(playlist)-1)
audio, songtitle = GenerateStreamUrl(playlist[play_index])
if soundqualities == "best":
stream = audio[len(audio)-1]
else:
qualities = len(audio)
if soundquality > qualities:
stream = audio[qualities]
else:
stream = audio[soundquality]
#print(stream.quality, int(stream.get_filesize()/10000)/100, "mb")
playurl = stream
media=instance.media_new(playurl)
media.get_mrl()
player.set_media(media)
player.set_time(0)
timescale.set(0)
btnPP.place(x=340, y=2)
btnAddsong.place(x=170, y=62)
btnBACK.place(x=295, y=2)
btnBACK2.place(x=240, y=2)
btnFWD.place(x=395, y=2)
btnFWD2.place(x=445, y=2)
timescale.place(x=370, y=68)
player.play()
btnPP.config(text="||")
while player.is_playing() == 0:
time.sleep(1)
timescale.config(to = player.get_length())
win.title(songtitle)
return(0)
#this is to select the next song in the list
def Addsong():
win.focus()
playlist.append(URLlist[song_index])
#next or previous song
def SkipSong(direction):
win.focus()
skip = play_index + direction
if direction == -1 and player.get_time() > 10000:
player.set_time(0)
elif skip >= 0 and skip < len(playlist):
NewSong("next", direction)
#this function is for downloading the song
def Download(song_url, song_title):
outtmpl = song_title + '.%(ext)s'
ydl_opts = {
'format': 'bestaudio/best',
'outtmpl': outtmpl,
'postprocessors': [
{'key': 'FFmpegExtractAudio','preferredcodec': 'mp3',
'preferredquality': '192',
},
{'key': 'FFmpegMetadata'},
],
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info_dict = ydl.extract_info("youtube.com" + song_url, download=True)
#moving through the scale for time
def SetTime(timescale_var):
place = player.get_time()
if abs(int(timescale_var) - place) > 4000:
player.set_time(int(timescale_var))
#this function is for moving back and forth in time of the song
def SkipTime(amount):
win.focus()
time_sum = player.get_time() + amount
time_all = player.get_length()
if time_sum < 0:
time_sum = 0
if time_sum>time_all:
time_sum = time_all
timescale.set(time_sum)
#to pause by keypress (space)
def TogglePause1():
if str(win.focus_get()) != str(".!entry"):
funcPP()
#to pause by keypress or click
def TogglePause2():
win.focus()
pause = player.is_playing()
player.set_pause(pause)
if pause == 1:
btnPP.config(text="|>")
else:
btnPP.config(text="||")
#import all songs from querie
def ImportAll():
playlist.extend(URLlist)
#controlling the volume
def ChangeVolume(volume_var):
player.audio_set_volume(int(volume_var))
#clear playlist
def ClearPlaylist():
global playlist
playlist = []
#setting sound quality
def ChangeQuality(amount):
global soundquality, soundqualities
if amount == "best":
soundqualities = "best"
else:
soundqualities = ""
if amount == 0:
soundquality = 0
elif amount == 1 or amount ==-1:
soundquality += amount
#toggle autoplay
def ToggleAutoplay():
global auto
auto = not(auto)
#toggle limit duration of song
def ToggleDurationLimit():
global dur
dur = not(dur)
#toggling shuffle
def ToggleShuffle():
global ran
ran = not(ran)
btnPP = Button(win, text = "||", command =(lambda: TogglePause2()))
btnBACK = Button(win, text = "<", command =(lambda: SkipTime(-10000)))
btnFWD = Button(win, text = ">", command =(lambda: SkipTime(10000)))
btnBACK2 = Button(win, text = "<<", command =(lambda: SkipSong(-1)))
btnFWD2 = Button(win, text = ">>", command =(lambda: SkipSong(1)))
btnDL = Button(win, text = "↓")
btnL = Button(win, text = "<-")
btnR = Button(win, text = "->")
btnPlay = Button(win, text = "OK")
btnAddsong = Button(win, text = "+")
timescale = Scale(win, from_=0, to=1000, orient=HORIZONTAL,length=200, variable = timescale_var, showvalue=0, command = SetTime)
volume_scale = Scale(win, from_=200, to=0, orient=VERTICAL,length=80, variable = volume_var, showvalue=0, command = ChangeVolume)
volume_scale.place(x=580, y=2)
volume_scale.set(100)
title_label = Label(win, text = "")
title_label.place(x=5, y=36)
time_label = Label(win, text = "")
time_label.place(x=220, y=66)
SearchBox = Entry(win, width=20)
SearchBox.place(x=5, y=5)
SearchBox.bind('<Return>', Search)
btnL.place(x=5, y=62)
btnR.place(x=60, y=62)
btnPlay.place(x=115, y=62)
win.bind_all("<Button-1>", lambda event: event.widget.focus_set())
filemenu = Menu(win, tearoff=0)
filemenu.add_command(label="toggle shuffle", command=ToggleShuffle)
filemenu.add_command(label="toggle limit duration", command=ToggleDurationLimit)
filemenu.add_command(label="toggle autoplay", command=ToggleAutoplay)
editmenu = Menu(menubar, tearoff=0)
editmenu.add_command(label="all results to playlist", command=ImportAll)
editmenu.add_command(label="clear playlist", command=ClearPlaylist)
qualmenu = Menu(menubar, tearoff=0)
qualmenu.add_command(label="quality up", command=(lambda: ChangeQuality(1)))
qualmenu.add_command(label="quality down", command=(lambda: ChangeQuality(-1)))
qualmenu.add_command(label="best quality", command=(lambda: ChangeQuality("best")))
qualmenu.add_command(label="worst quality", command=(lambda: ChangeQuality(0)))
menubar.add_cascade(label="Quality", menu=qualmenu)
menubar.add_cascade(label="Options", menu=filemenu)
menubar.add_cascade(label="Playlists", menu=editmenu)
win.config(menu=menubar)
win.bind('<space>',lambda event:TogglePause1())
win.after(2000, lambda:UpdateTime())
SearchBox.focus()
win.mainloop()
I found one major improvement to my code, which is to make it independant of pafy. Pafy is a badly functioning library, and in fact, it is only there to make using yt_dlp easier.
Also, I add a requirements.txt file to make install easier.
#! /usr/bin/python3
from tkinter import *
from youtube_search import YoutubeSearch
import re,random, vlc,datetime, time,yt_dlp
#global vars
ran = song_index = dur = timescale_var = 0
auto = 1
play_index=-1
volume_var= 100
soundquality = 5
soundqualities = "best"
URLlist = playlist = []
#window, player
win = Tk()
win.geometry('610x100')
win.title("Youtube Player")
menubar = Menu(win)
instance = vlc.Instance()
player = instance.media_player_new()
#making the search
def Search(event):
global song_index, URLlist
search_querie = str(SearchBox.get())
song_index = 0
results = YoutubeSearch(search_querie, max_results=40).to_dict()
title=[]
URLlist=[]
resultcount = -1
#the following loop is to optionally select only short songs <5min
for v in results:
duration = v['duration']
if duration != 0:
if duration.count(':') > 1 and dur == 1:
continue
if duration.count(':') == 1:
m, s = duration.split(':')
duration = int(m) * 60 + int(s)
if duration > 300 and dur == 1:
continue
URLlist.append("https://www.youtube.com" + v['url_suffix'])
resultcount+= 1
title.append(re.sub(r"[^a-zA-Z0-9 .,:;+-=!?/()öäßü]", "", v['title']))
btnPlay.focus()
btnL.config(command = (lambda: TitleShift(title, -1, resultcount)))
btnR.config(command = (lambda:TitleShift(title, 1, resultcount)))
btnPlay.config(command = (lambda: NewSong("insert",1)))
btnAddsong.config(command = (lambda: Addsong()))
btnDL.place(x=505, y=2)
btnDL.config(command =(lambda: Download(URLlist[song_index],title[song_index])))
title_label.config(text = title[song_index])
#moving through the songlist
def TitleShift(title,move, resultcount):
win.focus()
global song_index
song_index += move
if song_index < 0:
song_index =resultcount
if song_index > resultcount:
song_index = 0
title_label.config(text = title[song_index])
#this function keeps track of time and moves the timescale
def UpdateTime():
length = player.get_length()
place = player.get_time()
if player.is_playing() == 0 and abs(place-length) < 10000 and len(playlist) > 0 and auto == 1:
NewSong("next", 1)
if player.is_playing() == 1:
time_info =str(datetime.timedelta(seconds = round(place/1000))) + " / " + str(datetime.timedelta(seconds = round(length/1000)))
time_label.config(text=time_info)
timescale.set(place)
win.after(1000,lambda:UpdateTime())
#starting the song
def NewSong(question, direction):
win.focus()
#first, the play_index is updated
global play_index
play_index += direction
if play_index > (len(playlist)-1):
play_index = 0
if question == "insert":
playlist.insert(play_index,URLlist[song_index])
else:
if ran == 1 and len(playlist) > 1:
counttemp = play_index
while counttemp == play_index:
play_index = random.randrange(len(playlist)-1)
#then, the song gets initialised
audio = []
ydl_opts = {}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(playlist[play_index], download=False)
formats = info['formats']
songtitle = info['title']
for i,format in enumerate(formats):
url = format['url']
other = format['resolution']
if other == "audio only":
audio.append(url)
if soundqualities == "best":
stream = audio[len(audio)-1]
else:
qualities = len(audio)
if soundquality > qualities:
stream = audio[qualities]
else:
stream = audio[soundquality]
#print(stream.quality, int(stream.get_filesize()/10000)/100, "mb")
playurl = stream
media=instance.media_new(playurl)
media.get_mrl()
player.set_media(media)
player.set_time(1000)
timescale.set(1000)
btnPP.place(x=340, y=2)
btnAddsong.place(x=170, y=62)
btnBACK.place(x=295, y=2)
btnBACK2.place(x=240, y=2)
btnFWD.place(x=395, y=2)
btnFWD2.place(x=445, y=2)
timescale.place(x=370, y=68)
player.play()
btnPP.config(text="||")
while player.is_playing() == 0:
time.sleep(1)
timescale.config(to = player.get_length())
win.title(songtitle)
return(0)
#this is to select the next song in the list
def Addsong():
win.focus()
playlist.append(URLlist[song_index])
#next or previous song
def SkipSong(direction):
win.focus()
skip = play_index + direction
if direction == -1 and player.get_time() > 10000:
player.set_time(0)
elif skip >= 0 and skip < len(playlist):
NewSong("next", direction)
#this function is for downloading the song
def Download(song_url, song_title):
outtmpl = song_title + '.%(ext)s'
ydl_opts = {
'format': 'bestaudio/best',
'outtmpl': outtmpl,
'postprocessors': [
{'key': 'FFmpegExtractAudio','preferredcodec': 'mp3',
'preferredquality': '192',
},
{'key': 'FFmpegMetadata'},
],
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info_dict = ydl.extract_info("youtube.com" + song_url, download=True)
#moving through the scale for time
def SetTime(timescale_var):
place = player.get_time()
if abs(int(timescale_var) - place) > 4000:
player.set_time(int(timescale_var))
#this function is for moving back and forth in time of the song
def SkipTime(amount):
win.focus()
time_sum = player.get_time() + amount
time_all = player.get_length()
if time_sum < 0:
time_sum = 0
if time_sum>time_all:
time_sum = time_all
timescale.set(time_sum)
#to pause by keypress (space)
def TogglePause1():
if str(win.focus_get()) != str(".!entry"):
funcPP()
#to pause by keypress or click
def TogglePause2():
win.focus()
pause = player.is_playing()
player.set_pause(pause)
if pause == 1:
btnPP.config(text="|>")
else:
btnPP.config(text="||")
#import all songs from querie
def ImportAll():
playlist.extend(URLlist)
#controlling the volume
def ChangeVolume(volume_var):
player.audio_set_volume(int(volume_var))
#clear playlist
def ClearPlaylist():
global playlist
playlist = []
#setting sound quality
def ChangeQuality(amount):
global soundquality, soundqualities
if amount == "best":
soundqualities = "best"
else:
soundqualities = ""
if amount == 0:
soundquality = 0
elif amount == 1 or amount ==-1:
soundquality += amount
#toggle autoplay
def ToggleAutoplay():
global auto
auto = not(auto)
#toggle limit duration of song
def ToggleDurationLimit():
global dur
dur = not(dur)
#toggling shuffle
def ToggleShuffle():
global ran
ran = not(ran)
btnPP = Button(win, text = "||", command =(lambda: TogglePause2()))
btnBACK = Button(win, text = "<", command =(lambda: SkipTime(-10000)))
btnFWD = Button(win, text = ">", command =(lambda: SkipTime(10000)))
btnBACK2 = Button(win, text = "<<", command =(lambda: SkipSong(-1)))
btnFWD2 = Button(win, text = ">>", command =(lambda: SkipSong(1)))
btnDL = Button(win, text = "↓")
btnL = Button(win, text = "<-")
btnR = Button(win, text = "->")
btnPlay = Button(win, text = "OK")
btnAddsong = Button(win, text = "+")
timescale = Scale(win, from_=0, to=1000, orient=HORIZONTAL,length=200, variable = timescale_var, showvalue=0, command = SetTime)
volume_scale = Scale(win, from_=200, to=0, orient=VERTICAL,length=80, variable = volume_var, showvalue=0, command = ChangeVolume)
volume_scale.place(x=580, y=2)
volume_scale.set(100)
title_label = Label(win, text = "")
title_label.place(x=5, y=36)
time_label = Label(win, text = "")
time_label.place(x=220, y=66)
SearchBox = Entry(win, width=20)
SearchBox.place(x=5, y=5)
SearchBox.bind('<Return>', Search)
btnL.place(x=5, y=62)
btnR.place(x=60, y=62)
btnPlay.place(x=115, y=62)
win.bind_all("<Button-1>", lambda event: event.widget.focus_set())
filemenu = Menu(win, tearoff=0)
filemenu.add_command(label="toggle shuffle", command=ToggleShuffle)
filemenu.add_command(label="toggle limit duration", command=ToggleDurationLimit)
filemenu.add_command(label="toggle autoplay", command=ToggleAutoplay)
editmenu = Menu(menubar, tearoff=0)
editmenu.add_command(label="all results to playlist", command=ImportAll)
editmenu.add_command(label="clear playlist", command=ClearPlaylist)
qualmenu = Menu(menubar, tearoff=0)
qualmenu.add_command(label="quality up", command=(lambda: ChangeQuality(1)))
qualmenu.add_command(label="quality down", command=(lambda: ChangeQuality(-1)))
qualmenu.add_command(label="best quality", command=(lambda: ChangeQuality("best")))
qualmenu.add_command(label="worst quality", command=(lambda: ChangeQuality(0)))
menubar.add_cascade(label="Quality", menu=qualmenu)
menubar.add_cascade(label="Options", menu=filemenu)
menubar.add_cascade(label="Playlists", menu=editmenu)
win.config(menu=menubar)
win.bind('<space>',lambda event:TogglePause1())
win.after(2000, lambda:UpdateTime())
SearchBox.focus()
win.mainloop()
Requirements:
python_vlc==3.0.7110
youtube_search==2.1.2
yt_dlp==2022年11月11日
lang-py