# Le site de Babelio

L'adresse pour accéder à Babelio est <https://www.babelio.com/>.

La page d'accueil de Babelio dit: "Babelio est un réseau social dédié aux livres et aux lecteurs.
Il permet de créer et d’organiser sa bibliothèque en ligne, d’obtenir des informations sur des œuvres,
de partager et d’échanger ses goûts et impressions littéraires avec d’autres lecteurs."

Il n'est pas besoin de s'identifier pour obtenir des informations.
(ce qui évite la gestion d'un acompte dans le plugin)

J'ai développé ce plugin de calibre d'après le plugin existant de VdF pour résoudre une série de
limitations que je rencontre:

1. Il n'y pas de référence (id) qui permet de retrouver le URL, ni de moyen d'ajouter un id depuis
  le url par manque des deux routines suivantes:
   * get_book_url : used by calibre to convert the identifier to a URL...
   * id_from_url : takes an URL and extracts the identifier details...
  OK
2. Dès que le contenu de Babelio est remonté, TOUTE l'information est traduite en utf8,
  TOUS les outputs (logs...) et les inputs (ce qui est lu sur le site...) sont en utf8...
  les multiples conversions me rendent le code confus
  OK pour __init__.py
3. un seul matches même si deux livres répondent à la recherche
  OK
4. la compatibilité avec python 2.x me semble obsolète et perturbant.
  OK pour __init.py
5. Identify() devrait être invoqué avec NAME_ID puis ISBN et si ça marche pas
  avec titre + auteur... titre seul.
  OK
6. un config.py est OK mais je préfère utiliser le config intégré, bien suffisant.
  OK
7. Babelio donne dans le titre le nom de la série et son n° de tome (ordre dans la série),
  je vais essayer de l'introduire (et vérifier que toutes mes séries y répondent...)

8. Je préfère nettement les commentaires en HTML et beautifulsoup (utilisé dans calibre par ailleurs)
  OK pour __init__.py
9. J'ai horreur de ce langage de recherche et substitution (expression régulière) auquel
  je ne comprends pratiquement rien... enfin, un tout petit peu quoi!
  OK pour __init__.py

Je n'ai pas retrouvé trace de VdF... Son travail , sous licence GPL V3 peut être modifié.
J'aurais voulu le contacter avant de publier mon travail, basé sur le sien, sur mobileread...
De toute manière, il restera visible sur github <https://github.com/lrpirlet/cal-babelio_db>

Ce travail est open source... J'ai pris du plaisir à l'écrire, si vous pensez que ce travail
  doit être rétribué, choisissez une association caritative et donnez leur, un peu, avec une
  mention comme "Thanks to Louis Richard" ou "Merci à Louis Richard" ou quelque chose de
  similaire dans votre langue. Cela renforcera ma réputation (non publiée)...

Quelle charité ? Mes pires cauchemars impliquent le feu, donc je donne pour les enfants
  profondément brûlés... Ma femme a peur du cancer donc elle donne à la recherche sur le cancer,
  nous nous sentons tous les deux mal à l'aise face aux gens qui meurent de faim donc nous donnons
  au "resto du Cœur"...

Malheureusement, il y a toujours quelqu'un qui a besoin d'aide et qui ne pourra pas rembourser
(sauf peut-être avec une pensée pour l'inconnu qui l'a aidé). Il y a donc l'embarras du choix.

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Source sur github: <https://github.com/lrpirlet/cal-babelio_db>

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

ajout d'une série de routine dans __init__.py. Elles ne sont pas dans la class Babelio.

def urlopen_with_retry(log, dbg_lvl, br, url, rkt, who):
    '''
    this is an attempt to keep going when the connection to the site fails for no (understandable) reason
    "return (sr, sr.geturl())" with sr.geturl() the true url address of sr (the content).
    '''
def ret_soup(log, dbg_lvl, br, url, rkt=None, who=''):
    '''
    Function to return the soup for beautifullsoup to work on. with:
    br is browser, url is request address, who is an aid to identify the caller
    rkt list of arguments for a POST request, if rkt is None, the request is GET
    return (soup, url_ret)
    '''
def verify_isbn(log, dbg_lvl, isbn_str, who=''):
    '''
    isbn_str est brute d'extraction... la fonction renvoie un isbn correct ou "invalide"
    Notez qu'on doit supprimer les caractères de séparation et les caractères restants apres extraction
    et que l'on traite un mot de 10 ou 13 caractères.

    isbn_str is strait from extraction... function returns an ISBN maybe correct ...or not
    Characters irrelevant to ISBN and separators inside ISBN must be removed,
    the resulting word must be either 10 or 13 characters long.
    '''
def ret_clean_text(log, dbg_lvl, text, swap=False, who=''):
    '''
    for the site search to work smoothly, authors and title needs to be cleaned
    we need to remove non significant characters and remove useless space character...
    Calibre per default presents the author as "Firstname Lastname", cleaned to
    become "firstname lastname"  Noosfere present the author as "LASTNAME Firstname",
    let's get "Firstname LASTNAME" cleaned to "firstname lastname"
    '''
impose une version de calibre minimum: minimum_calibre_version = (6, 3, 0)

Dans __init__.py enlève les appels à encode() et à decode(),
documente toutes les fonctions et méthodes. Ainsi, Visual Studio me montre dans une bulle
toutes leurs informations relatives.
introduis une série de log pour mieux suivre le flot du code.
------------------------------------------------------------------
introduis
  __copyright__ = '2021, Louis Richard Pirlet using VdF work as a base'
  ID_NAME = 'bbl_id'
  def get_book_url(self, identifiers):
        '''
        get_book_url : used by calibre to convert the identifier to a URL...
        return an url if nsfr_id exists and is valid
        '''
  def id_from_url(self, url):
        '''
        id_from_url : takes an URL and extracts the identifier details...
        '''
  redéfini l'accès a Babelio en utilisant ret_soup(), verify_isbn() et ret_clean_text()
  enlève du code non utilisé ou jamais atteint
  supprime le processing des cookies (le site répond aussi bien...)
--------------------------------------------------------------------
Le plugin est vraiment très lent ce soir... Ajoute des timers pour déterminer où est le ralentissement.
Il semble qu'accéder à l'image peut être extrêmement long quand cette image n'est pas sur le site de Babelio..
En fait, accéder à l'image dans la méthode parse_cover() de worker.py n'est pas vraiment utile...
On peut voir que l'image est invalide au moment d'en faire le téléchargement...
Supprimer ce code de vérification accélère beaucoup le plugin... sans nuire aucunement à la qualité.
--------------------------------------------------------------------
retravaille identify() pour réagir sur les identifiers avant de réagir sur tire/auteurs
ça marche à peu près, faudra y revenir... (mais ne sera plus documenté)
--------------------------------------------------------------------
Introduit les messages de debug sélectif... ce qui implique de modifier le config.py...
je fini par le supprimer pour implémenter la configuration interne... Ceci me permet de documenter
la configuration du plugin Babelio.. la souris survole un champs et la bulle t'éclaire :)
--------------------------------------------------------------------
documente les méthodes dans worker.py
Améliore la recherche quand le titre est trop imprécis... essayer œdipe roi sans auteur défini (et sans id...)
--------------------------------------------------------------------
Limite sévèrement le nombre d'accès au site Babelio.com pour éviter de voir l'accès au site interdit
(le site répond time-out !pendant une semaine! ) quand un trop grand nombre de requêtes est formulé...
--------------------------------------------------------------------
documente et nettoie __init__.py
introduit une section test du plugin... l'algorithme de détection des auteurs doit être revu...
    [worker 1] self.url            :  https://www.babelio.com/livres/lePetitLitterairefr-Fiche-de-lecture--Limonov-dEmmanuel
    ...

    ****************************** Relevance: 1 ******************************
    Title               : Fiche de lecture : Limonov d'Emmanuel Carrère
    Author(s)           : Lepetitlittéraire.fr
    Tags                :  Réflexions  ,  Russe
    Languages           : fr
    Rating              : 4.5
    Identifiers         : Babelio:lePetitLitterairefr-Fiche-de-lecture--Limonov-dEmmanuel-Carrere/409829
    ...

    Author test failed. Expected: '{'emmanuel carrère'}' found '{'lepetitlittéraire.fr'}'
    ...
Introduit un fichier expliquant la licence, un readme.md pour github
--------------------------------------------------------------------
Damn it, cette section de test, m'énerve: le rapport effort de développement a la valeur du test est
nettement en faveur de laisser tomber le test...
La seule chose qu'il m'a apporté est le fait que j'avais oublié le "return bbl_tags" et donc les Tags
n'étaient jamais importé dans calibre... et honnêtement, c'est le manque de tags sur des titres
totalement vierges qui m'a fait comprendre le message du test... Il est probable que je pense
différemment que l'auteur du test. (on n'en parle plus...)
--------------------------------------------------------------------
Introduit Beautifulsoup in worker.py
la différence entre raw modifié et soup brute de fonderie est pour moi évidente... en plus
BeautifulSoup me semble plus simple
            # effect of raw being decoded to latin_1 inside calibre...
        #    rawbs=BS(raw, "html5lib")   (raw = raw.decode('latin-1', errors='replace') )
        #    self.log.info(self.who,"get details rawbs prettyfied :\n", rawbs.prettify())
            # resultat (court extrait...)
            # Poussé par lamour dune jolie femme, il simprovisera un moment professeur dans une école
        #    self.log.info(self.who,"get details soup prettyfied :\n", soup.prettify())
            # resultat (court extrait...)
            # Poussé par l’amour d’une jolie femme, il s’improvisera un moment professeur dans une école
