# -*- coding: utf8 -*-
# mod/aba.py
import cfg
import inc.infos as infos
import inc.mpc as mpc
import mod.commun as commun
from inc.inputkiz import input_seq
# variables du modules
# question : est-ce nécessaire de les garder en mémoire,
# ou bien on les définit à chaque opération ?
all_lvr = [] # all livres = tous les livres de la bibliothèque
sel_lvr = [] # la sélection des livres
sel_n2i = {} # retrouver l'index d'un champ "n" dans sel_lvr[]
ouverture_biblio=False
def aba_infos_go():
""" infos visuelles simples aba """
infos.m_g("vous écoutez, " + lv_titre() + ", de " + lv_auteur())
def aba_fav1():
""" ajoute le livre actuel aux favoris et téléchargements
trois fois de suite : retélécharge, après confirmation, le livre
"""
fav_add()
def aba_fav2():
""" supprime le livre actuel des favoris et téléchargements,
trois fois de suite : ajoute aux bannis
"""
del_num4c = lv_num4c()
msg = "supprimer " + zero_off(del_num4c) + " des favoris"
infos.pdrNew(msg)
suppression = favoris_bannis(del_num4c, "del_fav")
if suppression == False:
# le livre n'est pas dans les favoris,
# on supprime le dossier
dossier_du_livre = bbl_folder() + "/" + del_num4c
if commun.dir_exists(dossier_du_livre):
cmd = "rm -rf " + dossier_du_livre
mpc.sub_proc(cmd)
else:
# le dossier n'existe pas,
# on ajoute ce livre aux bannis
favoris_bannis(del_num4c, "add_bannis")
def aba_fav3():
""" menu favoris """
pass
def alogger(s):
""" fichier log pour débugger """
pass
def bbl_changer(cle_biblio):
""" changement de bibliothèque grâce au menu vocal """
bibo = bbl_actu()
if bibo == cle_biblio:
msg = "Vous êtes déjà dans la bibliothèque " + bbl_nom()
infos.pdrNew(msg)
else:
if nb_livres_total() > 0:
memo_pos_livre_aba()
save_num4c_actuel(lv_num4c())
infos.ini_set("aba_bbl_actuelle", cle_biblio)
reprendre('pas_lancement des audiolivres')
def bbl_audio_cite_classiques():
bbl_changer("audio_cite_classiques")
def bbl_audio_cite_contemporains():
bbl_changer("audio_cite_contemporains")
def bbl_cle_usb_anarchie():
""" lire les livres de la clé usb """
bbl_changer("cle_usb_anarchie")
def bbl_librivoxde():
bbl_changer("librivoxde")
def bbl_librivoxen():
bbl_changer("librivoxen")
def bbl_librivoxfr():
bbl_changer("librivoxfr")
def bbl_litterature():
bbl_changer("litteaudio")
def bbl_perso_zip():
""" lire les livres en ligne perso """
# procéder pour cette bibliothèque comme pour litterature audio, librivox ...
# en créant le tableau all_lvr[] adéquat
bbl_changer("perso_zip")
def bbl_loyalbooksfr():
bbl_changer("loyalbooksfr")
def bib_prec():
""" aller à la bibliothèque précédente
"""
# "loyalbooksfr"
# "divers_src"
# "litteaudio"
# "librivoxfr"
# "librivoxen"
# "librivoxde"
# cfg.bbl_PERSO_ZIP
# cfg.bbl_CLE_USB_ORDONNEE
# cfg.bbl_CLE_USB_ANARCHIE
# "audio_cite_contemporains"
# "audio_cite_classiques"
ba = bbl_actu()
nba = ""
if ba == "loyalbooksfr":
nba = "divers_src"
if ba == "divers_src":
nba = "litteaudio"
elif ba == "litteaudio":
nba = "librivoxfr"
elif ba == "librivoxfr":
nba = "librivoxen"
elif ba == "librivoxen":
nba = "librivoxde"
elif ba == "librivoxde":
nba = cfg.bbl_PERSO_ZIP
elif ba == cfg.bbl_PERSO_ZIP:
nba = cfg.bbl_CLE_USB_ORDONNEE
elif ba == cfg.bbl_CLE_USB_ORDONNEE:
nba = cfg.bbl_CLE_USB_ANARCHIE
elif ba == cfg.bbl_CLE_USB_ANARCHIE:
nba = "audio_cite_contemporains"
elif ba == "audio_cite_contemporains":
nba = "audio_cite_classiques"
elif ba == "audio_cite_classiques":
nba = "loyalbooksfr"
if nba == "":
nba = "audio_cite_classiques"
bbl_changer(nba)
def bib_suiv():
""" aller à la bibliothèque suivante
"""
# "audio_cite_classiques"
# "audio_cite_contemporains"
# cfg.bbl_CLE_USB_ANARCHIE
# cfg.bbl_CLE_USB_ORDONNEE
# cfg.bbl_PERSO_ZIP
# "librivoxde"
# "librivoxen"
# "librivoxfr"
# "litteaudio"
# "divers_src"
# "loyalbooksfr"
ba = bbl_actu()
nba = ""
if ba == "audio_cite_classiques":
nba = "audio_cite_contemporains"
elif ba == "audio_cite_contemporains":
nba = cfg.bbl_CLE_USB_ANARCHIE
elif ba == cfg.bbl_CLE_USB_ANARCHIE:
nba = cfg.bbl_CLE_USB_ORDONNEE
elif ba == cfg.bbl_CLE_USB_ORDONNEE:
nba = cfg.bbl_PERSO_ZIP
elif ba == cfg.bbl_PERSO_ZIP:
nba = "librivoxde"
elif ba == "librivoxde":
nba = "librivoxen"
elif ba == "librivoxen":
nba = "librivoxfr"
elif ba == "librivoxfr":
nba = "litteaudio"
elif ba == "litteaudio":
nba = "divers_src"
elif ba == "divers_src":
nba = "loyalbooksfr"
elif ba == "loyalbooksfr":
nba = "audio_cite_classiques"
if nba == "":
nba = "audio_cite_classiques"
bbl_changer(nba)
# gestion des favoris et des bannis
def fav_add():
""" ajouter le livre aux favoris de la bibliothèque en cours """
favoris_bannis(lv_num4c(), "add_fav")
def fav_del():
""" supprime le livre des favoris de la bibliothèque en cours """
favoris_bannis(lv_num4c(), "del_fav")
def ban_add():
""" ajouter le livre aux bannis de la bibliothèque en cours """
favoris_bannis(lv_num4c(), "add_ban")
def ban_del():
""" supprime le livre des bannis de la bibliothèque en cours """
favoris_bannis(lv_num4c(), "del_ban")
def fav_menu():
""" lance le menu vocal fav_ban """
explic = "utiliser les touches 1 à {} pour gérer vos favoris, " + \
" zéro pour sortir de ce menu, " + \
"Entrée pour valider la commande entendue"
commun.menu_vocal("aba_fav_ban", "favoris et indésirables", explic)
def favoris_bannis(num4c, operation):
""" gère les favoris et les bannis
qui sont en fait deux listes de mémoire
"""
SEP = ","
def add_ban_fav(num4c, ban_fav):
""" ajoute num4c aux favoris ou bannis
renvoie True si ajout, False sinon """
v_ini = "aba_" + ban_fav + "_" + bbl_actu()
str_fav_actu = infos.ini_get(v_ini, "")
fav_actu = str_fav_actu.strip().split(SEP)
if str_fav_actu == "":
infos.ini_set(v_ini, num4c) # pour éviter erreur aba_favoris_litteaudio=,0150
elif not num4c in fav_actu:
fav_actu.append(num4c)
fav_actu.sort() # https://docs.python.org/3/howto/sorting.html
if len(fav_actu) == 0:
infos.ini_set(v_ini, num4c)
else:
infos.ini_set(v_ini, SEP.join(fav_actu))
else:
msg = "livre déjà présent dans les " + ban_fav
infos.pdrNew(msg)
return False
# 3 lignes communes au if et 1er elif
msg = "livre " + zero_off(num4c) + " ajouté aux " + ban_fav
infos.pdrNew(msg)
return True
def del_ban_fav(num4c, ban_fav):
""" supprime num4c des favoris ou bannis
renvoie True si suppression, False sinon """
v_ini = "aba_" + ban_fav + "_" + bbl_actu()
str_ban_actu = infos.ini_get(v_ini, "")
ban_actu = str_ban_actu.strip().split(",")
if str_ban_actu == "":
pass # on ne peut pas enlever qch de rien
# éviter ce type d'erreur, aba_favoris_litteaudio=,0150
elif num4c in ban_actu:
ban_actu.remove(num4c)
if len(ban_actu) == 0:
infos.ini_set(v_ini, '')
else:
infos.ini_set(v_ini, SEP.join(ban_actu))
msg = "livre " + zero_off(num4c) + " supprimé des " + ban_fav
infos.pdrNew(msg)
return True
else:
msg = "livre déjà absent des " + ban_fav
infos.pdrNew(msg)
return False
if nb_livres_total() == 0:
choisir_autre_biblio_svp()
return 0
if num4c is None:
return False
if operation == "add_fav":
return add_ban_fav(num4c, "favoris")
elif operation == "del_fav":
return del_ban_fav(num4c, "favoris")
elif operation == "add_ban":
return add_ban_fav(num4c, "bannis")
elif operation == "del_ban":
return del_ban_fav(num4c, "bannis")
def aba_nfo1():
""" message sonore : vous écoutez "Des hommes sans femmes", de "Haruki Murakami"
"""
if nb_livres_total() == 0:
choisir_autre_biblio_svp()
return 0
bbll = bbl_langue()
if mpc.is_playing():
if bbll == cfg.LG_FRANCAIS:
masque = "vous écoutez le livre {}, rubrique {}, {}, de {}"
elif bbll == cfg.LG_ANGLAIS:
masque = "you are listening to the book {}, domain {}, {}, the author is {}"
elif bbll == cfg.LG_ALLEMAND:
masque = "Sie hören das Buch {}, im Besitz {}, {}, der Autor ist {}"
else:
if bbll == cfg.LG_FRANCAIS:
masque = "vous écoutez LE livre {}, rubrique {}, {}, de {}"
elif bbll == cfg.LG_ANGLAIS:
masque = "the current bOOk is {}, in the area {}, {}, the author is {}"
elif bbll == cfg.LG_ALLEMAND:
masque = "das aktuelle BUCh ist Nummer {}, im Besitz {}, {}, der Autor ist {}"
annonce = masque.format(zero_off(lv_num4c()), lv_genre(), lv_titre(), lv_auteur())
infos.pdrNew(annonce)
def aba_nfo2():
""" message sonore :
vous êtes à 2 minutes 43
TODO vous êtes à 2 minutes 43, sur la piste 3
"""
if nb_livres_total() == 0:
choisir_autre_biblio_svp()
return 0
duree_conv = duree_conviviale(str(lv_duree()))
bbll = bbl_langue()
if duree_conv == "":
duree2 = ""
else:
if bbll == cfg.LG_FRANCAIS:
duree2 = ", la durée totale est de " + duree_conv
elif bbll == cfg.LG_ANGLAIS:
duree2 = ", total duration is " + duree_conv
elif bbll == cfg.LG_ALLEMAND:
duree2 = ", im Ganzen dauert es " + duree_conv
p = mpc.status_progression()[0]
q = p.split(":")
# numéro de piste
# playlist_position
# playlist_longueur
piste = str(mpc.playlist_position())
piste_total = str(mpc.playlist_longueur())
mpc.ferme_ton_clapet()
if len(q) == 2:
if bbll == cfg.LG_FRANCAIS:
msg = "vous êtes à " + q[0] + " minutes " + q[1] + duree2
elif bbll == cfg.LG_ANGLAIS:
msg = "you are at " + q[0] + " minutes " + q[1] + duree2
elif bbll == cfg.LG_ALLEMAND:
msg = "Sie sind um " + q[0] + " Minuten " + q[1] + duree2
infos.pdrNew(msg)
if bbll == cfg.LG_FRANCAIS:
msg = "chapitre " + piste + " sur " + piste_total
elif bbll == cfg.LG_ANGLAIS:
msg = "chapter " + piste + " from " + piste_total
elif bbll == cfg.LG_ALLEMAND:
msg = "Kapitel " + piste + " von " + piste_total
infos.pdrNew(msg)
def aba_nfo3():
""" annonce le nombre de livres (pour le filtre actuel), le lecteur
"""
if nb_livres_total() == 0:
choisir_autre_biblio_svp()
return 0
nb_livres = str(nb_livres_total())
if lv_poids().strip() == "":
# espace à donner si livre téléchargé,
# ou bien redonner la longueur en temps
espace_mo = ""
else:
espace_mo = "il occupe un espace de " + commun.entier(lv_poids()) + " méga octets"
presents_bannis = "" # TODO
msg = "bibliothèque " + bbl_nom() + ", " + \
"vous ACTION un des " + nb_livres + " livres" + presents_bannis + " , " + \
"ce livre est lu par " + lv_lecteur() + ", " + espace_mo
if mpc.is_playing():
msg = msg.replace("ACTION", "écoutez")
else:
msg = msg.replace("ACTION", "êtes sur")
infos.pdrNew(msg)
def bbl_pos_livres():
""" renvoie le fichier (nom complet) qui mémorise
la position et progression des livres entamés d'une bibliothèque
"""
return "/m/memo/aba/pos_lvr_{}.txt".format(bbl_actu())
def bbl_folder(cle_biblio = None):
""" renvoie le dossier où sont téléchargés les audiolivres
de la bibliothèque online actuelle :
/m/music/aba/audio_cite_classiques
/m/music/aba/litteaudio
"""
if cle_biblio is None:
cle_biblio = bbl_actu()
mpd_dossier = cfg.M_MUSIC + "/aba/" + cle_biblio
return mpd_dossier
def bbl_sub_folder():
""" renvoie le dossier relatif où sont téléchargés les audiolivres
de la bibliothèque online actuelle :
aba/audio_cite_classiques
aba/litteaudio
"""
sub_dossier = "aba/" + bbl_actu()
return sub_dossier
def bbl_langue():
""" renvoie la langue de la bibliothèque en cours
"""
return cfg.BIB_DISPOS[bbl_actu()]["langue"]
def bbl_nom(cle = ''):
""" renvoie le nom de la bibliothèque en cours
"""
if cle == '':
return cfg.BIB_DISPOS[bbl_actu()]["nom"]
else:
return cfg.BIB_DISPOS[cle]["nom"]
def bbl_mpc_update():
""" màj mpd audiobooks biblio actuelle """
cmd_update = "mpc -q update " + "aba/" + bbl_actu()
retour_update = mpc.sub_proc(cmd_update)
def bbl_actu():
""" renvoie la clé de la bibliothèque online actuelle """
la_biblio = infos.ini_get("aba_bbl_actuelle", cfg.DEFAUT_BIBLIO)
alogger("la biblio = " + la_biblio)
alogger("cfg.BIB_DISPOS.keys() = ")
alogger(str(cfg.BIB_DISPOS.keys()))
if la_biblio in cfg.BIB_DISPOS.keys():
return la_biblio
else:
# la clé peut être inexistante, si développeur
# a modifié ou supprimé la clé mémorisée
cles = list(cfg.BIB_DISPOS.keys())
return cles[0]
def build_selektion(list_champs_n = None):
""" construit les tableaux globaux
sel_lvr[] et sel_n2i{} depuis all_lvr[],
sel_lvr[] est une liste d'objets livre
C'est la sélection des livres en cours,
c'est une partie du tableau complet all_lvr[]
sel_n2i{} fait pointer un champ "n" vers l'index de sel_lvr[]
list_champs_n : tableau de champs "n" d'un objet livre,
anciennement appelé num4c
"""
global sel_lvr
global sel_n2i
# raz tableaux globaux ...
sel_lvr = []
sel_n2i = {}
nb_mp3 = 0
nb_zip = 0
nb_undef = 0
if list_champs_n is None:
# parcours des all_lvr[]
for un_livre in all_lvr:
l_type_url = un_livre["type_url"]
if l_type_url == "mp3":
nb_mp3 += 1
elif l_type_url == "zip":
nb_zip += 1
else:
nb_undef += 1
sel_lvr = list(all_lvr) # duplication
indice_ze = 0
for un_livre in sel_lvr:
sel_n2i[ un_livre["n"] ] = indice_ze
indice_ze += 1
infos.log("{} livres, dont mp3/zip/undef {}/{}/{}".format(nb_livres_total(), nb_mp3, nb_zip, nb_undef))
else:
# on construit sel_lvr[] et sel_n2i[]
# depuis all_lvr ET list_champs_n
# ex : pour les livres présents seuls
for un_livre in all_lvr:
if un_livre["n"] in list_champs_n:
sel_lvr.append(un_livre)
indice_ze = 0
for un_livre in sel_lvr:
sel_n2i[ un_livre["n"] ] = indice_ze
indice_ze += 1
infos.m_g("{} livres".format(nb_livres_total()))
def charger_all_lvr(biblio = None):
""" crée le tableau all_lvr[]
d'une bibliothèque depuis le fichier catalog.txt correspondant
(ex : /opt/jk2019/tout/ini/aba/audiocite_classiques/catalog.txt)
all_lvr[] est un tableau d'objets livres
TODO : devra vérifier des champs essentiels :
n= OBLIGATOIRE
y= facultatif
d= facultatif
p= facultatif
l= facultatif
a= OBLIGATOIRE
t= OBLIGATOIRE
u= OBLIGATOIRE, liste d'urls de .mp3 ou .zip,
ou d'une url commençant par http et
ne se finissant pas par zip ou mp3
f= facultatif
x= facultatif
renvoie True si succès, False sinon
"""
if biblio is None:
biblio = bbl_actu()
global all_lvr
all_lvr = []
num_ligne = -1
cata_type = cfg.BIB_DISPOS[biblio]["cata_type"]
if cata_type == "dynamique":
infos.m_g('catalogue dynamic')
return False
catalog = cfg.BIB_DISPOS[biblio]["catalogue"] + "/catalog.txt"
if commun.file_exists(catalog) == False:
infos.g_m("Le fichier {} n'existe pas".format(catalog))
return False
t_auteurs = {}
t_lecteurs = {}
t_genres = {}
t_url = {}
t_duree = {}
t_poids = {}
t_titre = {}
with open(catalog, "r") as f:
for ligne in f:
if ligne.startswith("#"):
continue
elements = ligne.split("|")
num_ligne += 1
url_media = elements[7].split("=", 1)[1].strip()
# on suppose ici que tous les éléments d'une liste d'urls
# sont de la même nature que
if url_media.endswith(".mp3"):
type_url = "mp3"
elif url_media.endswith(".zip"):
type_url = "zip"
elif url_media.startswith("CE_TOME"):
type_url = "CE_TOME_la.com"
elif url_media.startswith("PARTIES"):
type_url = "PARTIES_la.com"
elif url_media == "":
type_url = "url_vide"
print("url_vide : " + \
elements[0].split("=", 1)[1].strip() + ", " + \
elements[8].split("=", 1)[1].strip())
else: # ex : 1347, https://www.audiocite.net/download.php?id=4491 (qui est un mp3 dans ce cas)
type_url = "undef"
num4c = elements[0].split("=", 1)[1].strip()
duree = elements[2].split("=", 1)[1].strip()
lecteur = elements[4].split("=", 1)[1].strip()
auteur = elements[5].split("=", 1)[1].strip()
genre = elements[1].split("=", 1)[1].strip()
url_media1 = url_media.replace(" ", "%20") # ex : 0186
arr_url_media = url_media1.split("+") # nouveauté avec litteratureaudio.com
titre = elements[6].split("=", 1)[1].strip()
poids = elements[3].split("=", 1)[1].strip()
poids = poids.replace(",", ".")
# tableau asso d'un livre
# TODO : charger_element() permettra de charger chaque champ,
# quel que soit l'ordre d'apparition sur la ligne
# nydplatuf sera du passé
# on pourra même ajouter d'autres champs,
# et ne même pas faire figurer les champs optionnels :
# x = "ECOUTER_EXTRAIT"
# b = "publie_le"
t_auteurs[auteur] = 0
t_genres[genre] = 0
t_lecteurs[lecteur] = 0
t_url[url_media[0]] = 0
t_duree[duree] = 0
t_poids[poids] = 0
t_titre[titre] = 0
if len(elements) > 9:
if elements[9].strip() == "":
extrait = ""
else:
xx = elements[9].split("=", 1)
extrait = xx[1].strip()
else:
extrait = ""
un_livre = {
"n": num4c , # numéro à 4 chiffres
"y": genre , # type
"d": duree , # durée
"p": poids , # poids (string : "5.78", "12", ...)
"l": lecteur , # lecteur
"a": auteur , # auteur
"t": titre, # titre
"u": arr_url_media, # url mp3 ou zip
"f": elements[8].split("=", 1)[1].strip(), # url fiche
"x": extrait, # extrait
"type_url": type_url, # type url : mp3, zip
}
all_lvr.append(un_livre)
# tables annexes, à numéroter, puis réindexer catalog.txt
# décommenter les lignes ci-dessous
# pour vérifier un catalogue :
# - auteurs en doublons du genre "Victor Hugo" et "Victor hugo" ou "Victor Hugo"
# - media_url mal formé : ne commence pas par http, par exemple
# ~ creer_nouvelles_tables(
# ~ biblio,
# ~ all_lvr,
# ~ list(t_auteurs.keys()),
# ~ list(t_genres.keys()),
# ~ list(t_lecteurs.keys()),
# ~ list(t_url.keys()),
# ~ list(t_duree.keys()),
# ~ list(t_poids.keys()),
# ~ list(t_titre.keys()),
# ~ )
return True
def choisir_livre():
""" accès direct à un livre depuis son num4c (de 1 à 4 chiffres demandés) """
# à l'avenir, le user pourra utiliser les favoris également, plus pratiques
memo_pos_livre_aba()
msg = "Entrez un numéro de livre " + \
" de 1 à " + str(nb_livres_total()) + ", " + \
" puis appuyez sur Entrée"
infos.pdrNew(msg)
try:
choix_user = input("")
global sel_n2i
n_0000 = zero_on(choix_user)
if n_0000 in sel_n2i.keys():
save_num4c_actuel(n_0000)
lire_livre_actuel("annoncer")
else:
msg = "Vous avez choisi un nombre hors limites. " + \
"Abandon de l'opération."
infos.pdrNew(msg)
except:
msg = "Veuillez choisir un nombre de 1 à " + str(nb_livres_total())
infos.pdrNew(msg)
def devDirSize(start_path):
""" taille totale du dossier en méga octets """
# https://stackoverflow.com/questions/1392413/calculating-a-directorys-size-using-python
import os
total_size = 0
for dirpath, dirnames, filenames in os.walk(start_path):
for f in filenames:
fp = os.path.join(dirpath, f)
# skip if it is symbolic link
if not os.path.islink(fp):
total_size += os.path.getsize(fp)
return total_size / 1000000
def dezipper_del(fichier, dossier, prefixeInfo = ""):
""" va dans le dossier dossier,
dézippe avec 7z le fichier fichier,
supprime le fichier fichier
Renvoie True si tout ok, False si décompression échouée
"""
# dézipper (cf. doc_04)
pfx = prefixeInfo
cmd = "cd " + dossier + "; 7z e -y " + fichier
infos.g_m(pfx + "dézipper {} 1/4. {}".format(fichier, cmd))
unzip_please = mpc.sub_proc(cmd)
# 7z (cf. doc_07)
if unzip_please.find("Everything is Ok"):
infos.g_m(pfx + "dézipper {} 2/4. Everything is Ok".format(fichier))
else:
infos.g_m(pfx + "dézipper {} 2/4. problème dézippage 7z e".format(fichier))
return False
cmd = "cd " + dossier + "; rm " + fichier
infos.g_m(pfx + "dézipper {} 3/4. {}".format(fichier, cmd))
remove_zip = mpc.sub_proc(cmd)
infos.g_m(pfx + "dézipper {} 4/4. {}".format(fichier, remove_zip))
return True
def dl_files_Now(poids, num4c, list_urls, dossier, fichier, extension):
""" téléchargements simple ou multiple
list_urls est une liste à 1 ou plusieurs éléments
seul le téléchargement a lieu ici, zip ou mp3,
le dézippage se fait dans dl_media
"""
if len(list_urls) == 1:
# un seul fichier à télécharger
r = dl_fileNow_one(poids, num4c, list_urls[0], dossier, fichier, extension)
if commun.file_exists("/m/quitter_download"):
return 1
else:
return r
else:
# ATTENTION : le bloc ci-dessous est identique
# au bloc similaire de dl_files_Now
# modifier l'un nécessite de modifier l'autre
suffixe = 1000
for une_url in list_urls:
suffixe += 1
if suffixe == 1001:
fichier = num4c
else:
fichier = num4c + "_" + str(suffixe)[-3:]
infos.log("dl files Now, fichier N° {} = {}".format(suffixe, fichier))
infos.log("dl files Now, url = " + une_url)
retour_un_fichier = dl_fileNow_one(poids, num4c, une_url, dossier, fichier, extension)
if commun.file_exists("/m/quitter_download"):
return False
if retour_un_fichier == False:
infos.m_g("ERR download url " + une_url)
return False
return True
def dl_fileNow_one(poids, num4c, une_url, dossier, fichier, extension):
""" télécharge un fichier """
# Entrée :
# une_url : liste d'urls http à télécharger
# dossier : dossier destination
# num4c : désigne le livre et le radical du fichier à créer
#
# Sortie :
# cette fonction renvoie True si fichier téléchargé, sinon False
# télécharger et mesurer temps d'exécution (pour estimer vitesse)
if poids != "":
taille = poids
if taille == "0":
taille = "1"
dire_poids = " de " + str(int(float(taille))) + " méga octets"
else:
dire_poids = ""
nfo_pfx = "dl fileNow one [" + num4c + "] "
from time import time
download_start = time()
prononcer = ""
# créer dossier destination
# et télécharger avec wget
# entourer l'url de guillemets
# NOK wget -O 1661.mp3 https://archive.org/download/Lenfant_Maupassant/L'enfant.mp3
# OK wget -O 1661.mp3 "https://archive.org/download/Lenfant_Maupassant/L'enfant.mp3"
masque = "mkdir {0}; wget --timeout=20 --tries=2 -O {0}/{1}.{2} \"{3}\" || echo nok"
cmd = masque.format(dossier, fichier, extension, une_url)
infos.g_m(nfo_pfx + cmd)
retour_cmd = mpc.sub_proc(cmd)
# killé par commun.quitter()
infos.g_m("wget killé ou terminé normalement")
if commun.file_exists("/m/quitter_download"):
return False
# TODO : vérifier la présence du fichier après téléchargement
if retour_cmd == "nok":
# le téléchargement a échoué
return False
# infos vitesse
if dire_poids != "":
duree = int(time() - download_start)
taille = float(str(taille))
try:
vitesse = int(taille / duree * 1000)
infos.g_m(nfo_pfx + "1. durée : {} secondes, vitesse : {} Ko/s".format(duree, vitesse))
except ZeroDivisionError:
infos.g_m("division par zéro")
infos.g_m("taille = " + str(taille))
infos.g_m("durée = " + str(duree))
infos.g_m(nfo_pfx + "1. durée : pb de mesure")
# vérification du résultat
cmd = "ls -lh " + dossier + "/" + num4c + "." + extension
infos.g_m(nfo_pfx + "2. vérif : " + cmd)
retour_cmd = mpc.sub_proc(cmd)
infos.g_m(nfo_pfx + "3. résultat : " + retour_cmd)
cmd_ls = "[ -f {}/{}.{} ] && echo dl_ok".format(dossier, fichier, extension)
retour_ls = mpc.sub_proc(cmd_ls)
infos.g_m(nfo_pfx + "4. : " + retour_ls)
if retour_ls == "dl_ok":
return True
else:
return False
def dl_media(bib_index, num4c, poids, duree, list_urls, type_url):
""" se charge de télécharger le mp3, le zip, ou le undef
de le placer où il faut,
et de mettre à jour mpd
"""
# cf. doc_09, pour exemples num4c à tester
# infos user
# ~ msg = "dl media [], ze_idx = " + str(ze_idx) + ", num4c = " + num4c
if len(list_urls) == 1:
msg1 = "un seul fichier"
else:
msg1 = str(len(list_urls)) + " fichiers"
infos.g_m(msg1)
# vaut mieux nettoyer complètement ce dossier
# avant de travailler plus bas
temp_dir_dlMedia = "/m/temp_dl_media"
cmd = "rm -rf " + temp_dir_dlMedia
purger = mpc.sub_proc(cmd)
# 1. télécharger, et dézipper si zip, vers dossier temporaire
if type_url == "mp3":
r = dl_files_Now( poids, num4c, list_urls, temp_dir_dlMedia, num4c, "mp3")
if commun.file_exists("/m/quitter_download"):
return 1
if not r:
infos.m_g("ERR dl media, dl files Now mp3")
elif type_url == "zip":
r = dl_files_Now( poids, num4c, list_urls, temp_dir_dlMedia, num4c, "zip")
if commun.file_exists("/m/quitter_download"):
return 1
if not r:
infos.m_g("ERR dl media, dl files Now zip")
# dézipper un ou plusieurs fichiers
# les noms sont générés de la même façon que dans dl_files_Now()
# numéroter sur 2, ou mieux sur 3 chiffres
# pour éviter un problème d'ordre (le fichier
# 0123_20.mp3 viendra entre le 0123_2.mp3 et le 0123_3.mp3)
# ATTENTION : le bloc ci-dessous est identique
# au bloc similaire de dl_files_Now
# modifier l'un nécessite de modifier l'autre
suffixe = 1000
for une_url in list_urls:
suffixe += 1
if suffixe == 1001:
fichier = num4c
else:
fichier = num4c + "_" + str(suffixe)[-3:]
r2 = dezipper_del(fichier + ".zip", temp_dir_dlMedia)
if r2 == False:
break
elif type_url == "undef":
infos.m_g("undef, wget --spider pour connaître type")
infos.m_g("undef, wget --spider pour connaître type")
# 1. déterminer le type de fichier avec wget --spider
cmd = "wget --tries=5 --spider {} | grep Taille".format(list_urls[0])
infos.g_m("wget SPIDER : wget --tries=5 --spider {} 2>&1 | grep Taille".format(list_urls[0]))
infos.g_m("wget SPIDER : wget --tries=5 --spider {} 2>&1 | grep Taille".format(list_urls[0]))
r_spider = mpc.sub_proc(cmd)
infos.g_m("wget SPIDER : {}".format(r_spider))
infos.g_m("wget SPIDER : {}".format(r_spider))
# 2. lancer dl_media en récursif en forçant mp3 ou zip
if r_spider.find("application/zip") > 0:
infos.g_m("undef, zip")
infos.g_m("undef, zip")
r = dl_media(bib_index, num4c, poids, duree, list_urls, "zip")
elif r_spider.find("audio/mpeg") > 0:
infos.g_m("undef, mp3")
infos.g_m("undef, mp3")
r = dl_media(bib_index, num4c, poids, duree, list_urls, "mp3")
else:
infos.g_m("undef, UNKNOWN")
infos.g_m("undef, UNKNOWN")
# signaler un problème de téléchargement :
# dans fichier .ini, ou mémoire utilisateur
# wget ne trouve pas le fichier dans le temps imparti
return False
return r
if commun.file_exists("/m/quitter_download"):
return 1
# 2. déplacer les mp3 vers dossier num4c
if type_url in [ "mp3", "zip" ]:
dir_dest = "/m/music/aba/" + bib_index + "/" + num4c
if not commun.dir_exists(dir_dest):
r_creer_dossier = commun.make_dir(dir_dest)
if commun.dir_exists(dir_dest):
for audio in [ "mp3", "m4a", "wav" ]:
cmd = "mv {}/*{} {}".format(temp_dir_dlMedia, audio, dir_dest)
infos.log("dl media déplacer : " + cmd)
r_deplacement = mpc.sub_proc(cmd)
else:
infos.m_g("ERR création impossible dossier \"" + dir_dest + "\"")
# TOUDOU_optionnel émettre un bip sonore spécial quand un téléchargement est terminé
# TOUDOU_optionnel émettre un bip sonore encore spécial quand tous les téléchargements sont terminés
return r
def DOKU_enregistrer_dans_tableur_html():
""" enregistre dans un fichier html
le contenu de all_lvr[]
et calculent des stats : total Mo, toital durée,
nb livres, nb auteurs, nb_lecteurs, ...
"""
def create_auteurs(auteurs, quoi):
""" renvoie corps de table des auteurs à deux colonnes
1. auteur
2. nb de livres
"""
# table basique, sans tri
corps_auteurs = ""
cles = list(auteurs.keys())
cles.sort()
n = 0
for i in cles:
# i = nom auteur
# auteurs[i] = nombre de livres
n += 1
# ligne = tr_td([ str(n) + "/" + str(len(cles)), i, auteurs[i] ])
ligne = tr_td([ n, i, auteurs[i] ])
corps_auteurs = corps_auteurs + "\n" + ligne
tbl_auteurs_noms = '<a href="#menu" name="' + quoi + '">' + \
"""<h2 style="text-align: center;">""" + quoi + """</h2></a>
<table class="table_touches">
<caption>""" + quoi + """ classés par ordre alpha</a></caption>
""" + \
entete_table("auteurs") + \
corps_auteurs + \
"""
</table>
"""
# table triée sur nombre de livres décroissants
# https://docs.python.org/3/howto/sorting.html
# cf. Operator Module Functions
from operator import itemgetter, attrgetter
t = []
for i in auteurs.keys():
auteur = i
nb_livres = auteurs[i]
t.append( (auteur, int(nb_livres)) )
s = sorted(t, key=itemgetter(0)) # tri sur auteur (colonne 0)
x = sorted(s, key=itemgetter(1), reverse=True) # tri sur nombre de livres (colonne 1)
sorted(x, key=itemgetter(0)) # tri sur auteur (colonne 0)
# for i in x:
# print("{}, {}".format(i[0], i[1]))
corps_auteurs = ""
n = 0
for i in x:
n += 1
ligne = tr_td([ str(n) + "/" + str(len(x)), i[0], i[1] ])
# ligne = tr_td([ str(n) + "/" + str(len(cles)), i, auteurs[i] ])
corps_auteurs = corps_auteurs + "\n" + ligne
tbl_auteurs_nb_livres = '<a href="#menu" name="' + quoi + '">' + \
"""<h2 style="text-align: center;">""" + quoi + """</h2></a>
<table class="table_touches">
<caption>""" + quoi + """ classés par ordre alpha</a></caption>
""" + \
entete_table(quoi) + \
corps_auteurs + \
"""
</table>
"""
xxx = "<center><table>" + \
"<tr>" + \
"<td>" + tbl_auteurs_noms + "</td>" + \
"<td>" + tbl_auteurs_nb_livres + "</td>" + \
"</tr>" + \
"</table></center>"
return xxx
def create_resume():
""" tableau résumé
"""
table_resume = ""
taille_totale_mo = 0
duree_totale_minutes = 0
genres__ = {} # champ "y"
lecteurs = {} # champ l
auteurs_ = {} # champ a
n = 0
max_poids = 1
min_poids = 1000
max_duree = 1 # minute
min_duree = 10000 # 10000 minutes
nb_cases_poids_vides = 0
nb_cases_durees_vides = 0
nb_poids = 0
nb_duree = 0
for lvr in all_lvr: # init tableaux
genres__[lvr["y"]] = 0
auteurs_[lvr["a"]] = 0
lecteurs[lvr["l"]] = 0
for lvr in all_lvr:
genres__[lvr["y"]] += 1
auteurs_[lvr["a"]] += 1
lecteurs[lvr["l"]] += 1
if lvr["p"].strip() == "":
nb_cases_poids_vides += 1
else:
nb_poids += 1
taille_totale_mo += float(lvr["p"])
if lvr["d"].strip() == "":
nb_cases_durees_vides += 1
else:
nb_duree += 1
duree_totale_minutes += duree_minutes(lvr["d"])
n += 1
# taille
if nb_poids > 0:
# taille totale
# str_taille_totale = \
# '{:,}'.format(int(taille_totale_mo)).replace(",", " ") + \
# " Mo"
str_taille_totale = infos.cvt_taille_mo2go_mo(taille_totale_mo)
# taille moyenne
taille_moyenne_mo = taille_totale_mo / nb_poids
# str_taille_moyenne_mo = \
# '{:,}'.format(int(taille_moyenne_mo)).replace(",", " ") + \
# " Mo"
str_taille_moyenne_mo = infos.cvt_taille_mo2go_mo(taille_moyenne_mo)
else:
str_taille_totale = ""
str_taille_moyenne_mo = "poids NC"
# durée
if nb_duree > 0:
# durée totale
# str_duree_totale = \
# '{:,}'.format(int(duree_totale_minutes)).replace(",", " ") + \
# "<br>" + infos.cvt_duree_minutes2jhm(duree_totale_minutes)
str_duree_totale = infos.cvt_duree_minutes2jhm(duree_totale_minutes)
# durée moyenne
duree_moyenne_minutes = duree_totale_minutes / nb_duree
str_duree_moyenne_minutes = \
'{:,}'.format(int(duree_moyenne_minutes)).replace(",", " ") + \
" mn"
else:
str_duree_totale = ""
str_duree_moyenne_minutes = "durées NC"
remarque_poids = "Poids max : ..., min : ..."
remarque_duree = "Durée max : ..., min : ..."
# table résumé
table_resume = """
<a href="#menu" name="resume"><h2 style="text-align: center;">Résumé</h2></a>
<table class="table_touches">
<caption>Statistik</a></caption>
<tr>
<th>Champ</th>
<th>Valeur</th>
<th>Remarque</th>
</tr>
""" + \
tr_td(["Nombre de livres", '{:,}'.format(n).replace(",", " "), ""]) + \
tr_td(["Taille totale" , str_taille_totale, str(nb_cases_poids_vides) + " case(s) vide(s)"]) + \
tr_td(["Taille moyenne" , str_taille_moyenne_mo, remarque_poids]) + \
tr_td(["Durée totale" , str_duree_totale, str(nb_cases_durees_vides) + " case(s) vide(s)"]) + \
tr_td(["Durée moyenne" , str_duree_moyenne_minutes, remarque_duree]) + \
"""
</table>
"""
return table_resume, auteurs_, genres__, lecteurs
def create_tous_les_livres():
"""
"""
global all_lvr
corps_table = ""
n = 0
for lvr in all_lvr:
ligne_tr = \
"<tr>" + \
td(n) + \
td(lvr["n"]) + \
td(lvr["y"]) + \
td(lvr["d"]) + \
td(lvr["p"]) + \
td(lvr["l"]) + \
td(lvr["a"]) + \
td(lvr["t"]) + \
td(lvr["x"][:40] + "...") + \
"</tr>" + "\n"
corps_table += ligne_tr
n += 1
table_all_lvr = """
<a href="#menu" name="tous_les_livres"><h2 style="text-align: center;">Tous les livres (all_lvr)</h2></a>
<table class="table_touches">
<caption>Documentation http://gangand./pp/projets/xavbox/adm/docs</a></caption>
""" + entete_table("all_lvr") + corps_table + "</table>"
return table_all_lvr
def duree_minutes(d):
t = d.split(":")
return int(t[0]) * 60 + int(t[1])
def entete_table(quoi):
"""
"""
if quoi == "all_lvr":
return """
<tr>
<th>#</th>
<th>num4c</th>
<th>Genre</th>
<th>Durée</th>
<th>Poids</th>
<th>Lecteur</th>
<th>Auteur</th>
<th>Titre</th>
<th>eXtrait</th>
</tr>
"""
elif quoi == "auteurs":
return """
<tr>
<th>#</th>
<th>Auteur</th>
<th>Nb de livres</th>
</tr>
"""
elif quoi == "lecteurs":
return """
<tr>
<th>#</th>
<th>Lecteur</th>
<th>Nb de livres</th>
</tr>
"""
elif quoi == "genres":
return """
<tr>
<th>#</th>
<th>Genre</th>
<th>Nb de livres</th>
</tr>
"""
def footer_html():
"""
"""
return """</body>
</html>
"""
def header_html():
return """<!DOCTYPE html>
<html>
<head>
<title>Module audiolivres</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://gangand.net/ff/formation/notes/style_notes.css">
<link rel="stylesheet" href="http://gangand.net/pp/projets/xavbox/xavbox.css">
</head>
<style>
html {
scroll-behavior: auto;
}
</style>
<body>
"""
def header_page():
return "<center><h1>" + bbl_actu() + "</h1><br></center>"
def menu():
""" menu en te de page
"""
return """<a name="menu">
<table class="table_touches">
<caption>Menu</caption>
<tr>
<th><a href="#resume">Résumé</a></th>
<th><a href="#auteurs">Auteurs</a></th>
<th><a href="#genres">Genres</a></th>
<th><a href="#lecteurs">Lecteurs</a></th>
<th><a href="#tous_les_livres">Tous les livres</a></th>
</tr>
</table>
</a>
"""
def td(s):
return " <td>" + str(s) + "</td>"
def tr_td(arr_td):
""" renvoie une ligne tr de td
"""
ligne = ""
for i in arr_td:
ligne += td(i) + "\n"
return " <tr>" + "\n" + ligne + "</tr>" + "\n"
if commun.reseau("hostname") == cfg.MACHINE_DEV_1:
infos.pdrNew("Fichier tableur créé pour la documentation.")
infos.m_g("*** Lancer dd doku sur bureau => Doku http://gangand.net/pp/projets/xavbox/adm/docs/stats...")
else:
return False
table_tous_les_livres = create_tous_les_livres()
table_resume, auteurs_, genres__, lecteurs = create_resume()
table_auteurs = create_auteurs (auteurs_, "auteurs")
table_genres = create_auteurs (genres__, "genres")
table_lecteurs = create_auteurs (lecteurs, "lecteurs")
corps_html = header_page() + \
menu() + \
table_resume + \
table_auteurs + \
table_genres + \
table_lecteurs + \
table_tous_les_livres
page_entiere = header_html() + corps_html + footer_html()
file_write = "/tmp/proj_xbx_adm_dok_stats_" + bbl_actu() + ".html"
with open(file_write, "w") as f:
f.write(page_entiere)
infos.m_g("===== Fichier tableur créé " + file_write)
def duree_conviviale(duree):
""" renvoie la durée en heures et minutes """
# AVANT
# 1h09 --> 1 heure 9 minutes
# 03 --> 3 minutes
# 2h --> 2 heures
# APRES
# 01:54:23 --> une heure 54 minutes 23
def duree_tester(quantite, unite):
""" chaine à prononcer selon quantité et unité
"""
bbll = bbl_langue()
if int(quantite) == 0:
dire = ""
elif int(quantite) == 1:
if bbll == cfg.LG_FRANCAIS:
article_singulier = "une"
elif bbll == cfg.LG_ANGLAIS:
article_singulier = "one"
elif bbll == cfg.LG_ALLEMAND:
article_singulier = "eine"
dire = "{} {} ".format(article_singulier, unite)
else:
# int(quantite) permet de transformer 02 en 2
# pluriel
if bbll == cfg.LG_FRANCAIS:
marque_pluriel = "s"
elif bbll == cfg.LG_ANGLAIS:
marque_pluriel = "s"
elif bbll == cfg.LG_ALLEMAND:
# eine Stunde --> zwei Stunden
# eine Minute --> zwei Minuten
marque_pluriel = "n"
dire = "{} {}{} ".format(int(quantite), unite, marque_pluriel)
return dire
if duree == "":
return ""
h, m, s = duree.split(":")
dire_s = ""
bbll = bbl_langue()
if bbll == cfg.LG_FRANCAIS:
dire_h = duree_tester(h, "heure")
dire_m = duree_tester(m, "minute")
elif bbll == cfg.LG_ANGLAIS:
dire_h = duree_tester(h, "hour")
dire_m = duree_tester(m, "minute")
elif bbll == cfg.LG_ALLEMAND:
dire_h = duree_tester(h, "Stunde")
dire_m = duree_tester(m, "Minute")
# une heure trois minutes
return dire_h + dire_m + dire_s
def enqueue_download(bbl_key, lvr, silent = ""):
""" ajoute le téléchargement à la file d'attente,
en créant le fichier témoin,
que le thread Enqueue traitera
ajouter le livre actuel, de la bibliothèque actuelle
au thread thread_download
ex: /m/aba_dl_bg_bib_audio_cite__0152.txt
pour télécharger le num4c 0152 de la biblio audio_cite
audio_cite est la clé de BIB_DISPOS dans cfg.py
"""
# dl_bg = download background (téléchargement en arrière-plan)
espace_ok, s_espace = commun.espace("suffisant")
if espace_ok == True:
masque = "/m/aba_dl_bg_{}__{}.txt"
file_download = masque.format(bbl_key, lvr["n"])
with open(file_download, "w") as fd:
# contenu du fichier témoin sans importance pour l'instant
# bib_librivoxfr|0152|35|1h18|http://...zip+http://...zip
contenu = "{}|{}|{}|{}|{}|{}".format(bbl_key, lvr["n"], lvr["type_url"], lvr["p"], lvr["d"], "+".join(lvr["u"]))
fd.write(contenu)
if silent == "":
if espace_ok == True:
msg = "enqueue " + file_download + " créé pour " + bbl_key
infos.m_g(msg)
msg = "espAce libre, " + \
str(commun.espace("libre")) + ", " + \
"téléchargement programmé"
infos.pdrNew(msg) # "il reste 3200 méga octets sur la clé usb"
else:
msg = "espace libre trop faible, " + str(commun.espace("libre")) + \
"téléchargement annulé"
infos.pdrNew(msg)
else:
if espace_ok == True:
msg = "enqueue " + file_download + ", " + \
lvr["p"] + ", " + \
lvr["t"] + ", " + \
" créé pour " + bbl_key
else:
msg = "enqueue annulé, espace trop faible"
infos.m_g(msg)
return msg
from threading import Thread
class Download(Thread):
""" Thread chargé de télécharger en arrière-plan """
# thread à lancer dès le démarrage du module aba
def __init__(self):
Thread.__init__(self)
# ~ print("Lancement thread Download ...")
def run(self):
"""Code à exécuter pendant l'exécution du thread."""
# pause pour laisser temps chargement de sel_lvr[]
commun.faire_pause(10)
while True:
commun.faire_pause(4)
cmd = "ls -1 /m/aba_dl_bg_*.txt 2> /dev/null"
str_dir_command = mpc.sub_proc(cmd)
# on quitte le thread et l'appli
if commun.file_exists("/m/quitter_download"):
infos.g_m("fin thread Download")
cmd = "rm /m/quitter_download"
mpc.sub_proc(cmd)
cmd = "rm /m/aba_dl_bg*txt"
mpc.sub_proc(cmd)
break
# si fichiers témoin présents
# un fichier témoin est du type :
# /m/aba_dl_bg_audio_cite_classiques__2254.txt
# et contient une ligne comme ci-dessous :
# audio_cite_classiques|2254|mp3|15.0|0:15:00|http://www.archive.org/download/LhommeVoil/Lhomme_voil_Marcel_-_schwob.mp3
if len(str_dir_command) > 10:
# TOUDOU_optionnel afficher les téléchargements en attente pour le DEV
list_downloads = str_dir_command.split("\n")
n_dl_bg = 0
# afficher tous les .txt présents
for dl_bg in list_downloads:
n_dl_bg += 1
masque = "DEBUG dl en attente, {} sur {} {}"
msg = masque.format(n_dl_bg, len(list_downloads), dl_bg)
infos.log(msg)
# nettoyer liste_dl pour ne conserver que
# les lignes qui commencent par "aba_dl_bg_"
num4c_dl = ""
for temoin in list_downloads:
if temoin.startswith("/m/aba_dl_bg_"):
# lire le contenu du fichier
with open(temoin, "r") as file_data:
data_ligne = file_data.readline().strip()
data_livre = data_ligne.split("|")
# bib_librivoxfr|0152|mp3|35|1h18|http://...zip+http://...zip
bib_index = data_livre[0] # bib_audiocite
num4c_dl = data_livre[1] # 0152
type_url = data_livre[2]
poids = data_livre[3]
duree = data_livre[4]
liste_d_urls = data_livre[5].split("+")
# on ne télécharge que le premier de la liste
# avec dl_media, on est en synchrone
b_espace, s_espace = commun.espace("suffisant")
if b_espace == True:
mask = "téléch. {} n:{}, {} Mo, {}, type {}"
msg = mask.format(bib_index, num4c_dl, poids, duree, type_url)
infos.m_g(msg)
dl_media(bib_index, num4c_dl, poids, duree, liste_d_urls, type_url)
# contrôler encore ici si téléchargement
# a bien eu lieu
# (pb d'espace, connexion interrompu, ...)
# la tâche doit se finir pour que les lignes
# ci-dessous soient exécutées
msg = "espace libre, " + \
str(commun.espace("libre")) + ", " + \
"après téléchargement arrière-plan fini " + \
str(temoin)
infos.m_g(msg)
# on émet un son quand un téléchargement est terminé
commun.sound_tache_terminee()
# on met à jour mpd pour la biblio actuelle
bbl_mpc_update()
else:
msg = "le livre ne peut pas être " + \
"téléchargé faute de place"
# car s_espace =
# "espace restant inférieur à 2000 méga octets"
infos.pdrNew(msg)
# infos.m_g("Download, " + message_espace_insuffisant(s_espace)[0])
# on supprime le fichier témoin
cmd = "rm {}".format(temoin)
mpc.sub_proc(cmd)
# on ne télécharge que le premier de la liste
break
DEV_ne_pas_lancer_thread = False
if DEV_ne_pas_lancer_thread == False:
# démarrer le thread avec le module aba ?
thread_queue = Download()
# Lancement des threads
thread_queue.start()
def entree_lire():
""" lit le livre actu si présent,
le télécharge sinon
séquence : touche Entrée une fois
"""
mpc.ferme_ton_clapet()
if infos.ini_get("mode_consultation", "consulter") == "consulter":
if mpc.is_playing():
msg = "Vous êtes déjà en train de lire le livre, " + \
"utilisez les touches 1, 2, 3 pour naviguer"
infos.m_g(msg)
else:
lire_livre_actuel("lire")
else:
infos.m_g("En mode lire / consultation, touche Entrée pressée => RIEN")
def espace_suffisant_aba():
""" vérifie dès démarrage du module aba
si on pourra télécharger des livres """
b_espace, s_espace = commun.espace("suffisant")
if b_espace == False:
infos.pdrNew(str(s_espace));
msg = "L'espace est insuffisant actuellement " + \
"pour télécharger de nouveaux livres, " + \
"mais vous pouvez toujours écouter les présents."
infos.pdrNew(msg)
# mega_octets_biblio = commun.du(bbl_folder())
# bbll = bbl_langue()
# if bbll == cfg.LG_FRANCAIS:
# voc_dl1 = "les livres téléchargés de cette bibliothèque occupent {} méga octets ".format(mega_octets_biblio)
# voc_dl2 = "téléchargement impossible par manque de place, " + \
# "veuillez supprimer des livres, " + \
# "ou éteindre la machine et insérer " + \
# "une clé avec de l'espace libre "
# elif bbll == cfg.LG_ANGLAIS:
# voc_dl1 = "download of absent books will not happen because space is missing "
# voc_dl2 = "download of absent books will not happen because space is missing "
# elif bbll == cfg.LG_ALLEMAND:
# voc_dl1 = "Herunterladung unmöglich, Raum zu kurz "
# voc_dl2 = "Herunterladung unmöglich, Raum zu kurz "
# infos.pdrNew(voc_dl1, voc_dl2)
def supprimer_livres():
""" supprimes les livres présents de la bibliothèque actuelle
"""
if nb_livres_total() == 0:
choisir_autre_biblio_svp()
return 0
mpc.stop()
mpc.clear()
mpc.ferme_ton_clapet()
space_left_avant = commun.espace("libre")
bn = bbl_nom()
nb_prez = nb_livres_prezents()
space = commun.du(bbl_folder())
mask = "suppression des {} livres présents dans la bibliothèque {}"
infos.pdrNew(mask.format(nb_prez, bn))
dossier = bbl_folder()
cmd = "rm -rf " + dossier
mpc.sub_proc(cmd)
space_left_apres = commun.espace("libre")
mask = "espace avant, {}, espace après suppression, {}"
infos.pdrNew(mask.format(space_left_avant, space_left_apres))
mask = "gain obtenu : {} méga octets"
infos.pdrNew(mask.format(space))
cmd = "mkdir " + dossier
mpc.sub_proc(cmd)
slct_tout()
def supprimer_livre():
""" supprime le livre présent actuel
"""
if nb_livres_total() == 0:
choisir_autre_biblio_svp()
return 0
space_left_avant = commun.espace("libre")
mpc.stop()
mpc.clear()
mpc.ferme_ton_clapet()
# - supprimer de la liste sel_lvr[]
del_num4c = lv_num4c()
del_titre = lv_titre()
infos.g_m("Nb livres AVANT : {}".format(nb_livres_total()))
ze_idx = ze__indice_actuel()
# supprimer dossier physique
dossier_du_livre = bbl_folder() + "/" + del_num4c
cmd = "rm -rf " + dossier_du_livre
infos.g_m(cmd)
mpc.sub_proc(cmd)
# reconstruire sel_lvr et sel_n2i
global sel_n2i
global sel_lvr
ze2 = []
sel_n2i = {}
idx = 0
nb_append = 0
for i in sel_lvr:
if idx != ze_idx:
ze2.append(i)
sel_n2i[i["n"]] = nb_append
nb_append += 1
idx += 1
# print("==================== ze_idx = " + str(ze_idx))
# print("==================== sel_n2i keys = " + str(sel_n2i.keys()))
# print("==================== sel_n2i values = " + str(sel_n2i.values()))
sel_lvr = []
if nb_append == 0:
# on a supprimé tous les livres
infos.pdrNew("vous avez supprimé le dernier livre de la sélection")
commun.faire_pause(3)
space_left_apres = commun.espace("libre")
masque = "espace avant, {}, espace après suppression, {}"
infos.pdrNew(masque.format(space_left_avant, space_left_apres))
slct_tout()
else:
idx = 0
for i in ze2:
sel_lvr.append(i)
infos.g_m("Nb livres APRES : {}".format(nb_livres_total()))
masque = "suppression du livre {}, de la bibliothèque {}, " + \
"il vous reste {} livres en sélection"
infos.pdrNew(masque.format(del_titre, bbl_nom(), nb_livres_total()))
space_left_apres = commun.espace("libre")
masque = "espace avant, {}, espace après suppression, {}"
infos.pdrNew(masque.format(space_left_avant, space_left_apres))
msg = "Appuyer sur 1, 2 ou 3 pour naviguer dans les livres"
infos.pdrNew(msg)
def choisir_autre_biblio_svp():
msg = "Aucun livre disponible, veuillez choisir " + \
"une autre bibliothèque avec la touche 11"
infos.pdrNew(msg)
def livre_hasard(quiet = ""):
""" livre au petit bonheur la chance dans sel_lvr[] """
if nb_livres_total() == 0:
choisir_autre_biblio_svp()
return 0
memo_pos_livre_aba()
mpc.ferme_ton_clapet()
import random
num_rand = random.randint(0, nb_livres_total() - 1)
num4c_ze_actu = lv_num4c(num_rand)
save_num4c_actuel(num4c_ze_actu)
msg34 = "un livre au hasard parmi " + str(nb_livres_total())
arr_msg = [ "", # ne rien dire au niveau 0
"hasard",
msg34,
msg34
]
infos.pdrNew(arr_msg)
if infos.niveau_aide_voc() in (2, 3):
commun.faire_pause(2, False)
infos.g_m("lire_livre_actuel")
lire_livre_actuel("annoncer")
def offline_download():
""" appareil offline, télécharger tous les livres de la bibliothèques en cours
en vue de créer un appareil autonome qui aura à disposition
tous les livres du catalogue sur place
On télécharge hors clé usb sur ip12, car il y a 22 Go d'espace
libre sur / le 23 juin 2020.
touche OFFLINE
"""
# infos.m_g("
# télécharger
commun.tts_niveau_aide(0)
# infos.m_g("Début du téléchargement de quelques audiolivre hors ligne")
bbl_audio_cite_classiques()
offline_sr1("audio_cite_classiques", 15)
bbl_litterature()
offline_sr1("litteaudio", 5)
commun.tts_niveau_aide(3)
# infos.m_g("Fin du téléchargement de quelques audiolivre hors ligne")
def offline_sr1(fichier_faits, nb_downloads_max):
""" télécharger nb_downloads_max livres
de la biblio en cours
"""
def dir_classer_define(lvr_n):
""" renvoie sous-dossier de rangement
pour le lvr["n"] demandé
"""
# ex : lvr["n"] = 0158 => dir_classer = 0101-0200
# : lvr["n"] = 1502 => dir_classer = 1501-1600
# : lvr["n"] = 0100 => dir_classer = 0101-0200 ERREUR
# : lvr["n"] = 0100 => dir_classer = 0001-0100 OK
# A B C D
# 0001 à 0100 => 0001-0100
A = lvr_n[:2]
B = lvr_n[-2:]
if B == "00": # lvr_n = 0100
C1 = str(int(A) + 100 - 1)[-2:] # 00
D1 = A # 01
else: # lvr_n = 0099
C1 = A # 00
D1 = "0" + str(int(A) + 1)[-2:] # 001
D1 = D1[-2:] # 01
sous_dir = C1 + "01" + "-" + D1 + "00"
return sous_dir
def batch():
""" crée le fichier offline_<BIBLIO>.sh
"""
output = "/m/offline_" + bbl_actu() + ".sh"
global all_lvr
n = 0
f = open(output, "w")
ligne = "# bibliothèque " + bbl_actu()
print(ligne, file=f)
print("", file=f)
ligne = "[ -d /home/pi/xavbox_offline ] || echo Dossier /home/pi/xavbox_offline absent"
print(ligne, file=f)
ligne = "[ -d /home/pi/xavbox_offline ] || exit"
print(ligne, file=f)
ligne = "cd /home/pi/xavbox_offline"
print(ligne, file=f)
ligne = "if [ -f livres_faits.txt ]; then "
print(ligne, file=f)
ligne = " echo livres_faits.txt présent"
print(ligne, file=f)
ligne = "else"
print(ligne, file=f)
ligne = " echo livres_faits.txt absent"
print(ligne, file=f)
ligne = " exit"
print(ligne, file=f)
ligne = "fi"
print(ligne, file=f)
for lvr in all_lvr:
ligne = "# livre " + lvr["n"]
print(ligne, file=f)
dir_classer = dir_classer_define(lvr["n"])
partial_path = bbl_actu() + "/" + dir_classer + "/" + lvr["n"]
full_path = "/home/pi/xavbox_offline/" + partial_path
ligne = "cd /home/pi/xavbox_offline"
print(ligne, file=f)
print("", file=f)
ligne = "[ -f " + bbl_actu() + ".stop ] && echo Dossier biblio_stop"
print(ligne, file=f)
ligne = "[ -f " + bbl_actu() + ".stop ] && exit"
print(ligne, file=f)
print("", file=f)
ligne = "if grep " + partial_path + " livres_faits.txt ; then "
print(ligne, file=f)
ligne = " echo PRESENT " + full_path
print(ligne, file=f)
print("else", file=f)
ligne = " echo dl " + full_path
print(ligne, file=f)
ligne = " mkdir -p " + full_path
print(ligne, file=f)
ligne = " cd " + full_path
print(ligne, file=f)
pfx = 1000
for u in lvr["u"]: # plusieurs fichiers pour ce livre
pfx += 1
dest = lvr["n"] + "_" + str(pfx)[1:] + "." + lvr["type_url"]
ligne = " wget -O " + dest + " \"" + u + "\""
print(ligne, file=f)
if lvr["type_url"] == "zip":
ligne = " 7z e -y " + dest
print(ligne, file=f)
ligne = " rm " + dest
print(ligne, file=f)
print("fi", file=f)
print("[ $(df . | tail -1 | awk '{print $4}') -lt 5000000 ] && echo 5 Go restants, FIN", file=f)
print("[ $(df . | tail -1 | awk '{print $4}') -lt 5000000 ] && exit", file=f)
print("", file=f)
infos.m_g("Fichier {} crée".format(output))
def ancienne_fonction():
""" télécharge un par un les livres non présents
dans le fichier faits.txt
PAS AU POINT
"""
global all_lvr
n = 0
taille_totale = 0
nb_passer = 0
with open("/home/pi/xavbox_offline/livres_faits.txt", "r") as f:
ff = f.readlines()
faits = []
for i in ff:
faits.append(i.strip())
for lvr in all_lvr:
if bbl_actu() + "/" + lvr["n"] in faits:
continue
dir_classer = dir_classer_define(lvr["n"])
full_path = "/home/pi/xavbox_offline/" + bbl_actu() + "/" + dir_classer + lvr["n"]
if commun.dir_exists(full_path):
# infos.m_g("livre fait " + full_path + ", on passe")
pass
else:
commun.make_dir(full_path)
n += 1
# wget_spider_taille indique la taille d'un fichier
# sans besoin de le télécharger
pfx = 0
for u in lvr["u"]: # plusieurs fichiers pour ce livre
pfx += 1
if lvr["p"] == "":
poids = wget_spider_taille(u)
# poids = '{:,} octets'.format(poids)
else:
poids = lvr["p"]
dest = lvr["n"] + "_" + str(pfx) + "." + lvr["type_url"]
cmd = "cd " + full_path + ";" + "wget -O " + dest + " " + u
msg = bbl_actu() + " multi " + str(n) + "." + str(pfx) + " , " + \
lvr["n"] + " , " + \
lvr["type_url"] + ", " + \
str(poids) + " Mo, " + \
lvr["t"]
infos.m_g(msg)
msg_wget = "wget -O " + dest + " " + u
infos.m_g(msg_wget)
r = mpc.sub_proc(cmd)
dezipper_del(dest, full_path)
taille = commun.du(full_path)
taille_totale += taille
tf1 = '{:,}'.format(taille).replace(",", " ")
tf2 = '{:,}'.format(taille_totale).replace(",", " ")
infos.m_g("--> {} Mo, total {} Mo".format(tf1, tf2))
infos.m_g("")
if n > nb_downloads_max:
break
mask = "dl offline_download() {} terminés dans la biblio {}"
infos.m_g(mask.format(n, "/home/pi/xavbox_offline/" + bbl_actu()))
batch()
def present_hasard_biblios():
""" écouter un livre présent au hasard
en recherchant dans toutes les bibliothèques
touches "1111"
"""
def taille_livre_present():
""" renvoie espace en Mo du livre présent
attention :
opération différente selon que c'est anarchie
ou online
"""
def phb_chercher(prononcer = True):
""" rechercher tous les livres présents
dans les bibliothèques statiques
un livre présent est symbolisé par la présence d'un sous-dossier
dans le dossier de la bibliothèque
doc : gangand.net/pp/projets/xavbox/adm/adm_aba.php#changement
"""
cles = list(cfg.BIB_DISPOS.keys())
cles.sort()
n = 0
infos.m_g("Bibliothèques, livres présents")
total_Mo = 0
nb_total_presents = 0
nb_biblios_presents = 0
choix_hasard = []
nb_livr_prezents_partout = 0
for cle_biblio in cles:
n += 1
bib1 = cfg.BIB_DISPOS[cle_biblio]
cata_type = bib1["cata_type"]
catalogue = bib1["catalogue"]
nom = bib1["nom"]
msg = "vide"
if cata_type == "statique":
# cata_type = "tous":
# if cata_type == "tous":
dir_biblio = cfg.ABA_DIR + "/" + cle_biblio # /m/music/aba/audio_cite_classiques
if commun.dir_exists(dir_biblio):
nb_dossiers = nb_livres_prezents(cle_biblio)
nb_total_presents += nb_dossiers
if nb_dossiers > 0:
nb_biblios_presents += 1
t1 = commun.du(dir_biblio)
taille = " (" + str(t1) + " Mo)"
total_Mo += t1
sous_dossiers = commun.folders_simple(dir_biblio)
for full_path in sous_dossiers:
if commun.du(full_path) > 0:
# on ne vérifie que la taille,
# pas la nature des fichiers
choix_hasard.append((cle_biblio, full_path))
nb_livr_prezents_partout += 1
else:
taille = ""
msg = str(nb_dossiers).rjust(2) + " présents" + taille
else:
msg = "dynamique"
infos.g_m(str(n).rjust(2) + ". " + nom.ljust(20) + " : " + msg)
if nb_livr_prezents_partout > 0:
infos.g_m("Taille totale : " + str(total_Mo) + " Mo")
mask = "{} livres présents dans {} bibliothèques, qui occupent {} méga octets"
msg = mask.format(nb_total_presents, nb_biblios_presents, total_Mo)
if prononcer:
infos.pdrNew([ "", msg ])
else:
infos.m_g(msg)
return nb_livr_prezents_partout, choix_hasard
def phb_5_au_hasard(nb_livr_prezents_partout, choix_hasard, prononcer = True):
""" lister chaque biblio + livres présents
"""
if nb_livr_prezents_partout > 0:
import random
max_rand = len(choix_hasard) - 1
num_rand = random.randint(0, max_rand)
try:
cle_biblio, full_path = choix_hasard[ num_rand ]
except IndexError:
infos.m_g("index random = " + str(num_rand))
infos.m_g("longueur choix_hasard = " + str(len(choix_hasard)))
mask = "biblio {}, dossier {}"
msg = mask.format(cle_biblio, full_path)
infos.g_m(msg)
splitter = full_path.split("/")
champ_n = splitter[ len(splitter) - 1 ] # programmer commun.basename(path)
mask = "Lecture du livre au hasard {}, de la bibliothèque {}"
msg = mask.format(champ_n, bbl_nom(cle_biblio) )
if prononcer:
infos.pdrNew(msg)
else:
infos.g_m(msg)
return cle_biblio, champ_n
# parcourir toutes les bibliothèques au hasard
# voir s'il y a des livres présents
mpc.ferme_ton_clapet()
msg = "écoute d'un livre présent, choisi au hasard " + \
"des bibliothèques"
infos.pdrNew(["", msg])
mpc.clear()
Prononcer_True = True
nb_livr_prezents_partout, choix_hasard = phb_chercher(Prononcer_True)
if nb_livr_prezents_partout == 0:
msg = "Aucun livre n'est présent " + \
"dans les bibliothèques, " + bbl_nom() + ", " + \
"vous pouvez utiliser les touches 666 ou 6666 " + \
"pour télécharger des livres au hasard."
infos.pdrNew(msg)
return 0
cle_biblio, champ_n = phb_5_au_hasard(
nb_livr_prezents_partout, choix_hasard, Prononcer_True)
# lancer la lecture après mémorisation livre en cours
if nb_livres_total() > 0:
memo_pos_livre_aba()
save_num4c_actuel(lv_num4c())
infos.ini_set("aba_bbl_actuelle", cle_biblio)
save_num4c_actuel(champ_n)
charger_all_lvr()
build_selektion()
if infos.niveau_aide_voc() > 1:
infos.pdrNew("Appuyez sur Entrée pour écouter le livre")
a = input()
lire_livre_actuel("lire")
# touches "1111"
def rand10lvr():
""" télécharge 10 nouveaux livres au hasard
en arrière-plan
pour lecture ultérieure
touches "666"
"""
if nb_livres_total() == 0:
choisir_autre_biblio_svp()
return 0
NB_LIVRES_DL_HASARD = 10
if 0 < nb_livres_total() < NB_LIVRES_DL_HASARD:
nb_downloads_random = nb_livres_total()
else:
nb_downloads_random = NB_LIVRES_DL_HASARD
memo_pos_livre_aba()
mpc.ferme_ton_clapet()
# sortir si espace insuffisant
espace_ok, s_espace = commun.espace("suffisant")
if not espace_ok:
infos.pdrNew(message_espace_insuffisant(s_espace))
# msg = "espace restant insuffisant pour télécharger, " + \
# "veuillez libérer d'abord de l'espace."
# infos.pdrNew(msg)
# msg = "Pour cela, placez-vous sur un livre présent, " + \
# "puis effacez-le avec 987, " + \
# "ou bien 11 pour ouvrir le menu vocal, puis la touche 9, " + \
# "pour supprimer plusieurs livres d'un coup."
# infos.pdrNew(msg)
return 0
space_left = commun.espace("libre")
msg = "eSpace libre, " + str(space_left) + ", " + \
"tentative de téléchargement de 10 livres au hasard " + \
"dans la sélection"
infos.pdrNew(msg)
commun.faire_pause(4)
# memo_lvr_actu = lv_livre_actuel() # définit le livre actu
# contrôler le nombre de livres au total d'abord
nb_livres_finaux = 0
import random
# TODO : s'assurer que le nombre au hasard n'a pas encore été choisi
for i in range(nb_downloads_random):
num_rand = random.randint(0, nb_livres_total() - 1)
infos.m_g("***** num_rand =" + str(num_rand) + " *****")
num4c_ze_actu = lv_num4c(num_rand)
save_num4c_actuel(num4c_ze_actu)
if media_present(lv_livre_actuel()) == "absent_usb":
lvr = lv_livre_actuel()
enqueue_download(bbl_actu(), lvr, "rand10lvr")
nb_livres_finaux += 1
else:
msg = str(num4c_ze_actu) + \
" présent, on en choisit un autre"
infos.g_m(msg)
infos.pdrNew(str(nb_livres_finaux) + " livres sont en cours " + \
"de téléchargement")
def rand10lvr_biblios():
""" télécharger 10 livres au hasard
de toutes les bibliothèques
touches "6666"
"""
# parcourir toutes les bibliothèques au hasard
# voir s'il y a des livres présents
msg = "télécharger 10 livres au hasard " + \
"de toutes les bibliothèques"
infos.pdrNew(msg + " en cours")
# prendre 10 fois une bibliothèque au hasard
# programmer avec enqueue le téléchargement
def rand11lvr_biblios():
""" télécharger 11 livres au hasard
de toutes les bibliothèques
touches "6666"
"""
# parcourir toutes les bibliothèques au hasard
# voir s'il y a des livres présents
mpc.ferme_ton_clapet()
mpc.clear()
msg = "Téléchargement de 11 livres au hasard " + \
"de toutes les bibliothèques"
infos.pdrNew(msg + " en cours")
# prendre 11 fois une bibliothèque au hasard
# programmer avec enqueue le téléchargement
# sortir si espace insuffisant
espace_ok, s_espace = commun.espace("suffisant")
if not espace_ok:
infos.pdrNew(message_espace_insuffisant(s_espace))
return 0
nb_dl_books_partout = 11
cles = list(cfg.BIB_DISPOS.keys())
cles.sort()
infos.m_g("Bibliothèques, {} livres au hasard partout".format(nb_dl_books_partout))
import random
nb_livres_programmes = 0
global all_lvr
while True:
if nb_livres_programmes == nb_dl_books_partout:
break
num_rand = random.randint(0, len(cles) - 1 )
cle_biblio = cles[num_rand]
bib1 = cfg.BIB_DISPOS[cle_biblio]
cata_type = bib1["cata_type"]
if cata_type == "statique":
infos.ini_set("aba_bbl_actuelle", cle_biblio)
if charger_all_lvr():
# choisir un livre au hasard dans la bibliothèque activée
nb_livres_programmes += 1
num_rand_2 = random.randint(0, len(all_lvr) - 1 )
lvr_hasard = all_lvr[ num_rand_2 ]
champ_n_hasard = lvr_hasard[ "n" ]
titre = lvr_hasard[ "t" ]
infos.m_g("nb_livres_programmes = " + \
str(nb_livres_programmes) + \
", " + champ_n_hasard + \
", " + titre)
enqueue_download(cle_biblio, lvr_hasard, "silence")
def livre_prec():
""" aller au livre suivant """
if nb_livres_total() == 0:
choisir_autre_biblio_svp()
return 0
memo_pos_livre_aba()
num_livre_actuel = ze__indice_actuel() - 1
if num_livre_actuel == -1:
num_livre_actuel = nb_livres_total() - 1
save_num4c_actuel(lv_num4c(num_livre_actuel))
mpc.ferme_ton_clapet()
lire_livre_actuel("annoncer")
def livre_suiv():
""" aller au livre précédent """
if nb_livres_total() == 0:
choisir_autre_biblio_svp()
return 0
memo_pos_livre_aba()
num_livre_actuel = ze__indice_actuel() + 1
if num_livre_actuel > nb_livres_total() - 1:
num_livre_actuel = 0
save_num4c_actuel(lv_num4c(num_livre_actuel))
mpc.ferme_ton_clapet()
lire_livre_actuel("annoncer")
def lire_livre_actuel(action, direkt = ''):
""" lit le livre de numéro ze_num_actuel(),
l'annonce, ou le télécharge
quand on change de bibliothèque, le dernier livre lu
dans la bibliothèque est retrouvé grâce à la valeur correspondante
du fichier py_user.ini, exemples :
num4c_litteaudio=0444|2020-02-25 17:00:10
num4c_librivoxen=0053|2020-02-25 19:54:42
num4c_cle_usb_anarchie=0012|2020-02-25 21:48:06
"""
def final_annoncer(final_seek_read):
""" renvoie une chaîne du type :
- "livre présent, ..."
- "livre à télécharger, ..."
"""
# annoncer seulement le livre (cf. doc_05)
infos.log(" --> TIP : Appuyer sur Entrée pour (re)lancer (débuter/terminer) la lecture de ce livre")
infos.log(" --> seek_read = " + seek_read)
# on prononce livre ou audiolivre si média présent sur clé usb,
# référence s'il est absent
msg1 = final_resume_livre()
bbll = bbl_langue()
if bbll == cfg.LG_FRANCAIS:
msg_livre_present = "livre présent "
msg_livre_telech = "livre à télécharger "
msg_final_appui_sur_entree_download = ", appuyez sur Entrée pour lancer le téléchargement"
msg_final_appui_sur_entree_lire = ", appuyez sur Entrée pour lancer la lecture"
elif bbll == cfg.LG_ANGLAIS:
msg_livre_present = "book present "
msg_livre_telech = "book to download "
msg_final_appui_sur_entree_download = ", press enter to start the download"
msg_final_appui_sur_entree_lire = ", press Enter to start reading"
elif bbll == cfg.LG_ALLEMAND:
msg_livre_present = "anwesendes Buch "
msg_livre_telech = "Buch zu herunterladen "
msg_final_appui_sur_entree_download = ", drücken Sie Enter zur Herunterladung"
msg_final_appui_sur_entree_lire = ", drücken Sie Enter zum Lesen"
# bn = bbl_nom() + ", "
bn = "" # on raccourcit le message vocal
if media_present(lv_livre_actuel()) == "présent_usb":
return [
msg_livre_present + msg1[0],
msg_livre_present + msg1[1],
bn + msg_livre_present + msg1[2] + msg_final_appui_sur_entree_lire,
bn + msg_livre_present + msg1[3] + msg_final_appui_sur_entree_lire
]
elif bbl_actu() == cfg.bbl_CLE_USB_ANARCHIE:
msg_livre_present = " livre sur clé "
return [
msg_livre_present + msg1[0],
msg_livre_present + msg1[1],
bn + msg_livre_present + msg1[2] + msg_final_appui_sur_entree_lire,
bn + msg_livre_present + msg1[3] + msg_final_appui_sur_entree_lire
]
else:
return [
msg_livre_telech + msg1[0],
msg_livre_telech + msg1[1],
bn + msg_livre_telech + msg1[2] + msg_final_appui_sur_entree_download,
bn + msg_livre_telech + msg1[3] + msg_final_appui_sur_entree_download
]
def final_lire(lvr, piste, seek):
""" lance le livre en cours, ou son téléchargement
renvoie une chaîne du type :
- "lecture du livre, ..."
- "téléchargement programmé ..."
"""
# infos
arr_resume_livre = final_resume_livre()
# "777, 51 minutes, Dix années d'exil, de staël De"
bbll = bbl_langue()
if ( (bbl_actu() == cfg.bbl_CLE_USB_ANARCHIE) or
(media_present(lvr) == "présent_usb") ):
# clé usb ou media présent : on lit
infos.m_g("final_lire, média présent pour " + lvr["n"])
arr_lecture = lancer_lecture(lvr, piste, seek)
# au lieu de mémoriser le livre quand on quitte le module,
# on le mémorise dès que la lecture commence
save_num4c_actuel(lvr["n"])
if bbll == cfg.LG_FRANCAIS:
voc_lecture1 = "lecture "
voc_lecture2 = "lecture du livre "
elif bbll == cfg.LG_ANGLAIS:
voc_lecture1 = "book reading "
voc_lecture2 = "book is being read "
elif bbll == cfg.LG_ALLEMAND:
voc_lecture1 = "Buchlesung "
voc_lecture2 = "wir lesen das Buch "
arr_prononcer3 = [
"",
voc_lecture1 + ", " + arr_resume_livre[1] + ",, " + arr_lecture[1],
voc_lecture2 + ", " + arr_resume_livre[2] + ",, " + arr_lecture[2],
voc_lecture2 + ", " + arr_resume_livre[3] + ",, " + arr_lecture[3]
]
else:
# media absent : on programme le téléchargement
# est-ce qu'on mémorise le livre même si pas téléchargé ?
# - oui , pour l'instant
save_num4c_actuel(lvr["n"])
b_espace, s_espace = commun.espace("suffisant")
if b_espace == False:
arr_prononcer3 = message_espace_insuffisant(s_espace)
else:
enqueue_download(bbl_actu(), lvr)
if bbll == cfg.LG_FRANCAIS:
voc_dl1 = "téléchargement programmé "
voc_dl2 = "téléchargement en arrière-plan du livre "
elif bbll == cfg.LG_ANGLAIS:
voc_dl1 = "download added to the queue "
voc_dl2 = "background download for book "
elif bbll == cfg.LG_ALLEMAND:
voc_dl1 = "Herunterladung programmiert "
voc_dl2 = "Herunterladung in Hintergrund programmiert "
arr_prononcer3 = [
voc_dl1,
voc_dl1,
voc_dl2 + arr_resume_livre[2],
voc_dl2 + arr_resume_livre[3]
]
return arr_prononcer3
def final_resume_livre():
""" retourne une chaîne du type :
- "La Maison à vapeur, de Jules VERNE"
- "404, 14 heures , La Maison à vapeur, de Jules VERNE, lu par Orangeno"
"""
# définir variables
n = zero_off(lv_num4c())
t = lv_titre()
a = lv_auteur()
l = lv_lecteur()
g = lv_genre()
t = t.replace("_", " ") # Raymond_Devos_-_Je_zappe_1992
# --> Raymond Devos - Je zappe 1992
a = a.replace("_", " ")
lu_par_lecteur = ", Lu par " + l
bbll = bbl_langue()
if bbll == cfg.LG_ANGLAIS:
if l.strip() == "":
lu_par_lecteur = ""
else:
lu_par_lecteur = ", the reader is " + l
elif bbll == cfg.LG_ALLEMAND:
if l.strip() == "":
lu_par_lecteur = ""
else:
lu_par_lecteur = ", der Vorleser ist " + l
else:
if l.strip() == "":
lu_par_lecteur = ""
else:
lu_par_lecteur = ", lu par " + l
# on inverse les termes
# ex : Allais Alphonse -> Alphonse Allais
# ~ if a.find(" ") > 0:
# ~ lva = a.split(" ", 2)
# ~ a = lva[1] + " " + lva[0]
d = duree_conviviale(lv_duree())
# 457, 19 minutes, Ventre Saint-Gris, de Brisay
# 458, 16 minutes, La Dame de Bayard, de henry Brisay
# 777, 51 minutes, Dix années d'exil, de staël De
# 1536, 10 minutes, Comment on se venge, de Richard Lesclide
# 2015, 28 minutes, Révélation magnétique, de Edgar Poe
if bbll == cfg.LG_FRANCAIS:
if a.strip() == "":
ecrit_par = ""
else:
ecrit_par = ", de " + a
return [
t + ", de " + a,
t + ", de " + a,
n + ", " + g + ", " + d + ", " + t + ecrit_par + lu_par_lecteur,
n + ", " + g + ", " + d + ", " + t + ecrit_par + lu_par_lecteur
]
elif bbll == cfg.LG_ANGLAIS:
if a.strip() == "":
ecrit_par = ""
else:
ecrit_par = ", author " + a
return [
t + ", written by " + a,
t + ", written by " + a,
n + ", " + d + ", " + t + ecrit_par + lu_par_lecteur,
n + ", " + d + ", " + t + ecrit_par + lu_par_lecteur
]
elif bbll == cfg.LG_ALLEMAND:
if a.strip() == "":
ecrit_par = ""
else:
ecrit_par = ", der Autor ist " + a
return [
t + ", geschrieben von " + a,
t + ", geschrieben von " + a,
n + ", " + d + ", " + t + ecrit_par + lu_par_lecteur,
n + ", " + d + ", " + t + ecrit_par + lu_par_lecteur
]
def horodatage_convivial(mn_sec):
""" convertit horodatage en langage parlé """
# ex : 0:05 devient 0 minute 5
# 14:32 devient 14 minutes 32
temps = mn_sec.split(":")
if len(temps) == 2:
return "{} minutes {}".format(temps[0], temps[1])
else:
return ""
def lancer_lecture(lvr_lecture, piste_lecture, seek_lecture):
""" lit un fichier mp3 ou un dossier de mp3
renvoie liste chaînes du type :
- "piste 3 sur 8"
- "piste 3 sur 8, à 3 minutes 12"
"""
if bbl_actu() == cfg.bbl_CLE_USB_ANARCHIE:
# jouer la clé usb : ajouter à mpd chaque fichier mp3
num_url = 0
for url in lvr_lecture["u"]:
if num_url == 0:
infos.m_g("USB {}: mpc add 'file://{}'".format(num_url, url))
# IMPORTANT, mpd accepte les chemins absolus, comme :
# mpc add "/m/music/type3/Z/Stefan Zweig/Partie 1"
mpc.add("file://" + url)
# LDM = lecture des médias
# documentation en cours d'écriture
# cf. http://gangand.net/pp/projets/xavbox/adm.php#aba_lecture
infos.m_g("LDM_mpc.add(\"file://" + url + "\")")
num_url += 1
infos.m_g("USB : ...")
infos.m_g("USB {} : mpc add {}".format(num_url, url))
else:
# ajouter le dossier, de fichier(s) mp3, du livre demandé
bib_dir = bbl_sub_folder()
audio_files_folder = bib_dir + "/" + lvr_lecture["n"]
# TODO : voir si bien placé
# il vaut mieux faire un update quand on crée un dossier
# et qu'on y copie ou dézippe des nouveaux mp3
mpc.update_wait(audio_files_folder)
# ajouter et jouer fichier à position enregistrée
mpc.add(audio_files_folder)
infos.m_g("LDM_mpc.add(\"" + audio_files_folder + "\")")
# lancer la lecture de la playliste du livre
mpc.ferme_ton_clapet()
mpc.play(piste_lecture)
mpc.seek(seek_lecture)
infos.m_g("inconnu ? => " + mpc.sub_proc("mpc -f %file% | head -1"))
# si une seule piste dans playlist, ne pas annoncer le n° de piste
# ~ if int(mpc.playlist_longueur()) > 1:
bbll = bbl_langue()
if bbll == cfg.LG_FRANCAIS:
piste, sur_total, at_time = "piste ", " sur ", " à "
elif bbll == cfg.LG_ANGLAIS:
piste, sur_total, at_time = "track ", " from ", " at "
elif bbll == cfg.LG_ALLEMAND:
piste, sur_total, at_time = "Stück ", " von ", " an "
msg_start = piste + piste_lecture + sur_total + mpc.playlist_longueur()
if seek_lecture in [ "", "00:00:00"]:
msg = msg_start
else:
msg = msg_start + ", " + at_time + horodatage_convivial(seek_lecture)
arr_prononcer2 = [
msg_start,
msg_start,
msg_start,
msg_start
]
return arr_prononcer2
def last_pos(pos_lvr):
""" position dans le morceau
renvoie un tuple :
position (numéro de piste), seek (02:38), ...
"""
# "non lu" signifie "pas de mémorisation trouvée pour ce livre"
piste1, seek1, seek1_read, horo1 = "1", "00:00:00", "non lu", ""
mem_file = bbl_pos_livres()
if commun.file_exists(mem_file):
with open(mem_file, "r") as f:
livres_commences = f.readlines()
for ligne in livres_commences:
ligne = ligne.strip()
if ligne.find(pos_lvr["n"] + "|") == 0:
t = ligne.split("|")
piste1, seek1, horo1 = t[1], t[2], t[3]
liste_str = [ str(i) for i in range(1, 1000) ]
if not piste1 in liste_str:
# pour éviter les valeurs du type::
# volume: 79% repeat: off random: off single: off consume: off
infos.log("ERR piste_memo BAD : " + piste1)
piste1 = "1"
seek1_read = seek1 + "/"
break
infos.log("piste1, seek1, seek1_read, horo = {}, {}, {}, {}".format(piste1, seek1, seek1_read, horo1))
# ex : 00:00:00, non lu
# 0:10, 0:10/
# 0:05, 0:05/
return piste1, seek1, seek1_read
def visu_nfo_livre(lv1, nfo_seek_read):
""" ligne infos livre
renvoie une chaîne du type :
livre 749 n=0749 mp3 0:14/ 0:1:00 1.2Mo DJ Rebel Conversation dune pe
"""
# TOUDOU_optionnel : indiquer par une lettre P = présent, A = absent (ou . = absent)
# si le media est là
# --> petit bip sonore genre pouce levé, pour dire que le media est là
lv1u = lv1["u"][0]
tu = lv1["type_url"]
seek1 = nfo_seek_read.rjust(7)
lv1n = zero_off(get_num4c_actuel()).rjust(4)
lv1d = lv1["d"].rjust(5)
lv1p = lv1["p"].rjust(5) + "Mo"
lv1l = lv1["l"][:9].ljust(10)
lv1t = (lv1["t"] + "." * 20)[0:20]
lv1urls = lv1u[:20] + " ... " + lv1u[-20:]
msg = "VISU livre " + " ".join((lv1n, tu, seek1, lv1d, lv1p, lv1l, lv1t))
infos.g_m(msg)
p0 = "livre " + lv1["n"] + ", " + lv1["t"] + " de " + lv1["a"]
p1 = "livre " + lv1["n"] + ", " + lv1["t"] + " de " + lv1["a"]
p2 = "livre " + lv1["n"] + ", " + lv1["t"] + " de " + lv1["a"]
p3 = "livre " + lv1["n"] + ", " + lv1["t"] + " de " + lv1["a"]
arr_prononcer1 = [ p0, p1, p2, p3 ]
return arr_prononcer1
####################################################################
# lire_livre_actuel() #
####################################################################
# la lecture est lancée si user appuie sur Entrée (entree_lire() ),
# quand il entend le livre actu (Entrée fixe la variable action à "lire")
# mpc.ferme_ton_clapet() # coupe les messages vocaux en cours et à venir
mpc.clear() # stoppe lecture actuelle
mpc.random_off() # lire un livre dans l'ordre
lvr_actu = lv_livre_actuel() # définit le livre actu
# cf. doc_01 et fichier lire_livre_actuel.odt sur /3en1
piste, seek, seek_read = last_pos(lvr_actu) # positionne dans le morceau, MUET
visu_nfo_livre(lvr_actu, seek_read) # infos visuelles livre , MUET
global ouverture_biblio
prendre_parole = True
if direkt == "direkt":
prendre_parole = False
arr_prononcer = final_lire(lvr_actu, piste, seek)
elif action == "lire":
if ouverture_biblio == True:
arr_prononcer = final_annoncer(seek_read)
else:
# prendre_parole = False
arr_prononcer = final_lire(lvr_actu, piste, seek)
# ne rien prononcer quand on demande la lecture d'un livre
# pour des infos, il y a les touches /, //, /*
# le user a déjà entendu les infos du livre
elif action == "annoncer":
arr_prononcer = final_annoncer(seek_read)
else:
arr_prononcer = "erreur, l'action n'est ni lire, ni annoncer "
if prendre_parole == True:
infos.pdrNew(arr_prononcer)
else:
infos.m_g("PRENDRE PAROLE FALSE 2")
# if prendre_parole == True:
# if direkt == '':
# infos.pdrNew(arr_prononcer, bbl_langue())
# dès qu'un livre est lu ou annoncé,
# la bibliothèque est au-delà du premier livre
ouverture_biblio = False
def loglevel():
""" retourne le niveau du loglevel """
return int(infos.ini_get("loglevel", "0"))
def lv_data(champ, idx_ze = None):
""" champ du livre
sel_lvr[ idx_ze ] ou
sel_lvr[ ze__indice_actuel() ]
"""
global sel_lvr
if len(sel_lvr) == 0:
# attention : si global sel_lvr est vide,
# sel_lvr[idx_ze] renvoie un IndexError
return "sel_lvr est vide"
if idx_ze is None:
idx_ze = ze__indice_actuel()
return sel_lvr[idx_ze][champ]
def lv_livre_actuel():
""" renvoie le livre actuel """
global sel_lvr
# ~ print("ze__indice_actuel()=" + str(ze__indice_actuel()))
return sel_lvr[ze__indice_actuel()]
def lv_auteur(idx_ze = None):
""" auteur du livre
sel_lvr[ idx_ze ] ou
sel_lvr[ ze__indice_actuel() ]
"a" signifie poids
"""
return lv_data("a", idx_ze)
def lv_duree(idx_ze = None):
""" durée du livre
sel_lvr[ idx_ze ] ou
sel_lvr[ ze__indice_actuel() ]
"d" signifie poids
"""
return lv_data("d", idx_ze)
def lv_fiche(idx_ze = None):
""" url fiche info html du livre
sel_lvr[ idx_ze ] ou
sel_lvr[ ze__indice_actuel() ]
"f" signifie fiche
"""
return lv_data("f", idx_ze)
def lv_genre(idx_ze = None):
""" genre du livre (roman, conte, ...)
sel_lvr[ idx_ze ] ou
sel_lvr[ ze__indice_actuel() ]
"y" signifie genre
"""
return lv_data("y", idx_ze)
def lv_lecteur(idx_ze = None):
""" lecteur(s) ou lectrice(s) du livre
sel_lvr[ idx_ze ] ou
sel_lvr[ ze__indice_actuel() ]
"l" signifie lecteur
"""
return lv_data("l", idx_ze)
def lv_poids(idx_ze = None):
""" poids du livre
sel_lvr[ idx_ze ] ou
sel_lvr[ ze__indice_actuel() ]
"p" signifie poids
"""
return lv_data("p", idx_ze)
def lv_num4c(idx_ze = None):
""" num4C (numéro à 4 chiffres) du livre
sel_lvr[ idx_ze ] ou
sel_lvr[ ze__indice_actuel() ]
"n" signifie numl4c
"""
return lv_data("n", idx_ze)
def lv_titre(idx_ze = None):
""" titre du livre
sel_lvr[ idx_ze ] ou
sel_lvr[ ze__indice_actuel() ]
"n" signifie numl4c
"""
return lv_data("t", idx_ze)
def lv_type_url(idx_ze = None):
""" type d'url du livre
sel_lvr[ idx_ze ] ou
sel_lvr[ ze__indice_actuel() ]
sera peut-être abandonné certainement
"""
return lv_data("type_url", idx_ze)
def lv_url(idx_ze = None):
""" liste d'urls media du livre (éléments séparés par le signe '+'
sel_lvr[ idx_ze ] ou
sel_lvr[ ze__indice_actuel() ]
"u" signifie url
"""
return lv_data("u", idx_ze)
def media_present(lvr):
""" teste présence mp3 seul, ou d'un dossier zip
renvoie une des 4 valeurs suivantes :
"présent_usb",
"absent_usb",
"dépôt_local_présent"
"dépôt_local_absent"
"taille_était_nulle"
fonctions utilisées dans deux autres fonctions seulement :
rand10lvr()
lire_livre_actuel.final_annoncer()
TODO : un livre présent sur un dépôt local (/media/fbx/rouge)
doit-il être considéré comme "présent" ou "dépôt_local"
"""
bib_dir = bbl_folder()
# présence sur clé usb
if commun.dir_exists(bib_dir + "/" + lvr["n"]):
# # vérifier si fichier .mp3 de taille nulle
cmd = "du -sc {}/{}".format(bib_dir, lvr["n"]) + \
"/*mp3 2>/dev/null | tail -1 | awk '{print $1}'"
taille_mp3 = mpc.sub_proc(cmd)
if taille_mp3 == "0":
msg = "Ce livre a rencontré un problème " + \
"de téléchargement, veuillez réessayer plus tard"
infos.pdrNew(msg)
mask_cmd = "rm -rf {}/{}"
cmd = mask_cmd.format(bib_dir, lvr["n"])
# # suppression du dossier num4c
mpc.sub_proc(cmd)
return "taille_était_nulle"
return "présent_usb"
# présence dépôt local (nas freebox)
elif commun.depot_local_present("aba"):
if commun.dir_exists("/media/fbx/aba/" + bbl_actu() + "/" + lvr["n"]):
return "dépôt_local_présent"
else:
return "dépôt_local_absent"
# média absent partout : sur clé usb ET sur dépôt local
else:
infos.log("debug Dossier media absent " + bib_dir + "/" + lvr["n"])
return "absent_usb"
def memo_pos_livre_aba():
""" mémorise le dernier moment lu du livre actuel (= livre quitté)
càd position dans playlist et progression
"""
def memo_pos_livres_maj(fichier, ecrire_ligne):
""" mémorise le dernier moment de lecture
d'un livre désigné par son num4c
ex : memo_pos_livres_maj("/m/memo/aba/memo_pos_livres_litteratureaudio.txt", "0038|1|0:41|2020-02-20 07:43:49")
"""
# attention : penser au cas où on a lu tout le livre
le_numero = ecrire_ligne.split("|")[0]
infos.m_g("DEBUG_MEMO " + fichier + " " + ecrire_ligne)
if commun.file_exists(fichier):
infos.g_m("le fichier " + fichier + " existe")
s_num = le_numero + "|" # "0152|"
with open(fichier, "r") as f:
lignes = f.readlines()
f2 = open(fichier, "w")
ligne_trouvee = False
for ligne in lignes:
ligne = ligne.strip()
if ligne.find(s_num) == 0:
# mettre à jour ce livre
ligne_trouvee = True
f2.write(ecrire_ligne + '\n')
infos.g_m("cas1 = " + ecrire_ligne)
infos.g_m("cas1 : on mémorise en mettant à jour")
infos.g_m("memoPosLivre cas1 [MAJ] : >>> " + ecrire_ligne + " <<<")
elif len(ligne) > 5:
f2.write(ligne + '\n')
infos.g_m("cas2 = " + ligne)
if not ligne_trouvee:
# première mémorisation pour ce livre
f2.write(ecrire_ligne + '\n')
infos.g_m("cas3 = " + ecrire_ligne)
infos.g_m("cas3 : on mémorise ce livre pour la première fois")
infos.g_m("memoPosLivre cas3 [NEW] : >>> " + ecrire_ligne + " <<<")
else:
# 1er livre mémorisé
f2 = open(fichier, "w")
f2.write(ecrire_ligne + '\n')
infos.g_m("cas4 = " + ecrire_ligne)
infos.g_m("cas4 : on mémorise un premier livre")
infos.g_m("memoPosLivre cas4 [+FILE] : >>> " + ecrire_ligne + " <<<")
f2.close()
infos.g_m("voir fichier " + fichier)
# mémoriser position et progression du livre quitté
if nb_livres_total() == 0:
infos.m_g("on ne mémorise rien, car nb livres total = 0")
return 0
s_piste = str(mpc.playlist_position())
if s_piste.startswith("volume:"):
infos.g_m("s_piste = " + s_piste)
infos.g_m("on ne mémorise rien, car s_piste.startswith volume")
else:
# on mémorise le num4c, la piste, la progression, l'horodatage
# 0418|1|0:11|2020-02-26 00:20:04
s_horo = infos.jour_heure_actu()
infos.m_g("debug1")
print("debug nb livres total = {}".format(nb_livres_total()))
s_num = lv_num4c() # 0152 (colonne "n=" dans pipe.txt)
infos.m_g("debug2")
s_prog = mpc.status_progression()[0]
memo_ligne = "{}|{}|{}|{}".format(s_num, s_piste, s_prog, s_horo)
memo_pos_livres_maj(bbl_pos_livres(), memo_ligne)
def memo_stop_module():
""" quitter module (touche 0) : mémoriser où on est """
infos.m_g("aba memo_stop_module")
memo_pos_livre_aba()
def menu_changer_biblio():
""" changer de bibliothèque par un menu vocal """
explication = \
"choisissez une bibliothèque de 1 à {0}, " + \
"pressez ensuite Entrée pour la lancer, " + \
"ou bien zéro pour sortir de ce menu, " + \
"vous êtes actuellement dans la bibliothèque {}".format(bbl_nom())
commun.menu_vocal("aba_bibliotheques", "bibliothèque", explication)
def menu_suppr_lvr():
""" menu Entrée suppression livre(s) """
msg = "Appuyer sur 1 puis Entrée pour supprimer le livre présent"
infos.pdrNew(msg)
msg = "ou bien sur 2 pour supprimer tous les livres présents"
infos.pdrNew(msg)
choix = input()
if choix == "1":
supprimer_livre() # on ne vérifie pas que le livre est présent
# cela permet de forcer la suppression du dossier
# s'il existe
elif choix == "2":
supprimer_livres()
else:
infos.pdrNew("Suppression annulée")
def menu_voc11():
""" menu spécial aba """
commun.menu_vocal("aba_mnu11", "audiolivres")
def message_espace_insuffisant(s_espace):
""" message générique aba d'espace insuffisant
PAs de prononciation ici,
renvoi d'un tableau de messages pour pdrNew
"""
mega_octets_occupes = commun.du(cfg.M_MUSIC + "/aba")
bbll = bbl_langue()
if bbll == cfg.LG_FRANCAIS:
voc_dl2 = "vous ne pouvez pas télécharger " + \
"de livre audio, " + s_espace + ", " + \
"essayez de faire de la place " + \
"en sélectionnant les livres présents avec les touches 111, " + \
"puis en les effaçant."
# autre message possible :
# espace restant insuffisant pour télécharger,
# veuillez libérer d'abord de l'espace.
# Pour cela, placez-vous sur un livre présent,
# puis effacez-le avec 987, ou bien 11 pour
# ouvrir le menu vocal, puis la touche 9,
# pour supprimer plusieurs livres d'un coup.
voc_dl1 = voc_dl2
elif bbll == cfg.LG_ANGLAIS:
voc_dl1 = "download not possible because space is missing "
voc_dl2 = "download not possible because space is missing "
elif bbll == cfg.LG_ALLEMAND:
voc_dl1 = "Herunterladung unmöglich, Raum zu kurz "
voc_dl2 = "Herunterladung unmöglich, Raum zu kurz "
# pas de téléchargement, ne pas annoncer le résumé du livre
arr_msg_insuff = [
voc_dl1,
voc_dl1,
voc_dl2,
voc_dl2
]
return arr_msg_insuff
def nb_livres_favoris():
""" renvoie le nombre de livres consignés en favoris
IMPORTANT : un favori peut être présent ou absent
"""
num4c_trouves = infos.ini_get("aba_favoris_" + bbl_actu(), "")
if num4c_trouves == "":
return 0
else:
return len(num4c_trouves.split(","))
def nb_livres_prezents(cle_biblio = None):
""" renvoie le nombre (int) de sous-dossiers
dans dir_search
ou, si argument vide,
dans bbl_folder() --> /m/music/aba/<folder>
TODO : améliorer en vérifiant si dossiers de taille nulle existent
TODO IMPORTANT : pas valable pour usb anarchie
"""
if cle_biblio is None:
cle_biblio = bbl_actu()
# cas particulier : usb anarchie
if cle_biblio == cfg.bbl_CLE_USB_ANARCHIE:
return nb_livres_total()
# les autres cas
dir_search = bbl_folder(cle_biblio)
if commun.dir_exists(dir_search):
cmd = "ls -1 {} | wc -l".format(dir_search)
nb_dossiers = int(mpc.sub_proc(cmd))
return nb_dossiers
else:
return 0
def nb_livres_total():
""" nombre de livres (lignes) da la sélection,
càd du tableau global sel_lvr[]
"""
global sel_lvr
return len(sel_lvr)
def next_trk():
""" aller au chapitre suivant """
# la touche 6 a deux fonctions dans le module aba
mpc.next_trk()
infos.m_g("piste {}".format(mpc.playlist_position()))
def prev_trk():
""" aller au chapitre précédent """
mpc.prev_trk()
infos.m_g("piste {}".format(mpc.playlist_position()))
def rechercher():
""" rechercher un mot ou une partie de mots
dans la colonne auteur, lecteur ou titre
"""
def aide_alphabet():
""" récite les codes de chaque lettre
"""
# num2lettre = {
# "1":"a", "2":"b", "3":"c", "4":"d", "5":"e",
# "6":"f", "7":"g", "8":"h", "9":"i", "10":"j",
# "11":"k", "12":"l", "13":"m", "14":"n", "15":"o",
# "16":"p", "17":"q", "18":"r", "19":"s", "20":"t",
# "21":"u", "22":"v", "23":"w", "24":"x", "25":"y",
# "26":"z" }
# nombres = num2lettre.keys()
# utiliser num2lettre et num2lettre.keys()
pass
mpc.ferme_ton_clapet()
msg = """ Appuyez sur 1, 2 ou 3, puis Entrée pour rechercher
respectivement dans les auteurs, lecteurs et titres des livres
"""
infos.pdrNew(msg)
msg = """ Appuyez sur 4 puis Entrée pour rechercher
sur les trois colonnes, ou 0 puis Entrée pour annuler
"""
infos.pdrNew(msg)
# 1. demander le champ de recherche
champ = input()
# 2. demander le mot de recherche
mpc.ferme_ton_clapet()
num2lettre = {
"1":"a", "2":"b", "3":"c", "4":"d", "5":"e",
"6":"f", "7":"g", "8":"h", "9":"i", "10":"j",
"11":"k", "12":"l", "13":"m", "14":"n", "15":"o",
"16":"p", "17":"q", "18":"r", "19":"s", "20":"t",
"21":"u", "22":"v", "23":"w", "24":"x", "25":"y",
"26":"z" }
nombres = num2lettre.keys()
mot = ""
dans_quoi = {
"1":"auteurs",
"2":"lecteurs",
"3":"titres" }
msg = """ Pour définir le mot à rechercher,
tapez 1 puis Entrée pour la lettre, a,
10 puis Entrée pour la lettre, j,
20 puis Entrée pour la lettre, t,
puis Entrée tout court pour lancer la recherche
"""
infos.pdrNew(msg)
if champ in dans_quoi.keys():
while True:
carac = input()
mpc.ferme_ton_clapet()
if carac == "":
break
if carac in nombres:
# transformer 1 en a, 2 en b, 3 en c, ..., 25 en y, 26 en z
lettre = num2lettre[carac]
mot = mot + lettre
infos.pdrNew("lettre " + lettre)
else:
infos.pdrNew("mauvais nombre, désolé")
# recherche sur le mot
champ_dmd = dans_quoi[champ]
infos.m_g("recherche du mot '{}' dans les {}".format(mot, champ_dmd))
# 3. lancer la recherche sur le champ demandé
dans_champ = {
"1":"a",
"2":"l",
"3":"t" }
champ_alt = dans_champ[champ]
occurences = {}
# initialiser occurences{}
if mot != "":
for lvr in all_lvr:
if mot.lower() in lvr[champ_alt].lower():
occurences[lvr[champ_alt]] = 0
n = 0
t_recherche = []
if mot != "":
for lvr in all_lvr:
if mot.lower() in lvr[champ_alt].lower():
n += 1
t_recherche.append(lvr["n"])
occurences[lvr[champ_alt]] += 1
nb_corresp_mot = len(t_recherche)
if nb_corresp_mot > 0:
mask = "{} livres trouvés pour le mot {}"
infos.pdrNew(mask.format(nb_corresp_mot, mot))
mask = "{} {} différents trouvés"
infos.m_g(mask.format(len(occurences), champ_dmd))
num4c_trouves = ",".join(t_recherche)
slct_get_build(num4c_trouves)
else:
infos.pdrNew("Aucun livre trouvé pour le mot demandé")
num4c_trouves = ""
def reprendre_direct():
""" reprendre directement le dernier audiolivre
"""
msg = "reprendre directement le dernier audiolivre"
infos.g_m(msg)
reprendre("direkt")
def reprendre(direkt = ''):
""" lit dernier livre lu en quittant module """
# ici, on définit simplement le numéro du livre à lire,
# puis on lance lire_livre_actuel()
def dev_afficher_numeros_utiles():
""" affiche quelques nuémros de livres utiles de tests
"""
msg = "numéros de livres intéressants"
infos.m_g(msg)
numeros_audio_cite = " courts : 642, 748, 823, zip : 762, 763, mp3 : 869"
numeros_litteaudio = " courts : 28, 47, 70, 71, 304, 305, 306"
numeros_librivox_fr = " 4"
numeros_divers_src = "4, 5, 6"
msg = "biblio audiocité : " + numeros_audio_cite
msg = "biblio littérature : " + numeros_litteaudio
msg = "biblio librivox_fr : " + numeros_librivox_fr
msg = "biblio divers : " + numeros_divers_src
infos.m_g(msg)
def init_reprendre(direkt = ""):
""" initialisation variables selon biblio actuelle """
mpc.ferme_ton_clapet()
if direkt == 'pas_lancement des audiolivres':
pass
elif direkt == '':
msg = "audiolivres"
infos.g_m("DBG lancement des audiolivres")
# infos.pdrNew(["", msg, msg, msg])
# commun.faire_pause(3, True) # pause de 2s
infos.ini_set("py_current_module", "aba")
infos.ini_set("mode_consultation", "consulter")
bib_folder = bbl_folder()
# dossier /m/music/aba/perso_zip, /m/music/aba/litteratureaudio, ...
cmd = "[ -d " + bib_folder + " ] || mkdir -p " + bib_folder
retour_cmd = mpc.sub_proc(cmd)
def cnt_numeroter(quoi, liste1, nydplatufx = None):
""" renvoie la liste fournie, numérotée """
# cnt = Créer Nouvelles Tables
infos.m_g("===== " + quoi + " =====")
n = 1000
liste2 = []
dico = {}
compter = {}
for nom in liste1:
n += 1
num3c = str(n)[-3:]
num_nom = num3c + ":" + nom # 001:abbé Ricard
liste2.append(num_nom)
dico[nom] = num3c
compter[nom] = 0
if n < 1004:
infos.m_g(num_nom)
infos.m_g("...")
infos.m_g(num_nom) # le dernier élément
infos.m_g("") # ligne vide
if not nydplatufx is None:
global all_lvr
for L in all_lvr:
compter[L[nydplatufx]] += 1 # compter["Daniel Luttringer"] += 1
return liste2, dico, compter
else:
return liste2, dico
def cnt_pgcd(list_urls):
""" renvoie la partie commune la plus longue
pour tous les éléments
"""
longueur_maxi = 1000
# longueur la plus courte du tableau
for i in list_urls:
# ~ print(len(i))
if len(i) < longueur_maxi:
# ~ print(i)
longueur_maxi = len(i)
# ~ m_g("longueur_maxi = " + str(longueur_maxi))
# la chaîne commune n'excédera pas la longueur longueur_maxi
use_previous_modele = False
debut_commun_a_tous = ""
for i in range(longueur_maxi):
modele = list_urls[0][:i]
# ~ print("modele1 = " + modele)
for e in list_urls:
# ~ print("e[:i] = " + e[:i])
# ~ print("modele = " + modele)
# ~ print()
if e[:i] != modele:
# ce modèle ne marche plus
use_previous_modele = True
break
if use_previous_modele == True:
debut_commun_a_tous = modele_precedent
break
else:
modele_precedent = modele
return debut_commun_a_tous
def cnt_raccourcir_tab_url(arr_urls, clef):
""" remplir tableau html
"""
len_url = len(arr_urls)
if len_url == 0:
# ~ return " "
return " <td align=center><small>" + " " + "</small></td>" + '\n'
# LE_MP3 sont habituellement unique,
# parfois, il y a plusieurs liens
if (clef == "LE_MP3") and (len_url > 1):
return " <td align=center style='background: lightgreen;'><small>" + str(len_url) + "</small></td>"
else:
return " <td align=center><small>" + str(len_url) + "</small></td>"
return str(len_url)
# ~ elif len_url == 1:
# ~ return arr_urls[0]
pgcd1 = pgcd(arr_urls)
arr2 = [ i.replace(pgcd1, "[PC]") for i in arr_urls ]
return str(len_url)
def creer_nouvelles_tables(biblio, all_lvr, list_auteurs, list_genres, list_lecteurs, list_url, list_duree, list_poids, list_titre):
""" créer trois tables auteurs, genres, lecteurs,
et un nouveau catalogue aminci
soit au total 4 nouveaux fichiers :
tbl_catalog.txt, tbl_auteurs.txt, tbl_genres.txt, tbl_lecteurs.txt
les 3 listes suivantes sont non triées, mais avec des noms d'auteurs uniques :
list_auteurs, list_genres, list_lecteurs
gain de place dans la base de données trop faible pour être intéressant
par contre, permet de repérer/corriger les données rapidement
"""
chemin = cfg.BIB_DISPOS[biblio]["catalogue"]
save_list_to_file(chemin + "/tbl_auteurs_bruts.txt", list_auteurs)
save_list_to_file(chemin + "/tbl_lecteurs_bruts.txt", list_lecteurs)
save_list_to_file(chemin + "/tbl_genres_bruts.txt", list_genres)
save_list_to_file(chemin + "/tbl_url_bruts.txt", list_url)
save_list_to_file(chemin + "/tbl_duree_bruts.txt", list_duree)
save_list_to_file(chemin + "/tbl_poids_bruts.txt", list_poids)
save_list_to_file(chemin + "/tbl_titre_bruts.txt", list_titre)
# numéroter les listes
list_auteurs_num , dico_auteurs, compte_auteurs = cnt_numeroter("auteurs" , list_auteurs, "a")
list_genres_num , dico_genres, compte_genres = cnt_numeroter("genres" , list_genres, "y")
list_lecteurs_num, dico_lecteurs, compte_lecteurs = cnt_numeroter("lecteurs", list_lecteurs, "l")
list_url_num , dico_url = cnt_numeroter("url" , list_url)
list_duree_num, dico_duree = cnt_numeroter("duree", list_duree)
list_poids_num, dico_poids = cnt_numeroter("poids", list_poids)
list_titre_num, dico_titre = cnt_numeroter("titre", list_titre)
# enregistrer les listes numérotées sur fichier
save_list_to_file(chemin + "/tbl_auteurs.txt" , list_auteurs, compte_auteurs)
save_list_to_file(chemin + "/tbl_lecteurs.txt", list_lecteurs, compte_lecteurs)
save_list_to_file(chemin + "/tbl_genres.txt" , list_genres, compte_genres)
infos.m_g("Fichiers tbl créés.")
# recréer catalog.txt --> tbl_catalog.txt
# avec les colonnes a=, l=, y= (auteur, lecteur, genre)
# comportant uniquement des numéros
# 1. les dictionnaires :
# dico_auteurs : nomAuteur --> numAuteur
# dico_genres : nomGenre --> numGenre
# dico_lecteurs : nomLecteur --> numLecteur
new_catalogue = []
for L in all_lvr:
# nydplatufx
nom, genre_1, duree, poids, lecteur_1 = L["n"], L["y"], L["d"], L["p"], L["l"]
auteur_1, titre, media_url1, fiche, extrait = L["a"], L["t"], L["u"], L["f"], L["x"]
# attention : media_url1 est une variable list
auteur_2 = dico_auteurs[auteur_1]
genre_2 = dico_genres[genre_1]
lecteur_2 = dico_lecteurs[lecteur_1]
media_url2 = "+".join(media_url1) # il faudra raccourci avec radical commun (pgcd)
masque = "n={}|y={}|d={}|p={}|l={}|a={}|t={}|u={}|f={}|x={}"
# ~ masque = "{}|{}|{}|{}|{}|{}|{}|{}|{}|{}"
# on utilise les index et les autres tables
ligne_new = masque.format(nom, genre_2, duree, poids, lecteur_2, auteur_2, titre, media_url2, fiche, extrait)
# on n'utilise pas d'index
ligne_new = masque.format(nom, genre_1, duree, poids, lecteur_1, auteur_1, titre, media_url2, fiche, extrait)
new_catalogue.append(ligne_new)
save_list_to_file(chemin + "/tbl_CATALOG.txt", new_catalogue)
# source : catalog.txt
# ~ n=0001|y=nouvelles |d= 15|p= 14|l=Plumedencr |a=morissette Joseph ferdinand |t=Lucien et Marie-Louise |u=https://archive.org/download/LucienEtMarieLouise/Lucien%20et%20Marie-Louise.mp3 |f=nouvelles/joseph-ferdinand--morissette-lucien-et-marie-louise.html
# ~ n=0002|y=religions |d= 01h25|p= 80|l=Léa |a=Abbé regnault P.a. |t=Chemin de croix médité |u=https://archive.org/compress/chemindecroixmedite/formats=VBR%20MP3&file=/chemindecroixmedite.zip |f=religions/p.a.-abbe-regnault-chemin-de-croix-medite.html
# ~ n=0003|y=contes |d= 02|p= 1,75|l=Sabine |a=Abbé ricouard |t=Contes et légendes de la Seine-Maritime. La bal des fées |u=https://www.archive.org/download/LeBalDesFees/Le_bal_des_fees.mp3 |f=contes/abbe-ricouard-contes-et-legendes-de-la-seine-maritime--la-bal-des-fees.html
# des : tbl_catalog.txt
# ~ n=0001|y=001|d= 15|p= 14|l=001|a=001|t=Lucien et Marie-Louise |u=https://archive.org/download/LucienEtMarieLouise/Lucien%20et%20Marie-Louise.mp3 |f=nouvelles/joseph-ferdinand--morissette-lucien-et-marie-louise.html
# ~ n=0002|y=002|d= 01h25|p= 80|l=002|a=002|t=Chemin de croix médité |u=https://archive.org/compress/chemindecroixmedite/formats=VBR%20MP3&file=/chemindecroixmedite.zip |f=religions/p.a.-abbe-regnault-chemin-de-croix-medite.html
# ~ n=0003|y=003|d= 02|p= 1,75|l=003|a=003|t=Contes et légendes de la Seine-Maritime. La bal des fées |u=https://www.archive.org/download/LeBalDesFees/Le_bal_des_fees.mp3 |f=contes/abbe-ricouard-contes-et-legendes-de-la-seine-maritime--la-bal-des-fees.html
pass
def save_list_to_file(fichier, list_quoi, dico_compte = None):
"""
"""
if dico_compte is None:
list_quoi.sort()
liste_triee = "\n".join(list_quoi)
with open(fichier, "w") as f:
corps = "# fichier créé par aba.py\n" + liste_triee
f.write(corps)
else:
# comptabiliser pour chaque élément
liste_triee = list(list_quoi)
with open(fichier, "w") as f:
for i in list_quoi:
d = dico_compte[i]
# print(i + ":" + str(d), file=f)
f.write(i + ":" + str(d))
f.close()
def usb_dossiers_audio(src_dir):
""" renvoie une liste de dossiers contenant des fichiers audio,
sauf ceux commençant par /m/music,
càd avec extensions mp3, m4a, ogg, wav, wma
utile pour lire des audiolivres copiés de façon anarchique
sur une clé usb
output : list_audio_folders[]
"""
# TODO : vérifier que les fichiers audio ne sont pas de taille nulle
if cfg.CLE_USB_BROWSE_M_MUSIC == True:
# on prend toute la clé
list_folders = commun.folders_recurse(src_dir)
else:
# on prend tout sauf /m/music
list_folders_all = commun.folders_recurse(src_dir)
list_folders = []
for d in list_folders_all:
# supprimer les dossiers commençant par /m/music/
# car ils sont prévus pour être lus par mpd/jk2019 en natif
if d.startswith(cfg.M_MUSIC):
pass
else:
list_folders.append(d)
list_audio_folders = []
for un_dossier in list_folders:
liste_fichiers = commun.files_simple(un_dossier)
nb_fichiers = len(liste_fichiers)
if nb_fichiers > 0:
# analyser les fichiers du dossier "un_dossier"
nb_audio = 0
for i in liste_fichiers:
i_low = i.lower()
if (
(i_low.endswith(".mp3")) or
(i_low.endswith(".m4a")) or
(i_low.endswith(".ogg")) or
(i_low.endswith(".wav")) or
(i_low.endswith(".wma"))
):
nb_audio += 1
if nb_audio > 0:
if loglevel() > 0:
infos.m_g("{:>3s} fichiers, {:>3d} audio, {}".format(str(nb_fichiers), nb_audio, un_dossier))
list_audio_folders.append(un_dossier)
return list_audio_folders
def usb_charger_livres():
""" chercher les livres sur la clé usb,
création de la list all_lvr[]
"""
msg = "usb_charger_livres() recherchent tous les fichiers audio" + \
"sur la clé usb, à l'exception de ceux qui sont dans " + \
"/m/music. Ne prend pas en compte les fichiers .zip"
infos.g_m(msg)
msg = "La bibliothgèque 'lire les livres de la clé u s b'" + \
"permet de lire les fichiers copiés de façon anarchique" + \
"par une bonne âme."
infos.g_m(msg)
msg = "Il y aura peut-être une possibilité de fairte du ménage" + \
"sur une clé trop remplie."
infos.g_m(msg)
# dossiers avec fichiers audio
m_audio_folders = usb_dossiers_audio("/m")
if len(m_audio_folders) == 0:
return False
masque = "Nb dossiers contenant au moins un fichier audio, et hors du dossier /m/music : {}"
print(masque.format(len(m_audio_folders)))
# créer le tableau all_lvr []
global all_lvr
all_lvr = []
# 10 champs = nydplatufx
# n=0001|y=Romans|d=13:25:00|p=732|l=Victoria|a=MIRBEAU, Octave|t=Le Journal d'une femme de chambre|u=http://www.litteratureaudio.net/mp3/Octave_Mirbeau_-_Le_Journal_d_une_femme_de_chambre.zip|f=mirbeau-octave-le-journal-dune-femme-de-chambre.html|x=http://www.litteratureaudio.net/mp3/Octave_Mirbeau_-_Le_Journal_d_une_femme_de_chambre_Chap01.mp3
# n=0002|y=Romans|d=5:30:00|p=|l=Jean-Luc Fischer|a=H. P. Lovecraft|t=L'Affaire Charles Dexter Ward|u=http://www.litteratureaudio.org/mp3/H_P_Lovecraft_L_Affaire_CDW.zip|f=lovecraft-howard-phillips-laffaire-charles-dexter-ward.html|x=http://www.litteratureaudio.org/mp3/H_P_Lovecraft_L_Affaire_CDW_Ch_I_1.mp3
# n=0003|y=Romans|d=28:30:00|p=|l=Cocotte|a=DUMAS, Alexandre|t=Les Trois Mousquetaires|u=http://www.litteratureaudio.org/mp3/Alexandre_Dumas_-_Les_trois_Mousquetaires_chap0-10.zip+http://www.litteratureaudio.org/mp3/Alexandre_Dumas_-_Les_trois_Mousquetaires_chap11-20.zip+http://www.litteratureaudio.org/mp3/Alexandre_Dumas_-_Les_trois_Mousquetaires_chap21-30.zip+http://www.litteratureaudio.org/mp3/Alexandre_Dumas_-_Les_trois_Mousquetaires_chap31-40.zip+http://www.litteratureaudio.org/mp3/Alexandre_Dumas_-_Les_trois_Mousquetaires_chap41-50.zip+http://www.litteratureaudio.org/mp3/Alexandre_Dumas_-_Les_trois_Mousquetaires_chap51-60.zip+http://www.litteratureaudio.org/mp3/Alexandre_Dumas_-_Les_trois_Mousquetaires_chap61-68.zip|f=dumas-alexandre-les-trois-mousquetaires.html|x=http://www.litteratureaudio.org/mp3/Alexandre_Dumas_-_Les_Trois_Mousquetaires_Chap00_Introduction.mp3
# n=0004|y=Romans|d=6:43:00|p=182|l=Damien Genevois|a=VERNE, Jules|t=Le Tour du monde en 80 jours|u=http://www.litteratureaudio.net/mp3/Jules_Verne_-_Le_Tour_du_monde_en_80_jours.zip|f=jules-verne-le-tour-du-monde-en-80-jours.html|x=
# n=0005|y=Romans|d=19:0:00|p=|l=Monique Vincens|a=PROUST, Marcel|t=Du côté de chez Swann|u=http://www.litteratureaudio.net/mp3/Marcel_Proust_-_Du_Cote_de_chez_Swann_L1_Combray_V2.zip+http://www.litteratureaudio.net/mp3/Marcel_Proust_-_Un_Amour_de_Swann.zip+http://www.litteratureaudio.net/mp3/Marcel_Proust_-_Du_Cote_de_chez_Swann_L3_Nom_de_pays_-_le_nom.zip|f=proust-marcel-du-cote-de-chez-swann.html|x=http://www.litteratureaudio.net/mp3/Marcel_Proust_-_Du_Cote_de_chez_Swann_L1_Combray_Introduction.mp3
num = 0
for audio_folder in m_audio_folders:
files_audio_path_usb = commun.files_audio_simple(audio_folder)
num += 1
num4c = zero_on(num)
genre = ""
duree = ""
poids = ""
lecteur = ""
# ci-dessous, ok pour dossier
# Pierre-Gilles de Gennes/Laser fermeture éclair
# auteur = mpc.sub_proc('basename "$(dirname "{}")"'.format(audio_folder))
auteur = ""
titre = mpc.sub_proc('basename "{}"'.format(audio_folder))
arr_url_media = files_audio_path_usb
fiche = ""
extrait = ""
un_livre = {
"n": num4c , # numéro à 4 chiffres
"y": genre , # type
"d": duree , # durée
"p": poids , # poids (string : "5.78", "12", ...)
"l": lecteur , # lecteur
"a": auteur , # auteur
"t": titre , # titre
"u": arr_url_media, # url mp3 ou zip
"f": fiche , # url fiche
"x": extrait , # extrait
"type_url": "mp3", # type url : mp3, zip
# "type_url": "usb_mp3", # type url : mp3, zip
}
all_lvr.append(un_livre)
infos.m_g("usb, titre " + str(num) + " : " + str(titre))
infos.m_g("usb, titres trouvés sur la clé (hors /m/music) : " + str(num))
# creer_html_all_lvr(all_lvr, "/m/cle_usb_all_lvr.html")
return True
def perso_zip_charger_livres():
""" chercher les livres zip sur http://gangand.net/...
créer la list all_lvr[]
"""
# procéder pour cette bibliothèque comme pour litterature audio, librivox ...
# en créant le tableau all_lvr[] adéquat
cmd = 'wget -q http://gangand.net/aa/audiolivres/perso_zip -O - | grep zip | sort | grep -o -E "href=\\"[^>]*"'
liste_brute_1 = mpc.sub_proc(cmd)
cmd_poids = 'wget -q http://gangand.net/aa/audiolivres/perso_zip -O - | grep zip'
les_poids = mpc.sub_proc(cmd_poids)
print("*" * 30 + " bbl_perso_zip " + "*" * 30)
print(liste_brute_1)
############################################################
# href="antoine_blondin_-_rive_gauche_avec_pierre_assouline.zip"
# href="raymond_devos_-_mon_chien_c_est_quelqu_un.zip"
# href="raymond_devos_-_un_ange_passe.zip"
# href="raymond_devos_-_volume_1.zip"
# href="San_Antonio_-_En_peignant_la_girafe.zip"
############################################################
# TODO : récupérer le poids :
# http://gangand.net/aa/audiolivres/perso_zip/?C=N;O=D
print("*" * 30 + " bbl_perso_zip fin " + "*" * 30)
liste_brute_2 = liste_brute_1
liste_brute_1 = liste_brute_1.replace('"', '')
liste_brute_1 = liste_brute_1.replace('href=', '')
noms_zip = liste_brute_1.split("\n")
liste_brute_2 = liste_brute_2.replace('href="', "http://gangand.net/aa/audiolivres/perso_zip/")
liste_brute_2 = liste_brute_2.replace('"', '')
fichiers_zip = liste_brute_2.split("\n")
# fichiers zip en ligne
if len(fichiers_zip) == 0:
return False
masque = "Nb fichiers zip trouvés sur http://gangand.net/... : {}"
print(masque.format(len(fichiers_zip)))
# créer le tableau all_lvr []
global all_lvr
all_lvr = []
num = 0
for un_zip in fichiers_zip:
# un_zip est de la forme :
# http://gangand.net/aa/audiolivres/perso_zip/antoine_blondin_-_rive_gauche_avec_pierre_assouline.zip
auteur_titre = noms_zip[num]
new_num4c = auteur_titre
# auteur_titre est de la forme :
# antoine_blondin_-_rive_gauche_avec_pierre_assouline.zip
auteur_titre = auteur_titre.replace(".zip", "")
auteur_titre = auteur_titre.replace("_", " ")
auteur_titre = auteur_titre.replace("%c3%a9", "é")
auteur_titre = auteur_titre.split(" - ",2)
auteur = "auteur zip"
titre = "titre zip"
if len(auteur_titre) == 1:
auteur = "auteur inconnu"
titre = auteur_titre[0]
elif len(auteur_titre) == 2:
auteur = auteur_titre[0]
titre = auteur_titre[1]
num += 1
num4c = zero_on(num)
# TODO : Raymond_Devos_-_Je_zappe_1992
# au lieu de 0001
# num4c = new_num4c.replace(".zip", "")
genre = ""
duree = ""
poids = ""
lecteur = ""
arr_url_media = [ un_zip,]
fiche = ""
extrait = ""
un_livre = {
"n": num4c , # numéro à 4 chiffres
"y": genre , # type
"d": duree , # durée
"p": poids , # poids (string : "5.78", "12", ...)
"l": lecteur , # lecteur
"a": auteur , # auteur
"t": titre , # titre
"u": arr_url_media, # url mp3 ou zip
"f": fiche , # url fiche
"x": extrait , # extrait
"type_url": "zip", # type url : mp3, zip
# "type_url": "usb_mp3", # type url : mp3, zip
}
all_lvr.append(un_livre)
# creer_html_all_lvr(all_lvr, "/m/perso_zip_all_lvr.html")
return True
def creer_html_all_lvr(livr_bruts, f_html):
""" crée une vue du tableau dynamique
des livres sur clé usb quelconque
(càd une clé envoyée par un/une amie à France)
"""
entete = "<tr> \
<td><b>num4c</b></td> \
<td><b>genre</b></td> \
<td><b>duree</b></td> \
<td><b>poids</b></td> \
<td><b>lecteur</b></td> \
<td><b>auteur</b></td> \
<td><b>titre</b></td> \
<td><b>url[0]</b></td> \
<td><b>fiche</b></td> \
<td><b>extrait</b></td> \
</tr>"
corps_html = "<html><head><title>Livres sur clé usb</title></head>" + \
"<body><center><table border=1 cellpadding=4 cellspacing=2>"
corps_html += entete
lignes = ""
for i in livr_bruts:
les_champs = \
(i["n"], i["y"], i["d"], i["p"], i["l"], i["a"], i["t"], i["u"][0], i["f"], i["x"])
ligne = "<tr><td>" + \
"</td><td>".join(les_champs) + \
"</td></tr>" + "\n"
lignes += ligne
corps_html += lignes
corps_html += "</table></center></body></html>"
with open(f_html, "w") as f:
f.write(corps_html)
infos.m_g("Le fichier {} a été créé.".format(f_html))
def verif_dir_audiolivres():
""" si /m pas monté, on quitte
si /m/memo/aba pas créable, on quitte
"""
if commun.m_is_mounted() == False:
msg = "Problème, la clé u s b ne semble pas détectée, " + \
"abandon des audiolivres."
infos.pdrNew(msg)
return False
# vérif "/m/memo/aba" existe (ABA_MEMO_DIR)
dossier = cfg.ABA_MEMO_DIR
if not commun.dir_exists(dossier):
commun.make_dir(dossier)
if not commun.dir_exists(dossier):
msg = "Erreur lors de la création du dossier mémoire audiolivres"
infos.pdrNew(msg)
return False
return True
########################################
# reprendre aba #
########################################
# mettre False ci-dessous pour ne pas
# reprendre_directement la lecture ("annoncer" en fait)
REPRENDRE_ANNONCER = True
# REPRENDRE_ANNONCER = False
infos.m_g("B pour dbg_var_all_lvr(), étude variables ESSENTIELLES")
mpc.ferme_ton_clapet()
if verif_dir_audiolivres() == False:
return 0
init_reprendre(direkt)
global all_lvr
chargement_livres = False
if bbl_actu() == cfg.bbl_CLE_USB_ANARCHIE:
chargement_livres = usb_charger_livres()
# DOKU_enregistrer_dans_tableur_html()
elif bbl_actu() == cfg.bbl_PERSO_ZIP:
chargement_livres = perso_zip_charger_livres()
# DOKU_enregistrer_dans_tableur_html()
else:
chargement_livres = charger_all_lvr()
# DOKU_enregistrer_dans_tableur_html()
global ouverture_biblio
if (chargement_livres == True) and (direkt == 'direkt'):
build_selektion()
ouverture_biblio = True
lire_livre_actuel("lire", direkt)
elif chargement_livres == True:
bn = bbl_nom()
nb_ref = len(all_lvr)
nb_prez = nb_livres_prezents()
nb_favo = nb_livres_favoris()
space = commun.du(bbl_folder())
# découper les messages vocaux permet leur création plus rapide
# et perturbent moins l'utilisateur en réduisant la durée
# des moments de silence
# "ouverture de la bibliothèque audiocité classiques"
masque1 = "bibliothèque {}"
msg1 = masque1.format(bn)
masque2 = "ouverture de la bibliothèque {}"
msg2 = masque2.format(bn)
infos.pdrNew( [ msg1, msg2] )
# "2601 références disponibles dont 8 présentes et accessibles immédiatement"
if bbl_actu() == cfg.bbl_CLE_USB_ANARCHIE:
masque1 = "{} éléments présents"
msg1 = masque1.format( nb_ref )
msg2 = msg1
infos.pdrNew( [ msg1, msg2] )
else:
if nb_prez > 0:
masque1 = "{} éléments dont {} présents, qui occupent {} méga octets"
msg1 = masque1.format( nb_ref, nb_prez, space )
masque2 = "{} références disponibles dont {} présentes et accessibles immédiatement"
msg2 = masque2.format( nb_ref, nb_prez )
infos.pdrNew( [ msg1, msg2] )
else:
masque1 = "{} éléments dont aucun présent"
msg1 = masque1.format( nb_ref )
masque2 = "{} références disponibles dont aucune téléchargée"
msg2 = masque2.format( nb_ref, nb_prez )
infos.pdrNew( [ msg1, msg2] )
# 12 livres sont notés dans les favoris
if nb_favo > 0:
if nb_favo == 1:
msg1 = "un livre en favori"
msg2 = "un seul livre a été enregistré comme favori"
else:
masque1 = "{} livres en favori"
msg1 = masque1.format( nb_favo )
masque2 = "{} livres sont notés dans les favoris"
msg2 = masque2.format( nb_favo )
infos.pdrNew( [ msg1, msg2] )
# "les livres présents occupent un espace de 92 méga octets"
if nb_prez > 0:
msg1 = ""
if nb_prez == 1:
masque2 = "le seul livre présent occupe un espace de {} méga octets"
elif nb_prez > 1:
masque2 = "les livres présents occupent un espace de {} méga octets"
msg2 = masque2.format( space )
infos.pdrNew( [ msg1, msg2] )
# vérifier dès maintenant l'espace libre
# et annoncer si insuffisant
espace_suffisant_aba()
# annoncer la bibliothèque ouverte
build_selektion()
ouverture_biblio = True
if REPRENDRE_ANNONCER == True:
lire_livre_actuel("annoncer")
else:
msg = "Pas de catalogue trouvé pour " + bbl_actu() + ", " + \
"veuillez choisir une autre bibliothèque"
infos.pdrNew(msg)
menu_changer_biblio()
def stats_fichiers():
""" stats tous fichiers """
def stats_fich1(la_liste):
""" infos sur medias, auteurs, ... """
# calculer durée (minutes) et taille (Mo) totales
taille_totale = 0
duree_totale = 0
dic_taille = {}
dic_duree = {}
for el in la_liste:
taille_el = float(el["p"])
taille_totale += taille_el
duree = el["d"]
find_h = duree.find("h")
if find_h > -1:
# on a un format 1h ou bien 1h03
heure = int(duree[0:find_h])
# ~ print("vérif " + duree)
if duree[(find_h + 1):] != '':
minutes = int(duree[(find_h + 1):])
else:
minutes = 0
la_duree = minutes + heure * 60
else:
la_duree = int(duree)
duree_totale += la_duree
dic_duree[str(100000 + la_duree) + el["n"]] = [el["d"], el["t"], el["a"]]
dic_taille[str(200000 + taille_el) + el["n"]] = [el["p"], el["t"], el["a"]]
# cf. doc_03
r = [taille_totale, duree_totale, dic_taille, dic_duree]
return r
def stats_sel_lvr():
""" statistiques sur fichiers url mp3 """
global sel_lvr
r = stats_fich1(sel_lvr)
stats_voir_save("sel_lvr", len(sel_lvr), r)
def stats_voir_save(titre, len_liste, r):
""" afficher résultats """
taille_totale = r[0]
duree_totale = r[1]
# dic_taille = r[2]
# dic_duree = r[3]
infos.m_g("========== Stats : " + str(len_liste) + " fichiers " + titre + " ==========")
taille_moyenne = int(taille_totale / len_liste)
taille_totale = int(taille_totale)
infos.m_g("taille totale = " + str(taille_totale) + " Mo")
infos.m_g(" moyenne = " + str(taille_moyenne) + " Mo")
infos.m_g(
" moyenne = " + str(taille_totale) + " / " + str(len_liste) + " = " + str(taille_moyenne) + " Mo")
infos.m_g("")
duree_moyenne = int(duree_totale / len_liste)
infos.m_g("durée totale (mn)= " + str(duree_totale) + " mn")
infos.m_g(" (h) = " + str(int(duree_totale / 60)) + " h")
infos.m_g(" (j) = " + str(int(duree_totale / 60 / 24)) + " j")
infos.m_g(" moyenne (mn)= " + str(duree_totale) + " / " + str(len_liste) + " = " + str(duree_moyenne) + " mn")
infos.m_g("")
stats_sel_lvr()
def trk_first():
""" aller au premier chapitre """
if mpc.trk_first():
aba_infos_go()
def trk_last():
""" aller au dernier chapitre """
if mpc.trk_last():
aba_infos_go()
def save_num4c_actuel(num4c):
""" sauvegarde dans py_user.ini
du champ "n" (num4c) du livre actuel + bibliothèque actuelle.
ex : num4c_cle_usb_anarchie=0012
<=> le champ "n" du livre actuel de la biblio cle_usb_anarchie est 0012
ex : num4c_litteaudio=0244
<=> le champ "n" du livre actuel de la biblio litteaudio est 0244
valeur lue par la fonction get_num4c_actuel()
"""
if nb_livres_total() == 0:
return False
var1 = "aba_num4c_" + bbl_actu()
val1 = num4c + "|" + infos.jour_heure_actu()
infos.ini_set(var1, val1)
def get_num4c_actuel():
""" renvoie le num4c du livre actuel
de la bibliothèque actuelle """
# vérifier que le fichier .ini renvoie un num4c valide
# càd dans sel_n2i.keys()
num_horo = infos.ini_get("aba_num4c_" + bbl_actu(), "0001|")
num4c = num_horo.split("|")[0]
global sel_n2i
if num4c in sel_n2i.keys():
return num4c
else:
# on renvoie le champ "n" de la 1ère ligne de sel_lvr (indice 0)
if nb_livres_total() > 0:
global sel_lvr
infos.m_g("ERR num4c, 1er trouvé = {}".format(lv_num4c(0)))
# infos.m_g("ERR : 3. get_num4c_actuel, dim sel_lvr[] = {}".format(len(sel_lvr)))
return lv_num4c(0)
else:
return "sel_lvr vide"
def slct_auteur(): # OK
""" lit seulement les livres du même auteur """
def get_books():
""" liste les livres favoris dans la biblio actuelle """
# num4c_trouves = infos.ini_get("aba_favoris_" + bbl_actu(), "")
# -------------------------------------------------------------
# 0. rechercher le livre actuel
# 1. rechercher l'auteur du livre actuel
# 2. copier build_selektion pour trouver les livres du même auteur
# -------------------------------------------------------------
auteur_actuel = lv_auteur()
infos.pdrNew("Sélection des livres de l'auteur actuel, " + auteur_actuel)
# rechercher dans all_lvr le même auteur
t_meme_auteur = [] # Tableau Même Auteur
n_view = 5
mask = "{}. auteur {}, livre {}, titre {}"
for lv in all_lvr:
if auteur_actuel == lv["a"]:
t_meme_auteur.append(lv["n"])
n_view -= 1
if n_view > 0:
infos.m_g(mask.format(n_view, lv["a"], lv["n"], lv["t"]))
if len(t_meme_auteur) > 0:
num4c_trouves = ",".join(t_meme_auteur)
else:
num4c_trouves = ""
return slct_get_build(num4c_trouves)
if nb_livres_total() == 0:
choisir_autre_biblio_svp()
return 0
# slct_auteur()
mpc.ferme_ton_clapet()
nb_found = get_books()
if nb_found == 0:
masque = "Aucun livre du même auteur pour la bibliothèque {}"
msg = masque.format(bbl_nom())
elif nb_found == 1:
masque = "Un seul livre de cet auteur pour la bibliothèque {}"
msg = masque.format(bbl_nom())
else:
masque = "{} livres de cet auteur pour la bibliothèque {}"
msg = masque.format(nb_found, bbl_nom())
infos.pdrNew(msg)
def slct_favoris(): # OK
""" lit seulement les livres favoris """
def get_books():
""" liste les livres favoris dans la biblio actuelle """
# selon le type de bibliothèque,
# on va chercher les favoris à deux (ou trois ?) endroits différents
# TODO :
# 1. clé usb
# --> les favoris sont stockés dans la clé usb
# 2. perso en ligne
# --> les favoris sont stockés sur la machine
# dans /home/pi, et pas /opt/jk2019 (car màj peut écraser les favoris)
# 3. gratuits en ligne
# --> les favoris sont stockés sur la machine
# dans /home/pi, et pas /opt/jk2019 (car màj peut écraser les favoris)
# selon le type de bibliothèque,
# on va chercher les favoris à deux (ou trois ?) endroits différents
# TODO :
# 1. clé usb
# --> les favoris sont stockés dans la clé usb
# 2. perso en ligne
# --> les favoris sont stockés sur la machine
# dans /home/pi, et pas /opt/jk2019 (car màj peut écraser les favoris)
# 3. gratuits en ligne
# --> les favoris sont stockés sur la machine
# dans /home/pi, et pas /opt/jk2019 (car màj peut écraser les favoris)
num4c_trouves = infos.ini_get("aba_favoris_" + bbl_actu(), "")
return slct_get_build(num4c_trouves)
if nb_livres_total() == 0:
choisir_autre_biblio_svp()
return 0
# slct_favoris()
mpc.ferme_ton_clapet()
nb_found = get_books()
if nb_found == 0:
masque = "Aucun livre dans les favoris pour la bibliothèque {}"
msg = masque.format(bbl_nom())
elif nb_found == 1:
masque = "sélection du seul livre inscrit dans la liste " + \
"des favoris pour la bibliothèque {}"
msg = masque.format(bbl_nom())
else:
masque = "sélection des {} livres favoris de la bibliothèque {}"
msg = masque.format(nb_found, bbl_nom())
infos.pdrNew(msg)
def slct_get_build(str_champs_n_trouves):
""" lance build_selektion(str_champs_n_trouves)
si str_champs_n_trouves pas vide, et
renvoie le nombre de livres trouvés dans str_champs_n_trouves
Est appelé par
slct_auteur(),
slct_favoris(),
slct_lecteur(),
slct_presents()
"""
# bn = bbl_nom()
if str_champs_n_trouves == "":
# infos.m_g("Aucun livre favori pour la biblio " + bn)
nb_trouves = 0
else:
lst_champs_n = str_champs_n_trouves.split(",")
nb_trouves = len(lst_champs_n)
if nb_trouves > 0:
# msg = "livres favoris : " + ", ".join(lst_champs_n)
# infos.m_g(msg)
build_selektion(lst_champs_n) # ICI, liste générée des livres sélectionnés
# else:
# msg = "Aucun livre favori dans la bibliothèque " + bn
# infos.m_g(msg)
return nb_trouves
def slct_presents(): # OK
""" lit seulement les livres téléchargés """
def get_books():
""" liste les livres présents dans la biblio actuelle
les livres présents sont les dossiers
présents dans chaque dossier biblio
/m/music/aba/audiocite
/m/music/aba/litteratureaudio
/m/music/aba/librivox_fr
/m/music/aba/librivox_de
/m/music/aba/vorleser
renvoie un int : nombre de livres présents,
soir le nb d'éléments de la liste lst_champs_n
"""
# un livre est présent si son dossier l'est dans /m/music/aba/audiocite
# si la biblio actuelle est "bib_audio_cite"
dossiers_num4c = commun.folders_simple_nom_seul(bbl_folder())
str_dossiers_num4c = ",".join(dossiers_num4c)
return slct_get_build(str_dossiers_num4c)
if nb_livres_total() == 0:
choisir_autre_biblio_svp()
return 0
# slct_presents()
mpc.ferme_ton_clapet()
if bbl_actu() == cfg.bbl_CLE_USB_ANARCHIE:
# tous les livres sont présents pour bbl_CLE_USB_ANARCHIE
slct_tout("silent")
nb_found = nb_livres_total()
else:
nb_found = get_books()
if nb_found == 0:
masque = "Aucun livre présent sur la clé pour la bibliothèque {}"
msg = masque.format(bbl_nom())
elif nb_found == 1:
masque = "sélection du seul livre présent sur la clé pour la bibliothèque {}"
msg = masque.format(bbl_nom())
else:
masque = "sélection des {} livres présents sur la clé pour la bibliothèque {}"
msg = masque.format(nb_found, bbl_nom())
infos.pdrNew(msg)
def slct_bannis():
""" lit seulement les livres favoris """
# TODO à continuer
pass
def slct_lecteur():
""" lit seulement les livres du lecteur actuel """
def get_books():
""" liste les livres du lecteur actuel dans la biblio actuelle """
lecteur_actuel = lv_lecteur()
infos.pdrNew("Sélection des livres du lecteur actuel, " + lecteur_actuel)
# rechercher dans all_lvr le même auteur
t_meme_lecteur = [] # Tableau Même Auteur
n_view = 5
mask = "{}.lecteur {}, livre {}, titre {}"
for lv in all_lvr:
if lecteur_actuel == lv["l"]:
t_meme_lecteur.append(lv["n"])
n_view -= 1
if n_view > 0:
infos.m_g(mask.format(n_view, lv["l"], lv["n"], lv["t"]))
if len(t_meme_lecteur) > 0:
num4c_trouves = ",".join(t_meme_lecteur)
else:
num4c_trouves = ""
return slct_get_build(num4c_trouves)
if nb_livres_total() == 0: # empêche le plantage si on est
choisir_autre_biblio_svp() # dans une bibliothèque sans livre (usb par exemple)
return 0
# slct_lecteur()
mpc.ferme_ton_clapet()
nb_found = get_books()
if nb_found == 0:
masque = "Aucun livre du même lecteur pour la bibliothèque {}"
msg = masque.format(bbl_nom())
elif nb_found == 1:
masque = "Un seul livre de ce lecteur pour la bibliothèque {}"
msg = masque.format(bbl_nom())
else:
masque = "{} livres de ce lecteur pour la bibliothèque {}"
msg = masque.format(nb_found, bbl_nom())
infos.pdrNew(msg)
def filtrer_bruts(champ, valeur):
""" renvoie une list de num4c pour le lecteur lecteur
"""
global all_lvr
renvoyer = []
for i in all_lvr:
if i[champ] == valeur:
renvoyer.append(i["n"])
return renvoyer
def slct_genre():
""" lit seulement les livres du genre actuel """
# TODO à continuer
pass
def slct_tout(silent = ""):
""" réinitialise la sélection """
if nb_livres_total() == 0:
choisir_autre_biblio_svp()
return 0
build_selektion()
masque = "sélection des {} livres de la bibliothèque {}"
if silent == "":
msg = masque.format(nb_livres_total(), bbl_nom())
infos.pdrNew(msg)
def wget_spider_taille(url):
""" connaître la taille d'un fichier à télécharger """
# cf. doc_02
# utiliser wget --spider "http://www.litteratureaudio.org/mp3/Emile_Zola_-_La_debacle_P1.zip"
# ...
# Taille : 405411018 (387M) [application/zip]
# Le fichier distant existe
# ...
cmd = "wget --spider " + url + " 2> /tmp/spider.txt"
r = mpc.sub_proc(cmd)
with open("/tmp/spider.txt", "r") as f:
lignes = f.readlines()
for i in lignes:
if i.startswith("Taille : "):
x = i.replace("Taille : ", "")
y = x.split(" ")
taille = y[0]
cmd = "rm /tmp/spider.txt"
r = mpc.sub_proc(cmd)
return taille
return 0
def ze_indice(num4c):
""" indice de sel_lvr[] pour le num4c donné """
global sel_n2i
# num4c peut être égal à 'sel_lvr est vide'
# si la biblio est vide (usb par exemple)
return sel_n2i[num4c]
def ze__indice_actuel():
""" indice de sel_lvr[] pour le num4c actuel """
return ze_indice( get_num4c_actuel() )
def zero_on(s):
""" formate un num4c sur 4 caractères """
# inverse de zero_off()
# attention : s est une string
padder4 = "000" + str(s)
return padder4[-4:]
def zero_off(n):
""" enlève les 0 du début """
# inverse : zero_on
if len(str(n)) == 4:
n = int(n) + 20000 # 0307 + 20000 = 20307
n = n - 20000 # 20307 - 20000 = 307
return str(n) # 307
else:
return n
def dbg_var():
def header():
return """
<!DOCTYPE html>
<html>
<head>
<title>biblio """ + bbl_actu() + """[]</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://gangand.net/pp/projets/xavbox/xavbox.css">
<style>
html {
scroll-behavior: smooth;
}
body{
margin: 0;
padding: 0;
color: lightgrey;
background-color: black;
font-size: 1.11em;
position: relative;
}
h2 {
margin: 0 auto;
text-align: center;
}
a { text-decoration: none;
color: white;
}
a:link, a:visited {
text-decoration: none;
color: white;
}
.sticky1 {
position: sticky;
top: 0px;
right: 0px;
width: 600px;
/*
background: #222;
*/
opacity: 0.7;
}
a:hover {
color: white;
}
</style>
</head>
<body>
"""
def menu():
return """
<div class=\"sticky1\">
<table class=\"table_touches\">
<tr>
<td><a href="#top" >Accueil </a></td>
<td><a href="#sel_lvr" >sel_lvr[...] </a></td>
<td><a href="#sel_n2i" >sel_n2i{...} </a></td>
<td><a href="#all_lvr" >all_lvr[...] </a></td>
</tr>
</table>
</div>
"""
def footer():
return """</body>
</html>
"""
global all_lvr
p1 = dbg_var_gene(all_lvr, "all_lvr")
global sel_lvr
p2 = dbg_var_gene(sel_lvr, "sel_lvr")
global sel_n2i
p3 = dbg_var_sel_n2i(sel_n2i, "sel_n2i")
full_page = header() + \
"<a name='top'><h2>" + "Biblio " + bbl_actu() + "</h2></a>" + "<br>" + \
menu() + p2 + p3 + p1 + footer()
fichier = "dbg_var/" + bbl_actu() + ".html"
with open(fichier, "w") as f:
f.write(full_page)
infos.m_g("{} créé".format(fichier))
def dbg_var_gene(tableau, titre, limite = 12):
""" enregistre les variables all_lvr[], sel_lvr[]
et sel_n2i{} dans un fichier dbg_var_all_lvr.html
pour bien comprendre leur interaction
"""
def td(s):
return "<td>" + str(s) + "</td>"
n = 0
corps = ""
for i in tableau:
ligne = \
" <tr>" + td(str(n)) + \
td(i["n"]) + td(i["y"]) + td(i["d"]) + td(i["p"]) + td(i["l"]) + \
td(i["a"]) + td(i["t"]) + \
"<td><a title=\"" + str(i["u"]) + "\">URIs</a></td>" + \
"<td><a title=\"" + str(i["f"]) + "\">fiche info</a></td>" + \
td(i["x"]) + \
td(i["type_url"]) + \
" </tr>"
n += 1
corps = corps + ligne + "\n"
if n == limite:
break
entete = \
"<tr>" + \
"<th><a title='indice tableau'>#</a></th>" + \
"<th><a title='num4c'>n</a></th>" + \
"<th><a title='type (roman, nouvelle, conte, ...)'>y</a></th>" + \
"<th><a title='durée'>d</a></th>" + \
"<th><a title='poids'>p</a></th>" + \
"<th><a title='lecteur'>l</a></th>" + \
"<th><a title='auteur'>a</a></th>" + \
"<th><a title='titre'>t</a></th>" + \
"<th><a title='URIs média'>u</a></th>" + \
"<th><a title='fiche information'>f</a></th>" + \
"<th><a title='extra'>x</a></th>" + \
"<th><a title='mp3 ou zip'>type_url</a></th>" + \
"</tr>"
corps = "<table class=\"table_touches\" style='margin: 15px auto 25px;'>" + "\n" + entete + corps + "\n" + "</table>"
aname = "<a name='" + titre + "'><h2>" + titre + "[...]</h2></a>" + "\n"
return aname + corps
def dbg_var_sel_n2i(tableau, titre, limite = 12):
""" contenu de sel_n2i
"""
def td(s):
return "<td>" + str(s) + "</td>"
n = 0
corps = ""
tk = list(tableau.keys())
tk.sort()
for i in tk:
rri = "sel_n2i[" + str(i) + "]"
ri = sel_n2i[i]
mask = "le livre de champ 'n' {} se trouve dans sel_lvr[{}]"
if n > 1:
mask = "le livre {} est sel_lvr[{}]"
signifie = mask.format(str(i), ri)
ligne = \
" <tr>" + \
td(rri) + \
td(ri) + \
td(signifie) + \
" </tr>"
n += 1
corps = corps + ligne + "\n"
if n == limite:
break
entete = \
"<tr>" + \
"<th>sel_n2i[num4c]</th><th>Index sel_lvr</th><th>Signification</th>" + \
"</tr>"
corps = "<table class=\"table_touches\" style='margin: 15px auto 25px;'>" + "\n" + entete + corps + "\n" + "</table>"
aname = "<a name='" + titre + "'><h2>" + titre + "{...}</h2></a>" + "\n"
return aname + corps
if __name__ == "__main__":
print("Bienvenue dans le module aba (Audiobooks gratuits en ligne)")