Register Guidelines E-Books Today's Posts Search

Go Back   MobileRead Forums > E-Book Software > Calibre > Plugins

Notices

Reply
 
Thread Tools Search this Thread
Old 10-18-2025, 05:21 AM   #46
lrpirlet
Zealot
lrpirlet began at the beginning.
 
Posts: 104
Karma: 40
Join Date: Mar 2020
Location: Belgium (sorry, I am from the Walloon side of the country and I speak french only)
Device: PW3, Kobo Libra H2O
I did modify and upload version 1.0.0.

This version provide an adapted algorithm for parse_rating after Babelio.com change
lrpirlet is offline   Reply With Quote
Old 10-18-2025, 12:56 PM   #47
titaf
Junior Member
titaf began at the beginning.
 
titaf's Avatar
 
Posts: 3
Karma: 10
Join Date: Jun 2016
Location: France
Device: Kobo Aura H2O Edition 2 v1
Hello,
Thank you for this work.
Unfortunately, I can't get the grades.
Message from Calibre (in French):
calibre, version 8.13.0
Babelio Notes:
Recherche des Notes et des Votes sur le site Babelio pour 1 livre dont 0 ligne est marquée comme non mise à jour
Titre : La Maison des silences
Auteur(s) ['Donato Carrisi']:
Accès à https://www.babelio.com/livres/Carri...lences/1883375
babelio.com semble ne pas avoir des votes et/ou des notes
distribution dans le temps des accès à babelio.com
Sat Oct 18 18:55:27 2025 accès à https://www.babelio.com/livres/Carri...lences/1883375

Thank you
titaf is offline   Reply With Quote
Advert
Old 10-18-2025, 01:15 PM   #48
titaf
Junior Member
titaf began at the beginning.
 
titaf's Avatar
 
Posts: 3
Karma: 10
Join Date: Jun 2016
Location: France
Device: Kobo Aura H2O Edition 2 v1
**** Correction to the previous message sent too quickly: I hadn't updated the Babelio Notes plugin.
After updating both Babelio plugins, everything works fine.
Sorry, and thanks again.
titaf is offline   Reply With Quote
Old 10-24-2025, 06:23 AM   #49
lrpirlet
Zealot
lrpirlet began at the beginning.
 
Posts: 104
Karma: 40
Join Date: Mar 2020
Location: Belgium (sorry, I am from the Walloon side of the country and I speak french only)
Device: PW3, Kobo Libra H2O
Smile fine

Quote:
Originally Posted by titaf View Post
****
After updating both Babelio plugins, everything works fine.
Thanks to report it well working (for now)…
lrpirlet is offline   Reply With Quote
Old 02-03-2026, 01:45 PM   #50
Leilu
Enthusiast
Leilu began at the beginning.
 
Posts: 33
Karma: 10
Join Date: Feb 2023
Device: Kindle Oasis 3 / Kobo Libra 2
Bonjour,

Ca ne fonctionne plus depuis quelques temps, que je copie le babelio_id manuellement ou que je laisse le champs vide.

Voici les logs:
https://www.pastebin.fr/019c24d1-129...a-b4c6d2acbaa7
Leilu is offline   Reply With Quote
Advert
Old 02-03-2026, 04:05 PM   #51
titoum
Junior Member
titoum began at the beginning.
 
Posts: 2
Karma: 10
Join Date: Feb 2026
Device: ipad
Quote:
Originally Posted by Leilu View Post
Bonjour,

Ca ne fonctionne plus depuis quelques temps, que je copie le babelio_id manuellement ou que je laisse le champs vide.

Voici les logs:
https://www.pastebin.fr/019c24d1-129...a-b4c6d2acbaa7
hello,

fait un rollback vers la version calibre-64bit-8.16.2 et ca fonctionne de nouveau...