--------------------------------------------------------------------
développe en parallèle du code basé sur raw un code basé sur soup...
Title, authors et rating sont juste une affaire de sélectionner le bon morceau de code HTML par select_one
avant d'extraire ce que je veux.
--------------------------------------------------------------------
Tags demande un rien de traitement en plus (select crée une liste de code HTML qu'il faut traiter dans une boucle)
metadata (isbn, éditeur, date de publication)demande un peu plus de boulot surtout pour la date (sous quel
format calibre veut-il cette date?)... mais je peux laisser tomber la méthode qui traite la date...
--------------------------------------------------------------------
cover address n'est pas difficile si on l'extrait de <head>: le url est complet... j'ose esperer que le head de tous
les livres de babelio contiennent cette info dans le head..
Comments... Si je n'extrais QUE le texte (par comments_soup.text), je pers la structure: retour à la ligne par exemple.
Donc je décide de prendre le code html, le serialiser par un bbl_comments.encode('ascii','xmlcharrefreplace')
ET de modifier __init__ pour imposer:   has_html_comments = True
maintenant on a, et les accents, et la structure... ouais.
--------------------------------------------------------------------
OK, j'aime calibre pour faire des catalogues calibre de ebooks. Je les envoie par email... (pour me les faire offrir ou
pour en vanter la valeur). Les commentaires doivent donc contenir un référence que l'on peut suivre sur internet...
Je veux donc mettre dans les commentaires l'adresse babelio de la page du livre. J'aurais mis l'adresse de la couverture si
elles avaient été plus grandes et si elle avit été locale a babelio...
Tant qu'a faire, je me dis qu'un titre est bien plus joli (pretty).
j'implémente la référence et le titre avec un boolean dans le config pour un commentaire semblable a avant ou joli...
---------------------------------------------------------------------
Ca marche pas... jusqu'au moment ou je réalise que 'Pretty_wanted' dans Option est le nom sous lequel on enregistre
la valeur et que ce nom doit être le même que dans la méthode with_pretty_comments(self) (ou je l'avais écrit Pretty_wnated)
pas d'erreur mais pas de réaction...
---------------------------------------------------------------------
clean up
---------------------------------------------------------------------
Tient compte que tome peut être écrit Tome dans un titre/série
---------------------------------------------------------------------
adapte babelio_db pour pouvoir mettre l'ancien babelio et celui-ci en parallèle:
le nom devient babelio_db et son id sera bbl_id...
Ceci dit, metter et babelio et babelio_db en service est le plus sur moyen d'etre mis en quarantaine pour detection DoS
---------------------------------------------------------------------
modifie identify() pour mieux rechercher les livres en cherchant sur babelio le titre et en le comparant
avec le titre demandé... En l'absence d'auteurs, cela permet de trier les titres que l'on garde
(on veut eviter un DoS, et la mise en quarantaine...)
---------------------------------------------------------------------
introduit un délais dans ret_soup() de telle manière à éviter d'être expulsé de babelio
(on évite la détection DoS - Denial of Service qui sature un site par un grand nombre de request)
En fait, Chaque request doit durer 1 seconde et quand N workers travaillent en parallèle, je fixe
le delais à N et demare chaque worker à une seconde d'intervalle.
J'ai pu lancer l'update de 250 titres sans plus de problèmes...
---------------------------------------------------------------------
modifie identify() pour mieux rechercher les livres en associant aussi l'auteur dans le choix des 12 livres
maximum à sélectionner.
---------------------------------------------------------------------
clean up: enlève les messages de debug, simplifie le code en evitant des sauts inutiles dans les méthodes...
(pourquoi soumettre un titre de valeur None à une routine qui retourne None???)
corrige des erreurs dues à des inconsistances sur le site de babelio...
---------------------------------------------------------------------
la version de babelio_db est (0,5,0)
---------------------------------------------------------------------
repair 2 occurences of misspelled isnumeric instead of isnumeric()...
leading to an uncrontroled crash in the rare occurence of a "/" in the editor field...
---------------------------------------------------------------------
improved series_seq algoritm for when tome is both in the title tring and in the series field
---------------------------------------------------------------------
refactor authors extraction, to avoid finding a translator as an author... The authors
is now used to better extract the book title...
refactor title, series series_seq , now the presence of a link to series directs the search
of series and series_seq...
Added  a link in the comments to display the series url... this is also controlled by
"autorise un commentaire etendu" in the plugin configuration.
This MAY change the title of some book as assigned before.
---------------------------------------------------------------------
Added a class decorator to keep a minimum of TIME_INTERVAL seconds between each access to babelio.com.
rate_limit() from calibre.ebooks.metadata.sources.search_engines provides the delay
using a locked file containing the access time... maintenance of this resource
is hidden in a context manager implementation.
  @contextmanager
  def rate_limit(name='test', time_between_visits=2, max_wait_seconds=5 * 60, sleep_time=0.2):
this Un_par_un(objet) class also records when, by who and what url is accessed for each book.

result.log shows the log of the matadata download for author='henri vernes' and title 'jaune'...
this would have been a sure ban before rate_limit... note that I pushed the the timeout to 45 seconds
after first match is found in the configure metadata download..
(pour la petite histoire, Bob Morane a affronté l'ombre jaune en de multiples aventures :) )
---------------------------------------------------------------------
La version est maintenant 0.6.0... cette version fonctionne sous calibre 6.3.0 et +
---------------------------------------------------------------------
Correct a problem with name of the series when it contains a "-" character... reshuffle some instructions
to get a better title for selection of the series index
---------------------------------------------------------------------
add a break in a loop to make sure that the first match is taken (make sure that bbl_series_seq is
populated with 1 and not by 17 would the serie contain 17 items)
---------------------------------------------------------------------
add the possibility to display the popularity of the book. If enabled, the pluugin will
display a title "Popularité" under what the number of rating and the rating mean will be shown
version number is now 0.7.0
---------------------------------------------------------------------
correct a bug when serie is terminated by the character 's'
push it to version 0.8.0
---------------------------------------------------------------------
correct a possible bug if title contains ':'
correct a bug if serie contains 'Tome :' rather than 'tome :'
---------------------------------------------------------------------
correct a crash when the comments from Babelio are NOT crectly 'alligned':
I create an empty html file then append the extracted segment BeautifulSoup will then correct it
---------------------------------------------------------------------
correct a condition check that prevented optimization when babelio_id was present...
detected when babelio_id was valid and title was "None" (that is "unknown")
version is 0.8.3
---------------------------------------------------------------------
Babelio.com changed the way to access the search page. It used to work with a GET command,
It now works with a POST command.
I decided to avoid loading more than one page of search to try and avoid banning (this means 10
books instead of 12 and rely on Babelio sorting the most significant book)
----------------------------------------------------------------------
Test version 0.8.4, needs cleaning
---------------------------------------------------------------------