{"record":{"id":"cc9da744ab9c4f0d","repo":"pear-devs/pear-desktop","slug":"failed-to-extract-lyrics-from-page","errorCode":null,"errorMessage":"Failed to extract lyrics from page.","messagePattern":"Failed to extract lyrics from page\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/plugins/synced-lyrics/providers/Megalobiz.ts","lineNumber":93,"sourceCode":"    const sortedResults = searchResults.sort(\n      ({ duration: durationA }, { duration: durationB }) => {\n        const left = Math.abs(durationA - songDuration);\n        const right = Math.abs(durationB - songDuration);\n\n        return left - right;\n      },\n    );\n\n    const closestResult = sortedResults[0];\n    if (!closestResult) return null;\n    if (Math.abs(closestResult.duration - songDuration) > 15) {\n      return null;\n    }\n\n    const html = await fetch(`${this.baseUrl}${closestResult.href}`).then((r) => r.text());\n    const lyricsDoc = this.domParser.parseFromString(html, 'text/html');\n    const raw = lyricsDoc.querySelector('span[id^=\"lrc_\"][id$=\"_lyrics\"]')?.textContent;\n    if (!raw) throw new Error('Failed to extract lyrics from page.');\n\n    const lyrics = LRC.parse(raw);\n\n    return {\n      title: closestResult.title,\n      artists: closestResult.artists,\n      lines: lyrics.lines.map((l) => ({ ...l, status: 'upcoming' })),\n    };\n  }\n}\n\ninterface MegalobizSearchResult {\n  title: string;\n  artists: string[];\n  href: string;\n  duration: number;\n}\n","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/pear-devs/pear-desktop/blob/1e2aac5706c870c93ed74ba8727ae8390d3b0fa5/src/plugins/synced-lyrics/providers/Megalobiz.ts#L75-L111","documentation":"After picking the closest Megalobiz search result, the provider fetches that result page and looks for an element matching span[id^=\"lrc_\"][id$=\"_lyrics\"] containing the raw LRC lyrics. If the element is missing (selector returns nothing), it throws 'Failed to extract lyrics from page.'","triggerScenarios":"Megalobiz changing their result-page markup (renaming the lrc_ span id pattern); result pages without synced (LRC) lyrics — only plain lyrics; pages blocked by bot checks serving different HTML; parse mismatches after site redesigns.","commonSituations":"Site redesigns breaking the CSS selector (classic scraper breakage); tracks that have lyrics but not time-synced LRC content; ad/anti-bot interstitials replacing the real page.","solutions":["Update the synced-lyrics plugin for current Megalobiz markup","Fall back to other providers when this throws","Degrade to 'no synced lyrics' in the UI instead of erroring","Verify the track's Megalobiz page in a browser to see whether LRC content exists"],"exampleFix":"// before\nconst r = await megalobiz.search(info);\n\n// after\ntry { return await megalobiz.search(info); }\ncatch (e) { if (!/extract lyrics from page/.test(e.message)) throw e; return await lrclib.search(info); }","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { return await megalobiz.search(info); } catch (e) { if (!/extract lyrics from page/.test(e.message)) throw e; return await lrclib.search(info); }","preventionTips":["Update the plugin when Megalobiz changes markup (span[id^=\"lrc_\"])","Degrade to 'no synced lyrics' instead of erroring","Some tracks have plain but not LRC lyrics — fall back to plain-lyrics providers"],"tags":["lyrics","megalobiz","scraping","selector-breakage"],"backgroundTag":"web-scraping-selector-broken","analyzedSha":"1e2aac5706c870c93ed74ba8727ae8390d3b0fa5","analyzedAt":"2026-08-27T20:01:08.614Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}