un grand merci pour ce plugin mais est-ce qu il serait possible que si on fournit l'isbn ou le babelio_id -> le plugin fetch direct les info sans regarder le reste?
titoum is offline   Reply With Quote
Old 02-04-2026, 12:48 PM   #52
druss67
Connoisseur
druss67 can name that song in three notesdruss67 can name that song in three notesdruss67 can name that song in three notesdruss67 can name that song in three notesdruss67 can name that song in three notesdruss67 can name that song in three notesdruss67 can name that song in three notesdruss67 can name that song in three notesdruss67 can name that song in three notesdruss67 can name that song in three notesdruss67 can name that song in three notes
 
Posts: 80
Karma: 24492
Join Date: Jul 2013
Location: France
Device: Kindle 4, PBk Lux 2, PBk Lux 3, K Aura, K Libra H2O, K Libra2
Salut,

j'ai corrigé le plugin, ça fonctionne chez moi en tout cas sur Calibre 9.1.
je ne sais pas si je pouvais, si jamais ça pose problème je le retire.

slts,
Druss67
Attached Files
File Type: zip Babelio_db_1.0.1_fix_calibre9.zip (335.6 KB, 74 views)
druss67 is offline   Reply With Quote
Old 02-06-2026, 01:44 AM   #53
lktr45
Zealot
lktr45 knows the difference between 'who' and 'whom'lktr45 knows the difference between 'who' and 'whom'lktr45 knows the difference between 'who' and 'whom'lktr45 knows the difference between 'who' and 'whom'lktr45 knows the difference between 'who' and 'whom'lktr45 knows the difference between 'who' and 'whom'lktr45 knows the difference between 'who' and 'whom'lktr45 knows the difference between 'who' and 'whom'lktr45 knows the difference between 'who' and 'whom'lktr45 knows the difference between 'who' and 'whom'lktr45 knows the difference between 'who' and 'whom'
 
Posts: 137
Karma: 10280
Join Date: Oct 2016
Device: none
Merci druss67, fonctionne aussi avec la V9.1
lktr45 is offline   Reply With Quote
Old 02-06-2026, 08:52 AM   #54
lrpirlet
Zealot
lrpirlet began at the beginning.
 
Posts: 104
Karma: 40
Join Date: Mar 2020
Location: Belgium (sorry, I am from the Walloon side of the country and I speak french only)
Device: PW3, Kobo Libra H2O
J'y travaille...

Quote:
Originally Posted by Leilu View Post
Bonjour,

Ca ne fonctionne plus depuis quelques temps, que je copie le babelio_id manuellement ou que je laisse le champs vide.

Voici les logs:
https://www.pastebin.fr/019c24d1-129...a-b4c6d2acbaa7
Merci pour ces log, il semble que la version 9 a changé quelque chose qui rend la ligne 239 de worker.py invalide.
Code:
bbl_comments = bbl_comments.encode('ascii','xmlcharrefreplace')     # et on serialize le tout
en fait cette ligne de code n'est PAS correcte dans l'environnement beautifulsoup (bs4), mais elle fonctionnait sous les versions préalable tout en corrigeant un problème intermittent.

la solution présentée par druss67:
Code:
 bbl_comments = bbl_comments.encode('ascii', errors='xmlcharrefreplace').decode('ascii')     # serialize (bs4.encode signature changed; keep safe ASCII HTML)
me surprend encore plus car c'est l'argument errors='xmlcharrefreplace' qui est illegal dans un contexte beautifulsoup

Je vais voir ce que je peux faire, d'autant que le même problème s'est développé (pour la même raison) pour le plugin de noosfere...

Réparé: plutôt que de sérialiser avec un encode, j'ai utilisé str pour le même résultat compatible avec calibre versions 9 et plus anciennes,
Code:
bbl_comments = str(bbl_comments)

Last edited by lrpirlet; 02-06-2026 at 11:51 AM. Reason: corrigé
lrpirlet is offline   Reply With Quote
Old 03-22-2026, 05:38 PM   #55
unbreak51
Member
unbreak51 began at the beginning.
 
