{"record":{"id":"c85edf16d2608990","repo":"soimort/you-get","slug":"not-found-book-number-s","errorCode":null,"errorMessage":"not found book number: %s","messagePattern":"not found book number: (.+?)","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"src/you_get/extractors/lrts.py","lineNumber":15,"sourceCode":"#!/usr/bin/env python\n\n__all__ = ['lrts_download']\n\nimport logging\nfrom ..common import *\nfrom ..util import log, term\n\ndef lrts_download(url, output_dir='.', merge=True, info_only=False, **kwargs):\n    html = get_html(url)\n    args = kwargs.get('args')\n    if not args: args = {}\n    matched = re.search(r\"/book/(\\d+)\", url)\n    if not matched:\n        raise AssertionError(\"not found book number: %s\" % url)\n    book_no = matched.group(1)\n    book_title = book_no\n    matched = re.search(r\"<title>([^-]*)[-](.*)[,](.*)</title>\", html)\n    if matched:\n        book_title = matched.group(1)\n\n    matched = re.search(r\"var totalCount='(\\d+)'\", html)\n    if not matched:\n        raise AssertionError(\"not found total count in html\")\n    total_count = int(matched.group(1))\n    log.i('%s total: %s' % (book_title, total_count))\n    first_page = 0\n    if ('first' in args and args.first!= None):\n        first_page = int(args.first)\n\n    page_size = 10\n    if ('page_size' in args and args.page_size != None):\n        page_size = int(args.page_size)","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/soimort/you-get/blob/049548f3f3f35e67ba8d3181c71fdc71d11cf260/src/you_get/extractors/lrts.py#L1-L33","documentation":"The lrts.me audiobook extractor requires the URL itself to contain '/book/<digits>' — it parses the book number straight out of the URL with re.search(r\"/book/(\\d+)\", url). When that pattern misses, it raises AssertionError('not found book number: %s') because there is no other way to address the book's AJAX pagination API.","triggerScenarios":"Calling lrts_download with any URL lacking a /book/NNN path segment, e.g. 'http://www.lrts.me/book/' (no id), 'http://www.lrts.me/playlist', a chapter URL with a different path shape, or a URL where the id is non-numeric.","commonSituations":"Copying a listing/search URL instead of the book detail page; site restructuring paths (e.g. /audio/book/123) so the regex no longer matches; passing an already-parsed API URL.","solutions":["Navigate to the audiobook's detail page on lrts.me and copy the URL of the form http://www.lrts.me/book/12345","Verify the URL contains '/book/' followed by only digits (no query junk glued to the number)","If the site changed its path scheme, update the regex r\"/book/(\\d+)\" in src/you_get/extractors/lrts.py:15 to the new shape"],"exampleFix":"# before\nlrts_download('http://www.lrts.me/playlist')  # AssertionError: not found book number\n\n# after\nlrts_download('http://www.lrts.me/book/12345')","handlingStrategy":"validation","validationCode":"import re\n\ndef is_lrts_book_url(url):\n    return re.search(r'/book/\\d+', url) is not None","typeGuard":null,"tryCatchPattern":"try:\n    lrts_download(url, ...)\nexcept AssertionError as e:\n    if 'not found book number' in str(e):\n        print('URL must be http://www.lrts.me/book/<digits>')\n    else:\n        raise","preventionTips":["Always deep-link to the book detail page (lrts.me/book/NNN), never listings or playlists","Pre-validate the /book/\\d+ segment before invoking the extractor","Strip query parameters that could glue onto the numeric id"],"tags":["url-validation","lrts","audiobook","regex"],"backgroundTag":null,"analyzedSha":"049548f3f3f35e67ba8d3181c71fdc71d11cf260","analyzedAt":"2026-08-15T03:58:15.069Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}