Ajout de la gestion des playlist, des vidéo n'ayant pas de jaquette et ajout du racourci clavier "entrer" dans la zone de texte pour ajouter l'URL
This commit is contained in:
parent
84bd38eb30
commit
728be287f4
156
main.py
156
main.py
@ -7,8 +7,12 @@ from PIL import Image, ImageTk
|
|||||||
from tkinter.ttk import Progressbar
|
from tkinter.ttk import Progressbar
|
||||||
import threading
|
import threading
|
||||||
import queue
|
import queue
|
||||||
|
from tkinter.messagebox import askyesno
|
||||||
|
import os
|
||||||
|
|
||||||
def add_url():
|
res_directory = 'res'
|
||||||
|
|
||||||
|
def add_url(url=False, dowload_playlist=False):
|
||||||
|
|
||||||
#Ajoute un classe pour intercepter les logs
|
#Ajoute un classe pour intercepter les logs
|
||||||
class YTDLLogger:
|
class YTDLLogger:
|
||||||
@ -16,25 +20,105 @@ def add_url():
|
|||||||
Logger personnalisé pour capturer et afficher les messages de yt-dlp.
|
Logger personnalisé pour capturer et afficher les messages de yt-dlp.
|
||||||
"""
|
"""
|
||||||
def debug(self, msg):
|
def debug(self, msg):
|
||||||
print(msg) # Affiche les messages de debug
|
# Affiche les messages de debug
|
||||||
ProgresseLabel.config(text=msg)
|
ProgresseLabel.config(text=msg)
|
||||||
|
|
||||||
def warning(self, msg):
|
def warning(self, msg):
|
||||||
print(f"WARNING: {msg}") # Affiche les avertissements
|
# Affiche les avertissements
|
||||||
|
ProgresseLabel.config(text=f"WARNING: {msg}")
|
||||||
|
|
||||||
def error(self, msg):
|
def error(self, msg):
|
||||||
print(f"ERROR: {msg}") # Affiche les erreurs
|
# Affiche les erreurs
|
||||||
|
ProgresseLabel.config(text=f"ERROR: {msg}")
|
||||||
|
|
||||||
#Récuperer l'url
|
#Ajoute une fonction pour ajouter une vidéo a la liste
|
||||||
url = EntryURL.get()
|
def add_movies(info, is_playlist=False) :
|
||||||
|
|
||||||
|
title = info.get('title', 'Titre indisponible')
|
||||||
|
view_count = info.get('view_count', None)
|
||||||
|
subtitlte = (
|
||||||
|
info.get('artist', info.get('uploader', 'Artiste indisponible'))
|
||||||
|
+ ' · '
|
||||||
|
+ 'Nombre de vues indisponible' if view_count is None else '{:,}'.format(view_count).replace(',', ' ')
|
||||||
|
+ ' vues'
|
||||||
|
)
|
||||||
|
|
||||||
|
thumbnail_url = info.get('thumbnail')
|
||||||
|
|
||||||
|
if is_playlist :
|
||||||
|
title = '[Playlist] ' + title
|
||||||
|
subtitlte += ' · ' + str(info.get('playlist_count', 'Nombre de vidéo indisponible')) + ' vidéos'
|
||||||
|
try:
|
||||||
|
thumbnail_url = info.get('thumbnails')[0].get('url')
|
||||||
|
except TypeError :
|
||||||
|
thumbnail_url = False
|
||||||
|
|
||||||
|
# Création d'un cadre pour chaque vidéo
|
||||||
|
cadre = Frame(scrollable_frame)
|
||||||
|
cadre.pack(fill=X, padx=10, pady=5)
|
||||||
|
|
||||||
|
if thumbnail_url :
|
||||||
|
|
||||||
|
response = requests.get(thumbnail_url)
|
||||||
|
image = Image.open(BytesIO(response.content))
|
||||||
|
width, height = image.size
|
||||||
|
|
||||||
|
# Découper l'image en un carré centré
|
||||||
|
square_size = min(width, height)
|
||||||
|
left = (width - square_size) // 2
|
||||||
|
top = (height - square_size) // 2
|
||||||
|
|
||||||
|
# Calculer les coordonnées du coin inférieur droit du carré
|
||||||
|
right = left + square_size
|
||||||
|
bottom = top + square_size
|
||||||
|
|
||||||
|
# Découper l'image carrée
|
||||||
|
image = image.crop((left, top, right, bottom))
|
||||||
|
|
||||||
|
else :
|
||||||
|
image = Image.open(os.path.join(os.path.join(res_directory, "img"), 'jaquette_default.png'))
|
||||||
|
|
||||||
|
image.thumbnail((50, 50))
|
||||||
|
|
||||||
|
# Charger l'image et l'afficher
|
||||||
|
image = ImageTk.PhotoImage(image)
|
||||||
|
image_label = Label(cadre, image=image)
|
||||||
|
image_label.image = image # Préserver la référence pour éviter le garbage collection
|
||||||
|
image_label.pack(side=LEFT, padx=5)
|
||||||
|
|
||||||
|
|
||||||
|
# Ajouter les titres
|
||||||
|
texte_frame = Frame(cadre)
|
||||||
|
texte_frame.pack(side=LEFT, padx=10, fill=BOTH, expand=True)
|
||||||
|
|
||||||
|
label_texte1 = Label(texte_frame, text=title, font=("Arial", 12, "bold"))
|
||||||
|
label_texte1.pack(anchor="w")
|
||||||
|
|
||||||
|
label_texte2 = Label(texte_frame, text=subtitlte, font=("Arial", 10))
|
||||||
|
label_texte2.pack(anchor="w")
|
||||||
|
|
||||||
|
# Ajouter un bouton "Supprimer"
|
||||||
|
menu_button = Button(cadre, text="Supprimer", relief=FLAT, command=cadre.destroy)
|
||||||
|
menu_button.pack(side=RIGHT)
|
||||||
|
|
||||||
|
#Récuperer l'url si non fournie comme argument
|
||||||
|
if not url:
|
||||||
|
url = EntryURL.get()
|
||||||
|
if '&list=' in url :
|
||||||
|
if askyesno('Playlist', 'Attention, vous vous apretez à ajouter une playlist générer automatiquement par youtube, Pour garder uniquement la vidéo que vous regardiez, appuyer sur oui, si vous voulez télecharger la playlist, appuyer sur non.') :
|
||||||
|
url = url.split('&list=')[0]
|
||||||
# Effacer l'entrée URL
|
# Effacer l'entrée URL
|
||||||
EntryURL.delete(0, END)
|
EntryURL.delete(0, END)
|
||||||
|
|
||||||
ydl_opts = {
|
ydl_opts = {
|
||||||
'quiet': True, # Supprime la sortie standard (redirigée vers le logger)
|
'quiet': True, # Supprime la sortie standard (redirigée vers le logger)
|
||||||
'logger': YTDLLogger(), # Utilise le logger personnalisé
|
'logger': YTDLLogger(),
|
||||||
|
'extract_flat': True, # Utilise le logger personnalisé
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if dowload_playlist :
|
||||||
|
ydl_opts['extract_flat'] = False
|
||||||
|
|
||||||
# Queue pour recuperer les donnes
|
# Queue pour recuperer les donnes
|
||||||
q = queue.Queue()
|
q = queue.Queue()
|
||||||
|
|
||||||
@ -57,55 +141,18 @@ def add_url():
|
|||||||
|
|
||||||
if isinstance(info, dict): # Si l'info est un dictionnaire (métadonnées)
|
if isinstance(info, dict): # Si l'info est un dictionnaire (métadonnées)
|
||||||
ProgresseLabel.config(text=f"Dowloading complet")
|
ProgresseLabel.config(text=f"Dowloading complet")
|
||||||
title = info.get('title', 'Titre indisponible')
|
|
||||||
subtitlte = (
|
|
||||||
info.get('artist', info.get('uploader', 'Artiste indisponible'))
|
|
||||||
+ ' · '
|
|
||||||
+ '{:,}'.format(info.get('view_count', 'Nombre de vue indisponible')).replace(',', ' ')
|
|
||||||
+ ' vues'
|
|
||||||
)
|
|
||||||
thumbnail_url = info.get('thumbnail')
|
|
||||||
|
|
||||||
response = requests.get(thumbnail_url)
|
if info.get('_type', None) == 'playlist' : #Si c'est une playlist
|
||||||
image = Image.open(BytesIO(response.content))
|
if dowload_playlist : # Vérifie si l'utilisateur a déja répondus a la question suivante
|
||||||
width, height = image.size
|
for video in info.get('entries') :
|
||||||
|
add_movies(video)
|
||||||
|
elif askyesno('Playlist', f"L'URL que vous avez fourni est une playlist, voulez-vous l'ajouter en tant que playlist ou en plusieurs vidéos ?\nAttention, en fonction du nombre de vidéos (ici {str(info.get('playlist_count', 'Nombre de vidéo indisponible'))}), cette opération peut prendre du temps\n\n(Oui -> playliste / Non -> Vidéos)") : #Demande a l'utilisateur si on ajoute chaque vidéo séparément
|
||||||
|
add_movies(info, True)
|
||||||
|
else :
|
||||||
|
add_url(url, True)
|
||||||
|
else :
|
||||||
|
add_movies(info)
|
||||||
|
|
||||||
# Découper l'image en un carré centré
|
|
||||||
square_size = min(width, height)
|
|
||||||
left = (width - square_size) // 2
|
|
||||||
top = (height - square_size) // 2
|
|
||||||
|
|
||||||
# Calculer les coordonnées du coin inférieur droit du carré
|
|
||||||
right = left + square_size
|
|
||||||
bottom = top + square_size
|
|
||||||
|
|
||||||
# Découper l'image carrée
|
|
||||||
image = image.crop((left, top, right, bottom))
|
|
||||||
image.thumbnail((50, 50))
|
|
||||||
|
|
||||||
# Création d'un cadre pour chaque vidéo
|
|
||||||
cadre = Frame(scrollable_frame)
|
|
||||||
cadre.pack(fill=X, padx=10, pady=5)
|
|
||||||
|
|
||||||
# Charger l'image et l'afficher
|
|
||||||
image = ImageTk.PhotoImage(image)
|
|
||||||
image_label = Label(cadre, image=image)
|
|
||||||
image_label.image = image # Préserver la référence pour éviter le garbage collection
|
|
||||||
image_label.pack(side=LEFT, padx=5)
|
|
||||||
|
|
||||||
# Ajouter les titres
|
|
||||||
texte_frame = Frame(cadre)
|
|
||||||
texte_frame.pack(side=LEFT, padx=10, fill=BOTH, expand=True)
|
|
||||||
|
|
||||||
label_texte1 = Label(texte_frame, text=title, font=("Arial", 12, "bold"))
|
|
||||||
label_texte1.pack(anchor="w")
|
|
||||||
|
|
||||||
label_texte2 = Label(texte_frame, text=subtitlte, font=("Arial", 10))
|
|
||||||
label_texte2.pack(anchor="w")
|
|
||||||
|
|
||||||
# Ajouter un bouton "Supprimer"
|
|
||||||
menu_button = Button(cadre, text="Supprimer", relief=FLAT, command=cadre.destroy)
|
|
||||||
menu_button.pack(side=RIGHT)
|
|
||||||
else: # Si c'est une erreur
|
else: # Si c'est une erreur
|
||||||
ProgresseLabel.config(text=info)
|
ProgresseLabel.config(text=info)
|
||||||
|
|
||||||
@ -146,6 +193,7 @@ EntryFrame.pack(fill="x", padx=5, pady=2.5)
|
|||||||
|
|
||||||
EntryURL = Entry(EntryFrame)
|
EntryURL = Entry(EntryFrame)
|
||||||
EntryURL.pack(side=LEFT, fill="x", expand=True, padx=2.5)
|
EntryURL.pack(side=LEFT, fill="x", expand=True, padx=2.5)
|
||||||
|
EntryURL.bind("<Return>", lambda event=None: add_url())
|
||||||
|
|
||||||
EntryButton = Button(EntryFrame, text="Ajouter", command=add_url)
|
EntryButton = Button(EntryFrame, text="Ajouter", command=add_url)
|
||||||
EntryButton.pack(side=RIGHT, padx=3.5)
|
EntryButton.pack(side=RIGHT, padx=3.5)
|
||||||
|
BIN
res/img/jaquette_default.png
Normal file
BIN
res/img/jaquette_default.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
Loading…
Reference in New Issue
Block a user