Posts: 15
Karma: 10
Join Date: Sep 2021
Device: Kobo
Salut salut,

Il y a un nouveau soucis avec babelio mais je ne suis pas sur qu'il y ait une solution...
En gros, dès que j'utilise le plugin je suis ban de babelio. J'étais ban hier. Tout à l'heure, j'ai pu accéder au site, donc j'ai tenté de récupérer quelques métadonnées et j'ai été de bouveau ban instanément. Si de tente d'ouvrir babelio en utilisant le wifi de mon tel, ça fonctionne.
J'obtiens désormais : ERR_CONNECTION_TIMED_OUT....

Spoiler:
ApplicationPaletteChange event ignored
Using calibre Qt style: True
calibre Journal de débogage
calibre 8.16.2 embedded-python: True
Windows-10-10.0.19045-SP0 Windows ('64bit', 'WindowsPE')
('Windows', '10', '10.0.19045')
Python 3.11.14
Windows: ('10', '10.0.19045', 'SP0', 'Multiprocessor Free')
Interface language: fr
EXE path: C:\Program Files\Calibre2\calibre-debug.exe
Successfully initialized third party plugins: Gather KFX-ZIP (from KFX Input) (2, 29, 0) && Package KFX (from KFX Input) (2, 29, 0) && Babelio Notes (6, 0, 0) && Babelio_db (1, 1, 0) && Find Duplicates (1, 10, 10) && KFX metadata reader (from KFX Input) (2, 29, 0) && From KFX (2, 29, 0) && KFX Input (2, 29, 0) && Set KFX metadata (from KFX Output) (2, 18, 0) && KFX Output (2, 18, 0) && Reading List (1, 15, 7)
calibre 8.16.2 embedded-python: True
Windows-10-10.0.19045-SP0 Windows ('64bit', 'WindowsPE')
('Windows', '10', '10.0.19045')
Python 3.11.14
Windows: ('10', '10.0.19045', 'SP0', 'Multiprocessor Free')
Interface language: fr
EXE path: C:\Program Files\Calibre2\calibre-debug.exe
Successfully initialized third party plugins: Gather KFX-ZIP (from KFX Input) (2, 29, 0) && Package KFX (from KFX Input) (2, 29, 0) && Babelio Notes (6, 0, 0) && Babelio_db (1, 1, 0) && Find Duplicates (1, 10, 10) && KFX metadata reader (from KFX Input) (2, 29, 0) && From KFX (2, 29, 0) && KFX Input (2, 29, 0) && Set KFX metadata (from KFX Output) (2, 18, 0) && KFX Output (2, 18, 0) && Reading List (1, 15, 7)
QPA platform: windows
devicePixelRatio: 1.0
logicalDpi: 96.0 x 96.0
physicalDpi: 81.28 x 80.68235294117646
[0.00] Starting up...
[0.00] Showing splash screen...
[1.22] splash screen shown
[1.22] Initializing db...
[35.69] db initialized
[35.69] Constructing main UI...
[46.50] GUI main window shown
[47.16] main UI initialized...
[47.16] Hiding splash screen
[47.16] splash screen hidden
[47.16] Started up in 47.16 seconds with 28971 books
DEBUG: 0.0 Metadata sources cache was recently updated not updating again
Job: 0 Téléchargement des métadonnées pour 3 livres finished
Starting job: Téléchargement des métadonnées pour 3 livres
Download complete, with 3 failures

[360.05] Shutdown starting...
[362.58] Shutdown complete, quitting...

Je suis le seul à qui ça arrive ?

Va falloir se tourner vers booknode

Edit : j'ai récupéré l'accès à Babelio, j'ai renseigné manuellement le babelio_id avant, j'ai lancé une seule récupération de métadonnée et je suis de nouveau ban.

Last edited by unbreak51; 03-23-2026 at 07:32 PM.
unbreak51 is offline   Reply With Quote
Old 03-28-2026, 06:45 AM   #56
lrpirlet
Zealot
lrpirlet began at the beginning.
 
Posts: 104
Karma: 40
Join Date: Mar 2020
Location: Belgium (sorry, I am from the Walloon side of the country and I speak french only)
Device: PW3, Kobo Libra H2O
Désolé C'est la politique de Babelio

Quote:
Originally Posted by unbreak51 View Post
Salut salut,
En gros, dès que j'utilise le plugin je suis ban de babelio.
J'obtiens désormais : ERR_CONNECTION_TIMED_OUT....
Timeout est ce que te signale le programme de ton ordi quand le site ne te répond pas (soit parce qu'inaccessible soit parce qu'il refuse de répondre).

C'est un choix de Babelio... Peut être refusent ils de répondre quand la pub n'est pas publiée.... De nouveau, c'est leur choix et ils assument les conséquences.

En ce qui me concerne, Babelio n'existe plus.

SI VRAIMENT, j'ai besoin de renseignement sur un bouquin, j'y vais en mode interactif, je copie/paste les infos dont j'ai besoin... Mais j'ai tendance a voir ailleur.

Quote:
Va falloir se tourner vers booknode
J'ai la même réaction, en fait ça me rappelle: Paroles de « Tu veux ou tu veux pas ? » de Marcel Zanini ... la fin est ma conclusion.
lrpirlet is offline   Reply With Quote
Old 03-29-2026, 04:45 PM   #57
unbreak51
Member
unbreak51 began at the beginning.
 
Posts: 15
Karma: 10
Join Date: Sep 2021
Device: Kobo
C'était quand même bien pratique le plugin ... C'est triste.
unbreak51 is offline   Reply With Quote
Old 05-27-2026, 06:47 AM   #58
titoum
Junior Member
titoum began at the beginning.
 
Posts: 2
Karma: 10
Join Date: Feb 2026
Device: ipad
aide via l'IA...

Quote:
Originally Posted by lrpirlet View Post
En ce qui me concerne, Babelio n'existe plus.

SI VRAIMENT, j'ai besoin de renseignement sur un bouquin, j'y vais en mode interactif, je copie/paste les infos dont j'ai besoin... Mais j'ai tendance a voir ailleur.
le plugin fonctionne tjs tres bien et un grand merci a toi pour cela

j'ai poussé le truc un peu plus loin pour moins m'embêter

-> https://aistudio.google.com/prompts/new_chat

je lui donne le prompt suivant:

here is a python script, please load it so i can use it for the next prompt:
Code:
import os
import re
import json
import requests
import concurrent.futures
from google import genai
from google.genai import types

# ==============================================================================
# CONFIGURATION (Edit these values)
# ==============================================================================

GEMINI_API_KEY = "xxx"
MODEL_NAME = "gemma-4-26b-a4b-it"  # Fast and cost-efficient

SYSTEM_INSTRUCTION = (
    "You are a professional librarian specialized in French literature. "
    "Your task is to identify books from text and provide accurate metadata in JSON format. "
    "Always prioritize 13-digit ISBNs and French edition details."
)

TARGET_DIR = r'D:\book\rename'  

# Execution Modes:
# - "GENERATE_BAT": Generates a ready-to-use "rename_books.bat" inside TARGET_DIR
# - "LIVE_RENAME": Renames the files directly on your drive
# - "DRY_RUN": Prints what changes would occur without modifying any files
MODE = "GENERATE_BAT"  

# Number of parallel workers (5 is usually a safe default to avoid rate limits)
MAX_WORKERS = 5  


# Setup Gemini Client (Thread-safe)
client = genai.Client(api_key=GEMINI_API_KEY)


# ==============================================================================
# CORE LOGIC
# ==============================================================================

def validate_book_match(clean_bookname, parsed_data):
    """
    Extracts key identifying words from the cleaned filename
    and verifies they appear in the AI's resolved target page title.
    """
    target_title = str(parsed_data.get("exact_title_on_source_page", "")).lower()
    resolved_title = str(parsed_data.get("title", "")).lower()
    
    words = re.findall(r'\b[a-zA-Z]{4,}\b', clean_bookname.lower())
    
    ignored_words = {
        "tome", "volume", "french", "edition", "francais", "français", 
        "epub", "pdf", "book", "t01", "t02", "t03", "t04", "t05", "cbz"
    }
    keywords = [w for w in words if w not in ignored_words]
    
    if not keywords:
        keywords = [w for w in re.findall(r'\b[a-zA-Z]{3,}\b', clean_bookname.lower()) if w not in ignored_words]
    
    if not keywords:
        return True
    
    for kw in keywords:
        if kw in target_title or kw in resolved_title:
            return True
            
    return False

def query_llm(filename):
    """Sends the text to Gemini and attempts to extract JSON."""
    prompt = f"""
    do a websearch and Identify the book: "{filename}" (French Edition). 
    
    1. Search for the official series title and author.
    2. Identify the volume/tome number.
    3. Search for the 13-digit ISBN specifically (on Amazon.fr).
    4. Perform a secondary verification search using only the found ISBN on fnac.com to ensure it resolves strictly to this book and not a different series or volume released by the same publisher on the same date.
    5. Extract the literal title as it appears on the Amazon.fr page for the source URL you provide.
   
    Return ONLY a JSON object:
    {{
    "title": "clean serie title",
    "volume": "number or null",
    "author": "author name",
    "isbn": "13-digit ISBN",
    "verified_source": "URL",
    "exact_title_on_source_page": "exact text of the book title listed on the verified_source page"
    }}
    """
    
    try:
        grounding_tool = types.Tool(
            google_search=types.GoogleSearch()
        )
        
        response = client.models.generate_content(
            model=MODEL_NAME,
            contents=prompt,
            config=types.GenerateContentConfig(
                system_instruction=SYSTEM_INSTRUCTION,
                temperature=0.0,                    
                tools=[grounding_tool],             
                response_mime_type="application/json",
            ),
        )
        
        return json.loads(response.text)
        
    except Exception as e:
        print(f"  [!] Error during API call for {filename}: {e}")
        return None


def process_single_file(filename):
    """Processes metadata retrieval and path construction for a single file."""
    full_path = os.path.join(TARGET_DIR, filename)
    
    # Extra verification
    if os.path.isdir(full_path) or filename.startswith('.'):
        return None

    # Clean the filename prefixes
    bookname = filename
    for prefix in ["Zz", "zz", "ZZ"]:
        if bookname.startswith(prefix):
            bookname = bookname[len(prefix):]
            break

    # Dynamic extension separation
    base_name, extension = os.path.splitext(bookname)
    print(f"[*] Started processing: {base_name}")
    
    data = query_llm(base_name)

    if data:
        if not validate_book_match(base_name, data):
            print(f"  [!] Safety Validation Failed for: {base_name}")
            return None

        title = data.get("title")
        volume = data.get("volume")
        author = data.get("author")
        isbn = data.get("isbn")

        if not title:
            print(f"  [!] Missing title in AI result for: {base_name}")
            return None
        
        # Format filename
        if volume and str(volume).strip().lower() != 'null':
            new_name = f"{title} ,tome {volume} - {author} - {isbn}{extension}"
        else:
            new_name = f"{title}{extension}"

        new_name = re.sub(r'[<>:"/\\|?*]', '', new_name)
        
        return {
            "old_name": filename,
            "new_name": new_name,
            "old_path": full_path,
            "new_path": os.path.join(TARGET_DIR, new_name)
        }
    return None


def process_files():
    if not os.path.exists(TARGET_DIR):
        print(f"Error: The directory '{TARGET_DIR}' does not exist.")
        return

    print(f"--- Starting Parallel File Processor ---")
    print(f"Target: {TARGET_DIR}")
    print(f"Mode: {MODE}")
    print(f"Model: {MODEL_NAME}")
    print(f"Concurrent Workers: {MAX_WORKERS}\n")

    # Filter out directories and hidden files
    all_files = [f for f in os.listdir(TARGET_DIR) 
                 if os.path.isfile(os.path.join(TARGET_DIR, f)) and not f.startswith('.')]
    
    successful_results = []

    # Run the worker functions concurrently
    with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
        futures = {executor.submit(process_single_file, filename): filename for filename in all_files}
        
        for future in concurrent.futures.as_completed(futures):
            filename = futures[future]
            try:
                res = future.result()
                if res:
                    successful_results.append(res)
            except Exception as e:
                print(f"  [!] Error during task execution for {filename}: {e}")

    if not successful_results:
        print("\n--- No files could be matched/processed. ---")
        return

    print(f"\n--- Processing Completed ({len(successful_results)} matches resolved) ---")

    # Handle output according to chosen mode
    if MODE == "DRY_RUN":
        for item in successful_results:
            if item["old_name"] == item["new_name"]:
                print(f"  [.] Already cleanly named: '{item['old_name']}'")
            else:
                print(f"  [DRY RUN] Would rename: '{item['old_name']}' -> '{item['new_name']}'")
                
    elif MODE == "LIVE_RENAME":
        files_renamed = 0
        for item in successful_results:
            if item["old_name"] == item["new_name"]:
                continue
            try:
                os.rename(item["old_path"], item["new_path"])
                print(f"  [SUCCESS] Renamed: '{item['old_name']}' -> '{item['new_name']}'")
                files_renamed += 1
            except Exception as e:
                print(f"  [ERROR] Could not rename '{item['old_name']}': {e}")
        print(f"Total renamed: {files_renamed}")
        
    elif MODE == "GENERATE_BAT":
        bat_path = os.path.join(TARGET_DIR, "rename_books.bat")
        try:
            with open(bat_path, "w", encoding="utf-8") as f:
                f.write("@echo off\n")
                f.write("chcp 65001 >nul\n")
                f.write(f'cd /d "{TARGET_DIR}"\n\n')
                
                written_count = 0
                for item in successful_results:
                    if item["old_name"] == item["new_name"]:
                        continue
                    f.write(f'ren "{item["old_name"]}" "{item["new_name"]}"\n')
                    written_count += 1
                    
                f.write("\necho Renaming completed.\npause\n")
            print(f"[SUCCESS] Generated batch file with {written_count} lines at: {bat_path}")
        except Exception as e:
            print(f"[ERROR] Failed to write batch file: {e}")


if __name__ == "__main__":
    process_files()
ensuite je lui donne le nom de fichier et l'ia va renommer mes fichiers avec la serie - auteur - isbn.

prompt: now execute the provided script against those files names:

j'ai modifié mon calibre (preference / adding book) pour utiliser la même structure

(?P<title>.+) - (?P<author>[^_]+) - (?P<isbn>\d+)

Du coup, babelio_db fonctionne du tonnerre et rapidement (il a toute la structure + l'isbn valide)
titoum is offline   Reply With Quote
Reply


Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
[Metadata Source Plugin] Comicvine chewt0y Plugins 88 07-11-2022 12:00 PM
[Metadata Source Plugin] INMONDADORI Pr.BarnArt Plugins 7 12-03-2021 12:56 PM
Read a book's metadata in a Metadata source plugin? J-H Development 2 03-30-2021 09:08 AM
[Metadata Source Plugin] Empty Plugin? (Fake Identifier) mneimeyer Plugins 3 11-11-2019 08:07 PM
[Metadata Source Plugin] LubimyCzytac [PL] jbienko1 Plugins 33 01-23-2017 06:15 AM


All times are GMT -4. The time now is 09:58 AM.


MobileRead.com is a privately owned, operated and funded community.