{"_id":"@duyquangnvx/story-scraper","_rev":"12-c24f1176abaac1e067af7095a224d360","name":"@duyquangnvx/story-scraper","dist-tags":{"latest":"2.2.3"},"versions":{"2.0.0":{"name":"@duyquangnvx/story-scraper","version":"2.0.0","keywords":["parser","story","novel","scraper","truyenfull","tangthuvien","typescript"],"author":"","license":"ISC","_id":"@duyquangnvx/story-scraper@2.0.0","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/story-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/story-scraper/issues"},"dist":{"shasum":"8a0b8b11e37b2f0d3ba85fa1128201d62602ece7","tarball":"https://registry.npmjs.org/@duyquangnvx/story-scraper/-/story-scraper-2.0.0.tgz","fileCount":8,"integrity":"sha512-Qrs2ZSj17fRNt/U55zeLh3RbpO5KXgqfcasgh9Po4+2HwFXFI/8HPT7GU0x/+E8fi8MmqvslmGpPN6CAtEx0OQ==","signatures":[{"sig":"MEYCIQCIPgVSS/CY5LSrAtnV3DOL48FonNleo4aSbSfTqOZbnQIhAJ4g0rZ9qfItIbYpDNTa3diZPPmy9GxJHtz3trx/NkVT","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":273568},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"e1ed472d92e395a8a119fe13d6450725184b113b","scripts":{"dev":"tsup --watch","test":"tsx test-manual.ts","build":"tsup","typecheck":"tsc --noEmit","example:scraper":"tsx examples/scraper-usage.ts","example:pagination":"tsx examples/pagination-example.ts","example:truyenfull":"tsx examples/truyenfull-example.ts","example:tangthuvien":"tsx examples/tangthuvien-example.ts"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"repository":{"url":"git+https://github.com/duyquangnvx/story-scraper.git","type":"git"},"_npmVersion":"10.9.2","description":"TypeScript library for scraping and parsing stories from various Vietnamese novel websites","directories":{},"_nodeVersion":"22.16.0","dependencies":{"cheerio":"^1.1.2","html-to-text":"^9.0.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","jest":"^30.2.0","tsup":"^8.5.0","ts-jest":"^29.4.5","node-fetch":"^3.3.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^24.9.1","@types/node-fetch":"^2.6.13","@types/html-to-text":"^9.0.4"},"_npmOperationalInternal":{"tmp":"tmp/story-scraper_2.0.0_1761584586101_0.4213089774203478","host":"s3://npm-registry-packages-npm-production"}},"2.0.1":{"name":"@duyquangnvx/story-scraper","version":"2.0.1","keywords":["parser","story","novel","scraper","truyenfull","tangthuvien","typescript"],"author":"","license":"ISC","_id":"@duyquangnvx/story-scraper@2.0.1","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/story-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/story-scraper/issues"},"dist":{"shasum":"3f3330ac80d078ebbc92c4ce33e121901257c5bd","tarball":"https://registry.npmjs.org/@duyquangnvx/story-scraper/-/story-scraper-2.0.1.tgz","fileCount":8,"integrity":"sha512-hqQeTtUFoWoDEl0eRWuhwnjPcufCjMexHOYr9kWG7kRKfNaLBNIixEi5SXhSbx52RAwo2gtVUAtOIx37Rf31yQ==","signatures":[{"sig":"MEUCIF+EHisL+8akfIAK8iN2yVYFB+4tUPkd0I5oKC2xmaOUAiEAgSwz0b8PSPRykMca308rUdyfsDDKH8zzJMdWvvQeADs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":273568},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"2ef910205c39aa5c0d2d9d172a93dc60a76d77aa","scripts":{"dev":"tsup --watch","test":"tsx test-manual.ts","build":"tsup","typecheck":"tsc --noEmit","example:scraper":"tsx examples/scraper-usage.ts","example:pagination":"tsx examples/pagination-example.ts","example:truyenfull":"tsx examples/truyenfull-example.ts","example:tangthuvien":"tsx examples/tangthuvien-example.ts"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"repository":{"url":"git+https://github.com/duyquangnvx/story-scraper.git","type":"git"},"_npmVersion":"10.9.2","description":"TypeScript library for scraping and parsing stories from various Vietnamese novel websites","directories":{},"_nodeVersion":"22.16.0","dependencies":{"cheerio":"^1.1.2","html-to-text":"^9.0.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","jest":"^30.2.0","tsup":"^8.5.0","ts-jest":"^29.4.5","node-fetch":"^3.3.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^24.9.1","@types/node-fetch":"^2.6.13","@types/html-to-text":"^9.0.4"},"_npmOperationalInternal":{"tmp":"tmp/story-scraper_2.0.1_1761584937204_0.5805901979297494","host":"s3://npm-registry-packages-npm-production"}},"2.1.0":{"name":"@duyquangnvx/story-scraper","version":"2.1.0","keywords":["parser","story","novel","scraper","truyenfull","tangthuvien","typescript"],"author":"","license":"ISC","_id":"@duyquangnvx/story-scraper@2.1.0","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/story-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/story-scraper/issues"},"dist":{"shasum":"30995960fd6aa1e88301ba6afa404e184cde32ed","tarball":"https://registry.npmjs.org/@duyquangnvx/story-scraper/-/story-scraper-2.1.0.tgz","fileCount":8,"integrity":"sha512-4zIyVGYcPr5XqOjj3iRPlb8zQu/p28YD2/BXJ+Yat5H3OFahjc7FssjcXUtCPGE29NEB/FzLt7zOBEw5ISur9w==","signatures":[{"sig":"MEQCIE8jCUPUzrm+SvQ9hcIosMcww+KJzFDUMSyYQcK7vx1VAiBbZsxEUiBuhO6b7BjN1te1F8ZjOHRqvxNRiwh9znRGdQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":307553},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"13a69fee5dd12947a178d010e9421f124a9f491e","scripts":{"dev":"tsup --watch","test":"tsx test-manual.ts","build":"tsup","typecheck":"tsc --noEmit","example:scraper":"tsx examples/scraper-usage.ts","example:storylist":"tsx examples/story-list-example.ts","example:pagination":"tsx examples/pagination-example.ts","example:truyenfull":"tsx examples/truyenfull-example.ts","example:tangthuvien":"tsx examples/tangthuvien-example.ts"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"repository":{"url":"git+https://github.com/duyquangnvx/story-scraper.git","type":"git"},"_npmVersion":"10.9.2","description":"TypeScript library for scraping and parsing stories from various Vietnamese novel websites","directories":{},"_nodeVersion":"22.16.0","dependencies":{"cheerio":"^1.1.2","html-to-text":"^9.0.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","jest":"^30.2.0","tsup":"^8.5.0","ts-jest":"^29.4.5","node-fetch":"^3.3.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^24.9.1","@types/node-fetch":"^2.6.13","@types/html-to-text":"^9.0.4"},"_npmOperationalInternal":{"tmp":"tmp/story-scraper_2.1.0_1761672278365_0.5273253866021794","host":"s3://npm-registry-packages-npm-production"}},"2.1.1":{"name":"@duyquangnvx/story-scraper","version":"2.1.1","keywords":["parser","story","novel","scraper","truyenfull","tangthuvien","typescript"],"author":"","license":"ISC","_id":"@duyquangnvx/story-scraper@2.1.1","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/story-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/story-scraper/issues"},"dist":{"shasum":"da9bb197bf56fc1c632914ed2528e9828f5981a4","tarball":"https://registry.npmjs.org/@duyquangnvx/story-scraper/-/story-scraper-2.1.1.tgz","fileCount":8,"integrity":"sha512-MIe65JozyoN5MXNnXA1iRgLuaKoFf8Th58VU+jcw3dsCBL3P6Uvvz0e4uihSNIKan/jvP2zf6ADCL+Xx3RwaVQ==","signatures":[{"sig":"MEUCIQDTwavCBT5I61P1n4JUEb8RYdbJVIz4mkLcgqUcCyfCDAIgQcmMn+bez7Raexlr7mgPjato1CSg8J1txFImD9gNvpI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":307550},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"7b7fda4896f6662757ec86a18cd8d9dfd335f5e5","scripts":{"dev":"tsup --watch","test":"tsx test-manual.ts","build":"tsup","typecheck":"tsc --noEmit","example:scraper":"tsx examples/scraper-usage.ts","example:storylist":"tsx examples/story-list-example.ts","example:pagination":"tsx examples/pagination-example.ts","example:truyenfull":"tsx examples/truyenfull-example.ts","example:tangthuvien":"tsx examples/tangthuvien-example.ts"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"repository":{"url":"git+https://github.com/duyquangnvx/story-scraper.git","type":"git"},"_npmVersion":"10.9.2","description":"TypeScript library for scraping and parsing stories from various Vietnamese novel websites","directories":{},"_nodeVersion":"22.16.0","dependencies":{"cheerio":"^1.1.2","html-to-text":"^9.0.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","jest":"^30.2.0","tsup":"^8.5.0","ts-jest":"^29.4.5","node-fetch":"^3.3.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^24.9.1","@types/node-fetch":"^2.6.13","@types/html-to-text":"^9.0.4"},"_npmOperationalInternal":{"tmp":"tmp/story-scraper_2.1.1_1761849721455_0.18804533183748284","host":"s3://npm-registry-packages-npm-production"}},"2.1.2":{"name":"@duyquangnvx/story-scraper","version":"2.1.2","keywords":["parser","story","novel","scraper","truyenfull","tangthuvien","typescript"],"author":"","license":"ISC","_id":"@duyquangnvx/story-scraper@2.1.2","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/story-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/story-scraper/issues"},"dist":{"shasum":"935d4cfa1266ab4747dccf857071732b11071153","tarball":"https://registry.npmjs.org/@duyquangnvx/story-scraper/-/story-scraper-2.1.2.tgz","fileCount":8,"integrity":"sha512-QR8PkUXjR8sVIfyswJ5TYD4LLagZ+/G5ff03pRFytxqQfMmem98AC3ffYLWaaj/f5vrBD7vO78ucYvLEEEuGpg==","signatures":[{"sig":"MEUCIQC502e6ntOHIPS4YkXhDvUK4SEf0u/oaaPmwZhaEPcQwwIgePhfb44Nh4BCurC8uhUMrOSFcG/lpi/aUDNCm4xbmhE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":307550},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"751e64e9385300d1e3d151afd44828e13848cde3","scripts":{"dev":"tsup --watch","test":"tsx test-manual.ts","build":"tsup","typecheck":"tsc --noEmit","example:scraper":"tsx examples/scraper-usage.ts","example:storylist":"tsx examples/story-list-example.ts","example:pagination":"tsx examples/pagination-example.ts","example:truyenfull":"tsx examples/truyenfull-example.ts","example:tangthuvien":"tsx examples/tangthuvien-example.ts"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"repository":{"url":"git+https://github.com/duyquangnvx/story-scraper.git","type":"git"},"_npmVersion":"10.9.2","description":"TypeScript library for scraping and parsing stories from various Vietnamese novel websites","directories":{},"_nodeVersion":"22.16.0","dependencies":{"cheerio":"^1.1.2","html-to-text":"^9.0.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","jest":"^30.2.0","tsup":"^8.5.0","ts-jest":"^29.4.5","node-fetch":"^3.3.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^24.9.1","@types/node-fetch":"^2.6.13","@types/html-to-text":"^9.0.4"},"_npmOperationalInternal":{"tmp":"tmp/story-scraper_2.1.2_1761850183273_0.7118084507578313","host":"s3://npm-registry-packages-npm-production"}},"2.1.3":{"name":"@duyquangnvx/story-scraper","version":"2.1.3","keywords":["parser","story","novel","scraper","truyenfull","tangthuvien","typescript"],"author":"","license":"ISC","_id":"@duyquangnvx/story-scraper@2.1.3","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/story-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/story-scraper/issues"},"dist":{"shasum":"573be8389858e3e6ebfc85a4efcc2983f2537126","tarball":"https://registry.npmjs.org/@duyquangnvx/story-scraper/-/story-scraper-2.1.3.tgz","fileCount":8,"integrity":"sha512-j40F05v5G0d/QUCXoVP8bqlJKopUyiXrExnRn5bwKM1HMelatboSvi+AztXj626ttjJsVeBrN8wtzXOq8F2iYg==","signatures":[{"sig":"MEUCIQDFEwGoAPiuGXHPaan0Nud6egr6oSMo5Cil0MEa4hNm8QIgEQ4BFFCLpqI/U8tsbZLCu5ysOWlZVlETSU4Go4/vQis=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":308555},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"751e64e9385300d1e3d151afd44828e13848cde3","scripts":{"dev":"tsup --watch","test":"tsx test-manual.ts","build":"tsup","typecheck":"tsc --noEmit","example:scraper":"tsx examples/scraper-usage.ts","example:storylist":"tsx examples/story-list-example.ts","example:pagination":"tsx examples/pagination-example.ts","example:truyenfull":"tsx examples/truyenfull-example.ts","example:tangthuvien":"tsx examples/tangthuvien-example.ts"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"repository":{"url":"git+https://github.com/duyquangnvx/story-scraper.git","type":"git"},"_npmVersion":"10.9.2","description":"TypeScript library for scraping and parsing stories from various Vietnamese novel websites","directories":{},"_nodeVersion":"22.16.0","dependencies":{"cheerio":"^1.1.2","html-to-text":"^9.0.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","jest":"^30.2.0","tsup":"^8.5.0","ts-jest":"^29.4.5","node-fetch":"^3.3.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^24.9.1","@types/node-fetch":"^2.6.13","@types/html-to-text":"^9.0.4"},"_npmOperationalInternal":{"tmp":"tmp/story-scraper_2.1.3_1761850264296_0.6385535218528955","host":"s3://npm-registry-packages-npm-production"}},"2.1.4":{"name":"@duyquangnvx/story-scraper","version":"2.1.4","keywords":["parser","story","novel","scraper","truyenfull","tangthuvien","typescript"],"author":"","license":"ISC","_id":"@duyquangnvx/story-scraper@2.1.4","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/story-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/story-scraper/issues"},"dist":{"shasum":"8ef86c38731ed8f61d8e06780b0d75d1d55fa724","tarball":"https://registry.npmjs.org/@duyquangnvx/story-scraper/-/story-scraper-2.1.4.tgz","fileCount":8,"integrity":"sha512-Eo8zUD9mN/1+9fT9Tuk7IWjSVJRnw+IHq6T6ve7D8cAil3NAtkT4d6HYpXH4Eyvcsy1MIUQIWIr9NlNM8QzVWQ==","signatures":[{"sig":"MEYCIQCw2ZDF6PeNxKLPZe+C2dVWdS9FVd3TkH3c2KRbaF6xNwIhAIJ+GZsBOftEdUwERyWLSlDfOoaFQivai+3wKvtq4HB2","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":308555},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"a75b56dcb69e8634ac6b1951885485cd8c271712","scripts":{"dev":"tsup --watch","test":"tsx test-manual.ts","build":"tsup","typecheck":"tsc --noEmit","example:scraper":"tsx examples/scraper-usage.ts","example:storylist":"tsx examples/story-list-example.ts","example:pagination":"tsx examples/pagination-example.ts","example:truyenfull":"tsx examples/truyenfull-example.ts","example:tangthuvien":"tsx examples/tangthuvien-example.ts"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"repository":{"url":"git+https://github.com/duyquangnvx/story-scraper.git","type":"git"},"_npmVersion":"10.9.2","description":"TypeScript library for scraping and parsing stories from various Vietnamese novel websites","directories":{},"_nodeVersion":"22.16.0","dependencies":{"cheerio":"^1.1.2","html-to-text":"^9.0.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","jest":"^30.2.0","tsup":"^8.5.0","ts-jest":"^29.4.5","node-fetch":"^3.3.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^24.9.1","@types/node-fetch":"^2.6.13","@types/html-to-text":"^9.0.4"},"_npmOperationalInternal":{"tmp":"tmp/story-scraper_2.1.4_1763125968944_0.12678860641311918","host":"s3://npm-registry-packages-npm-production"}},"2.1.5":{"name":"@duyquangnvx/story-scraper","version":"2.1.5","keywords":["parser","story","novel","scraper","truyenfull","tangthuvien","typescript"],"author":"","license":"ISC","_id":"@duyquangnvx/story-scraper@2.1.5","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/story-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/story-scraper/issues"},"dist":{"shasum":"0d870bbaa5d66826238c443986d82c876286e48d","tarball":"https://registry.npmjs.org/@duyquangnvx/story-scraper/-/story-scraper-2.1.5.tgz","fileCount":8,"integrity":"sha512-8yqoLplX9XLTBct+oFArYFK7uPjC70jU9N6eEbDYBRLeWkjObHPDFk9NQba7ay8+fhATuBBGibBB7aDmzJWdEQ==","signatures":[{"sig":"MEQCIDUMikHLMew0Fvu6Ie+2E8UGf3dU0jw8pm9vb0lCrgrxAiBJX8WJ3CCB2ERH9DX0MAr38Y2euwMa979NK8h0iUDuQQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":308313},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"05301940aa52c8ee40bfa0b32c92eb8b97fc03fb","scripts":{"dev":"tsup --watch","test":"tsx test-manual.ts","build":"tsup","typecheck":"tsc --noEmit","example:scraper":"tsx examples/scraper-usage.ts","example:storylist":"tsx examples/story-list-example.ts","example:pagination":"tsx examples/pagination-example.ts","example:truyenfull":"tsx examples/truyenfull-example.ts","example:tangthuvien":"tsx examples/tangthuvien-example.ts"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"repository":{"url":"git+https://github.com/duyquangnvx/story-scraper.git","type":"git"},"_npmVersion":"10.9.2","description":"TypeScript library for scraping and parsing stories from various Vietnamese novel websites","directories":{},"_nodeVersion":"22.16.0","dependencies":{"cheerio":"^1.1.2","html-to-text":"^9.0.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","jest":"^30.2.0","tsup":"^8.5.0","ts-jest":"^29.4.5","node-fetch":"^3.3.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^24.9.1","@types/node-fetch":"^2.6.13","@types/html-to-text":"^9.0.4"},"_npmOperationalInternal":{"tmp":"tmp/story-scraper_2.1.5_1763126521417_0.5246458926833657","host":"s3://npm-registry-packages-npm-production"}},"2.2.0":{"name":"@duyquangnvx/story-scraper","version":"2.2.0","keywords":["parser","story","novel","scraper","truyenfull","tangthuvien","typescript"],"author":"","license":"ISC","_id":"@duyquangnvx/story-scraper@2.2.0","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/story-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/story-scraper/issues"},"dist":{"shasum":"294a985f83f29d6e6a9454065f9d3f61c61dbec7","tarball":"https://registry.npmjs.org/@duyquangnvx/story-scraper/-/story-scraper-2.2.0.tgz","fileCount":8,"integrity":"sha512-Q6YDJMJExCyxVzT5sHFSC3vLh0UqhtFGbJTlRphoDC2DtuGfmGbUK5o6g4kTtgOm+Rhh+Ynhdbpik2xrfcpP0A==","signatures":[{"sig":"MEUCIQDevMLFejhwOL52gOfb3i2fKOTi9sQJzWvnsi2FfR4Q+AIgBnYJgRWOcP6FZmuHFJURujvqTisVZEVKEpZJN8kdb+c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":586800},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"e1225a59b979a45a9870e5cc9c0dfe2d615ffe74","scripts":{"dev":"tsup --watch","test":"tsx test-manual.ts","build":"tsup","release":"npm run build && npm publish","typecheck":"tsc --noEmit","example:scraper":"tsx examples/scraper-usage.ts","example:storylist":"tsx examples/story-list-example.ts","example:metruyencv":"tsx examples/metruyencv-playwright-example.ts","example:pagination":"tsx examples/pagination-example.ts","example:truyenfull":"tsx examples/truyenfull-example.ts","example:sangtacviet":"tsx examples/sangtacviet-playwright-example.ts","example:tangthuvien":"tsx examples/tangthuvien-example.ts"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"repository":{"url":"git+https://github.com/duyquangnvx/story-scraper.git","type":"git"},"_npmVersion":"10.9.2","description":"TypeScript library for scraping and parsing stories from various Vietnamese novel websites","directories":{},"_nodeVersion":"22.16.0","dependencies":{"dotenv":"^17.2.3","cheerio":"^1.1.2","playwright":"^1.56.1","html-to-text":"^9.0.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","jest":"^30.2.0","tsup":"^8.5.0","ts-jest":"^29.4.5","node-fetch":"^3.3.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^24.9.1","@types/node-fetch":"^2.6.13","@types/html-to-text":"^9.0.4"},"_npmOperationalInternal":{"tmp":"tmp/story-scraper_2.2.0_1763226329122_0.31663539407392993","host":"s3://npm-registry-packages-npm-production"}},"2.2.1":{"name":"@duyquangnvx/story-scraper","version":"2.2.1","keywords":["parser","story","novel","scraper","truyenfull","tangthuvien","typescript"],"author":"","license":"ISC","_id":"@duyquangnvx/story-scraper@2.2.1","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/story-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/story-scraper/issues"},"dist":{"shasum":"447fdc56ec4e911644cbab71869cef21e0865e90","tarball":"https://registry.npmjs.org/@duyquangnvx/story-scraper/-/story-scraper-2.2.1.tgz","fileCount":8,"integrity":"sha512-frpvH9RUeSXylRhofTnCWWe4fIx+8LmixDIaJVCbLsgBj7CIvTHdZAS1HddRXfvSi+UCh4PmMcA0MVJURYMMLQ==","signatures":[{"sig":"MEUCIA3u5jmohSU98xYL8mkoNrvxY779uglLL6Rgr38p39oOAiEA+DNLKhuiYHZeRieBnkwrtnQdl/Uh981GFYm7qJq4Ssc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":590378},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"9ad1ddedb58d9f9fb2c7a35d7f983cd9dc53f8d8","scripts":{"dev":"tsup --watch","test":"tsx test-manual.ts","build":"tsup","release":"npm run build && npm publish","typecheck":"tsc --noEmit","example:scraper":"tsx examples/scraper-usage.ts","example:storylist":"tsx examples/story-list-example.ts","example:metruyencv":"tsx examples/metruyencv-playwright-example.ts","example:pagination":"tsx examples/pagination-example.ts","example:truyenfull":"tsx examples/truyenfull-example.ts","example:sangtacviet":"tsx examples/sangtacviet-playwright-example.ts","example:tangthuvien":"tsx examples/tangthuvien-example.ts"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"repository":{"url":"git+https://github.com/duyquangnvx/story-scraper.git","type":"git"},"_npmVersion":"10.9.2","description":"TypeScript library for scraping and parsing stories from various Vietnamese novel websites","directories":{},"_nodeVersion":"22.16.0","dependencies":{"dotenv":"^17.2.3","cheerio":"^1.1.2","playwright":"^1.56.1","html-to-text":"^9.0.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","jest":"^30.2.0","tsup":"^8.5.0","ts-jest":"^29.4.5","node-fetch":"^3.3.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^24.9.1","@types/node-fetch":"^2.6.13","@types/html-to-text":"^9.0.4"},"_npmOperationalInternal":{"tmp":"tmp/story-scraper_2.2.1_1763226844299_0.6599785370052422","host":"s3://npm-registry-packages-npm-production"}},"2.2.2":{"name":"@duyquangnvx/story-scraper","version":"2.2.2","keywords":["parser","story","novel","scraper","truyenfull","tangthuvien","typescript"],"author":"","license":"ISC","_id":"@duyquangnvx/story-scraper@2.2.2","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/story-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/story-scraper/issues"},"dist":{"shasum":"f6b7926bff11e23ec882415ed2b3cf27e92ab8b6","tarball":"https://registry.npmjs.org/@duyquangnvx/story-scraper/-/story-scraper-2.2.2.tgz","fileCount":24,"integrity":"sha512-duXSFBbLnvCcHJI58n1dAkdG5omBe+nNtKND3p2wA1S7ewcSRKceCAud0oHx4bzHcxro/HX7mOjPyro56QQL7Q==","signatures":[{"sig":"MEUCIQC0Zv61XDPNjFB2aOZChkGIYnDHBqH5TFOPx1Knlef56wIgd5/h2eo3lgBcfooPu+pUHeZMXbwR7VkIt/yUbFLHbAk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1454762},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./parser":{"types":"./dist/parser.d.ts","import":"./dist/parser.mjs","require":"./dist/parser.js"},"./scraper":{"types":"./dist/scraper.d.ts","import":"./dist/scraper.mjs","require":"./dist/scraper.js"}},"gitHead":"9ad1ddedb58d9f9fb2c7a35d7f983cd9dc53f8d8","scripts":{"dev":"tsup --watch","test":"tsx test-manual.ts","build":"tsup","release":"npm run build && npm publish","typecheck":"tsc --noEmit","example:basic":"tsx examples/basic-usage.ts","example:scraper":"tsx examples/scraper-usage.ts","example:storylist":"tsx examples/story-list-example.ts","example:metruyencv":"tsx examples/metruyencv-playwright-example.ts","example:pagination":"tsx examples/pagination-example.ts","example:truyenfull":"tsx examples/truyenfull-example.ts","example:sangtacviet":"tsx examples/sangtacviet-playwright-example.ts","example:tangthuvien":"tsx examples/tangthuvien-example.ts"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"repository":{"url":"git+https://github.com/duyquangnvx/story-scraper.git","type":"git"},"_npmVersion":"10.9.2","description":"TypeScript library for scraping and parsing stories from various Vietnamese novel websites","directories":{},"_nodeVersion":"22.16.0","dependencies":{"dotenv":"^17.2.3","cheerio":"^1.1.2","playwright":"^1.56.1","html-to-text":"^9.0.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","jest":"^30.2.0","tsup":"^8.5.0","ts-jest":"^29.4.5","node-fetch":"^3.3.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^24.9.1","@types/node-fetch":"^2.6.13","@types/html-to-text":"^9.0.4"},"_npmOperationalInternal":{"tmp":"tmp/story-scraper_2.2.2_1763227353409_0.34335317808853105","host":"s3://npm-registry-packages-npm-production"}},"2.2.3":{"name":"@duyquangnvx/story-scraper","version":"2.2.3","description":"TypeScript library for scraping and parsing stories from various Vietnamese novel websites","main":"./dist/index.js","module":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","require":"./dist/index.js","import":"./dist/index.mjs"},"./parser":{"types":"./dist/parser.d.ts","require":"./dist/parser.js","import":"./dist/parser.mjs"},"./scraper":{"types":"./dist/scraper.d.ts","require":"./dist/scraper.js","import":"./dist/scraper.mjs"}},"scripts":{"build":"tsup","dev":"tsup --watch","test":"tsx test-manual.ts","typecheck":"tsc --noEmit","release":"npm run build && npm publish","example:basic":"tsx examples/basic-usage.ts","example:truyenfull":"tsx examples/truyenfull-example.ts","example:tangthuvien":"tsx examples/tangthuvien-example.ts","example:metruyencv":"tsx examples/metruyencv-playwright-example.ts","example:sangtacviet":"tsx examples/sangtacviet-playwright-example.ts","example:scraper":"tsx examples/scraper-usage.ts","example:pagination":"tsx examples/pagination-example.ts","example:storylist":"tsx examples/story-list-example.ts","example:truyendichmienphi":"tsx examples/truyendichmienphi-scraper-example.ts"},"repository":{"type":"git","url":"git+https://github.com/duyquangnvx/story-scraper.git"},"keywords":["parser","story","novel","scraper","truyenfull","tangthuvien","typescript"],"author":"","license":"ISC","bugs":{"url":"https://github.com/duyquangnvx/story-scraper/issues"},"homepage":"https://github.com/duyquangnvx/story-scraper#readme","publishConfig":{"access":"public"},"devDependencies":{"@types/html-to-text":"^9.0.4","@types/jest":"^30.0.0","@types/node":"^24.9.1","@types/node-fetch":"^2.6.13","jest":"^30.2.0","node-fetch":"^3.3.2","ts-jest":"^29.4.5","tsup":"^8.5.0","tsx":"^4.20.6","typescript":"^5.9.3"},"dependencies":{"cheerio":"^1.1.2","dotenv":"^17.2.3","html-to-text":"^9.0.5","playwright":"^1.56.1"},"_id":"@duyquangnvx/story-scraper@2.2.3","gitHead":"8a08578861df41f1300fd6a980e2e71c0c258661","_nodeVersion":"22.16.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-SRsQiALZg73mSUfB8PpegqKTYQl4x0y8/G72x2jjTXPnyF+0wmCj6RsmC/yLCm+0r+kNHk/a36e3fLIwa7irxA==","shasum":"71c5dff5fb9118cf0033c5d110276e9c07f18687","tarball":"https://registry.npmjs.org/@duyquangnvx/story-scraper/-/story-scraper-2.2.3.tgz","fileCount":24,"unpackedSize":1742156,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCgFWgvZeEuj32FyWPfmQbHXUrMISBg+cg4/boDoIHz4gIhAKu9cSn7V7BNSJz+zy2rjVxUzgUrBpaxpMsw9xZXpKge"}]},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"directories":{},"maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/story-scraper_2.2.3_1763414621631_0.006648486127841524"},"_hasShrinkwrap":false}},"time":{"created":"2025-10-27T17:03:06.019Z","modified":"2025-11-17T21:23:42.041Z","2.0.0":"2025-10-27T17:03:06.297Z","2.0.1":"2025-10-27T17:08:57.409Z","2.1.0":"2025-10-28T17:24:38.552Z","2.1.1":"2025-10-30T18:42:01.644Z","2.1.2":"2025-10-30T18:49:43.470Z","2.1.3":"2025-10-30T18:51:04.467Z","2.1.4":"2025-11-14T13:12:49.152Z","2.1.5":"2025-11-14T13:22:01.606Z","2.2.0":"2025-11-15T17:05:29.368Z","2.2.1":"2025-11-15T17:14:04.515Z","2.2.2":"2025-11-15T17:22:33.614Z","2.2.3":"2025-11-17T21:23:41.830Z"},"bugs":{"url":"https://github.com/duyquangnvx/story-scraper/issues"},"license":"ISC","homepage":"https://github.com/duyquangnvx/story-scraper#readme","keywords":["parser","story","novel","scraper","truyenfull","tangthuvien","typescript"],"repository":{"type":"git","url":"git+https://github.com/duyquangnvx/story-scraper.git"},"description":"TypeScript library for scraping and parsing stories from various Vietnamese novel websites","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"readme":"# Story Scraper\n\nA TypeScript library for **scraping and parsing** stories from various Vietnamese novel websites. Extract story metadata, chapter lists, and chapter content with ease.\n\n## Features\n\n- **🔍 Dual Mode**: Parse HTML strings OR scrape directly from URLs\n- **⚡ Type-safe**: Built with TypeScript for full type safety\n- **🏗️ Modular**: Clean, extensible architecture with base parser and scraper classes\n- **🌐 Multiple sites**: Built-in support for TruyenFull.vision and TangThuVien\n- **🔧 Easy to extend**: Simple API to add custom parsers/scrapers for new websites\n- **📦 Lightweight**: Minimal dependencies (cheerio for parsing, html-to-text for conversion, native fetch for scraping)\n- **🌳 Tree-shakeable**: Built with tsup for optimal bundle size\n- **⚡ Fast**: Uses cheerio for efficient HTML parsing and DOM traversal\n- **📝 Smart text extraction**: Automatic conversion to clean, readable plain text using html-to-text\n- **⏱️ Rate limiting**: Built-in delay, retry, and progress tracking for scraping\n- **✅ Well-tested**: Comprehensive test suite\n\n## Supported Websites\n\n- **TruyenFull**: truyenfull.vision, truyenfull.vn, truyenfull.com\n- **TangThuVien**: tangthuvien.vn, tangthuvien.com, wikidich.com\n\n## Installation\n\n```bash\nnpm install story-scraper\n```\n\nor\n\n```bash\nyarn add story-scraper\n```\n\nor\n\n```bash\npnpm add story-scraper\n```\n\n## Usage\n\n### Quick Start: Scraping\n\nThe easiest way to get started is using the built-in scrapers:\n\n```typescript\nimport { TruyenFullScraper } from 'story-scraper';\n\nconst scraper = new TruyenFullScraper({\n  delay: 1000,      // 1 second between requests\n  timeout: 30000,   // 30 second timeout\n  maxRetries: 3,    // Retry up to 3 times on failure\n});\n\n// Scrape story metadata\nconst result = await scraper.scrapeMetadata('https://truyenfull.vision/story-url/');\n\nif (result.success) {\n  console.log('Title:', result.data.title);\n  console.log('Author:', result.data.author);\n  console.log('Duration:', result.duration, 'ms');\n}\n\n// Scrape a chapter\nconst chapterResult = await scraper.scrapeChapter('https://truyenfull.vision/story/chapter-1/');\n\n// Scrape complete story (metadata + chapter list)\nconst storyResult = await scraper.scrapeStory('https://truyenfull.vision/story-url/');\n\n// Scrape multiple chapters with progress tracking\nconst chaptersResult = await scraper.scrapeChapters(chapterUrls, {\n  concurrency: 1,\n  onProgress: (progress) => {\n    console.log(`Progress: ${progress.percentage}%`);\n  },\n});\n\n// **NEW**: Scrape ALL chapters from paginated chapter lists\nconst allChaptersResult = await scraper.scrapeAllChapterPages(url, {\n  maxPages: 100,  // Safety limit\n  onProgress: (progress) => {\n    console.log(`Scraping page ${progress.current}...`);\n  },\n});\n```\n\n### Handling Paginated Chapter Lists\n\nMany websites split chapter lists across multiple pages. The library automatically handles pagination:\n\n```typescript\nimport { TruyenFullScraper } from 'story-scraper';\n\nconst scraper = new TruyenFullScraper({ delay: 1000 });\n\n// Get ALL chapters across ALL pages (recommended)\nconst result = await scraper.scrapeAllChapterPages(storyUrl, {\n  maxPages: 100,           // Safety limit\n  onProgress: (progress) => {\n    console.log(`Page ${progress.current} scraped`);\n  },\n});\n\nif (result.success) {\n  console.log(`Total chapters: ${result.data.length}`);\n  // result.data contains ALL chapters from ALL pages\n}\n```\n\n### Parsing Only (No HTTP Requests)\n\nIf you already have the HTML and just need to parse it:\n\n```typescript\nimport { TruyenFullParser } from 'story-scraper';\n\nconst parser = new TruyenFullParser();\n\n// Parse story metadata\nconst htmlContent = '...'; // HTML string from the story page\nconst metadataResult = parser.parseMetadata(htmlContent);\n\nif (metadataResult.success && metadataResult.data) {\n  console.log('Title:', metadataResult.data.title);\n  console.log('Author:', metadataResult.data.author);\n  console.log('Description:', metadataResult.data.description);\n}\n\n// Parse chapter list\nconst chapterListResult = parser.parseChapterList(htmlContent);\n\nif (chapterListResult.success && chapterListResult.data) {\n  chapterListResult.data.forEach(chapter => {\n    console.log(`Chapter ${chapter.chapterNumber}: ${chapter.title}`);\n  });\n}\n\n// Parse chapter content\nconst chapterResult = parser.parseChapter(htmlContent);\n\nif (chapterResult.success && chapterResult.data) {\n  console.log('Chapter content:', chapterResult.data.content);\n}\n```\n\n### Using Scraper Registry\n\nAuto-detect and use the right scraper for any supported URL:\n\n```typescript\nimport { getScraperByURL, getScraper } from 'story-scraper';\n\n// Auto-detect scraper from URL\nconst scraper = getScraperByURL('https://truyenfull.vision/some-story/');\n\nif (scraper) {\n  const result = await scraper.scrapeMetadata(url);\n}\n\n// Or get scraper by domain\nconst scraper2 = getScraper('truyenfull.vision', {\n  delay: 500,\n  timeout: 20000,\n});\n```\n\n### Using Parser Registry (Parse-only mode)\n\n```typescript\nimport { getParser, isSupported } from 'story-scraper';\n\n// Check if a domain is supported\nif (isSupported('truyenfull.vision')) {\n  const parser = getParser('truyenfull.vision');\n\n  if (parser) {\n    const result = parser.parseMetadata(htmlContent);\n    // ...\n  }\n}\n```\n\n### Using with URLs (Parse-only mode)\n\n```typescript\nimport { getParserByURL } from 'story-scraper';\n\nconst url = 'https://truyenfull.vision/some-story/';\nconst parser = getParserByURL(url);\n\nif (parser) {\n  // Use parser to parse content\n}\n```\n\n### Creating Custom Parsers\n\n```typescript\nimport { BaseParser, ParserResult, StoryMetadata } from 'story-scraper';\n\nclass MyCustomParser extends BaseParser {\n  getSupportedDomains(): string[] {\n    return ['example.com'];\n  }\n\n  parseMetadata(html: string): ParserResult<StoryMetadata> {\n    const doc = this.safeParseHTML(html);\n    if (!doc) {\n      return this.error('Failed to parse HTML');\n    }\n\n    // Your custom parsing logic here\n    const title = doc.querySelector('.title')?.textContent || '';\n\n    return this.success({\n      title,\n      author: 'Unknown',\n      description: '',\n    });\n  }\n\n  parseChapterList(html: string): ParserResult<ChapterListItem[]> {\n    // Your implementation\n  }\n\n  parseChapter(html: string): ParserResult<Chapter> {\n    // Your implementation\n  }\n}\n\n// Register your custom parser\nimport { defaultRegistry } from 'story-scraper';\ndefaultRegistry.register(new MyCustomParser());\n```\n\n## API Reference\n\n### Types\n\n#### `StoryMetadata`\n```typescript\ninterface StoryMetadata {\n  title: string;\n  author: string;\n  description: string;\n  coverImage?: string;\n  status?: string;\n  genres?: string[];\n  tags?: string[];\n  rating?: number;\n  views?: number;\n  lastUpdated?: Date;\n}\n```\n\n#### `ChapterListItem`\n```typescript\ninterface ChapterListItem {\n  chapterNumber: number;\n  title: string;\n  url?: string;\n  id?: string;\n  publishedAt?: Date;\n}\n```\n\n#### `Chapter`\n```typescript\ninterface Chapter {\n  chapterNumber: number;\n  title: string;\n  content: string;          // HTML format\n  contentText: string;      // Plain text format (NEW in v1.4.0)\n  previousChapter?: {\n    chapterNumber: number;\n    url?: string;\n  };\n  nextChapter?: {\n    chapterNumber: number;\n    url?: string;\n  };\n  publishedAt?: Date;\n}\n```\n\n#### `ParserResult<T>`\n```typescript\ninterface ParserResult<T> {\n  success: boolean;\n  data?: T;\n  error?: string;\n}\n```\n\n#### `ScrapeResult<T>`\n```typescript\ninterface ScrapeResult<T> {\n  success: boolean;\n  data?: T;\n  error?: string;\n  statusCode?: number;\n  duration?: number;  // Request duration in milliseconds\n}\n```\n\n#### `ScraperOptions`\n```typescript\ninterface ScraperOptions {\n  headers?: Record<string, string>;\n  timeout?: number;          // Request timeout in ms\n  delay?: number;            // Delay between requests in ms\n  maxRetries?: number;       // Max retry attempts\n  userAgent?: string;        // Custom user agent\n}\n```\n\n#### `BulkScrapeOptions`\n```typescript\ninterface BulkScrapeOptions extends ScraperOptions {\n  onProgress?: (progress: ScrapeProgress) => void;\n  concurrency?: number;      // Number of concurrent requests\n  continueOnError?: boolean; // Continue scraping on errors\n}\n```\n\n### Classes\n\n#### `BaseParser`\nAbstract base class for all parsers.\n\nMethods:\n- `parseMetadata(html: string): ParserResult<StoryMetadata>`\n- `parseChapterList(html: string): ParserResult<ChapterListItem[]>`\n- `parseChapter(html: string): ParserResult<Chapter>`\n- `getSupportedDomains(): string[]`\n- `canParse(domain: string): boolean`\n\n#### `TruyenFullParser`\nParser for TruyenFull websites.\n\n#### `TangThuVienParser`\nParser for TangThuVien websites.\n\n#### `ParserRegistry`\nRegistry for managing parsers.\n\nMethods:\n- `register(parser: BaseParser): void`\n- `getParser(domain: string): BaseParser | undefined`\n- `getParserByURL(url: string): BaseParser | undefined`\n- `isSupported(domain: string): boolean`\n- `getSupportedDomains(): string[]`\n\n#### `BaseScraper`\nBase scraper class that combines parsing with HTTP fetching.\n\nMethods:\n- `scrapeMetadata(url: string): Promise<ScrapeResult<StoryMetadata>>`\n- `scrapeChapterList(url: string): Promise<ScrapeResult<ChapterListItem[]>>`\n- `scrapeChapter(url: string): Promise<ScrapeResult<Chapter>>`\n- `scrapeStory(url: string): Promise<ScrapeResult<{metadata, chapters}>>`\n- `scrapeChapters(urls: string[], options?: BulkScrapeOptions): Promise<ScrapeResult<Chapter[]>>`\n- `getParser(): BaseParser`\n- `setOptions(options: Partial<ScraperOptions>): void`\n\n#### `TruyenFullScraper`\nScraper for TruyenFull websites.\n\n#### `TangThuVienScraper`\nScraper for TangThuVien websites.\n\n#### `ScraperRegistry`\nRegistry for managing scrapers.\n\nMethods:\n- `register(domains: string[], factory: (options?) => BaseScraper): void`\n- `getScraper(domain: string, options?: ScraperOptions): BaseScraper | undefined`\n- `getScraperByURL(url: string, options?: ScraperOptions): BaseScraper | undefined`\n- `isSupported(domain: string): boolean`\n- `getSupportedDomains(): string[]`\n\n### Functions\n\n#### Parser Functions\n- `getParser(domain: string): BaseParser | undefined` - Get parser for a domain\n- `getParserByURL(url: string): BaseParser | undefined` - Get parser by URL\n- `isSupported(domain: string): boolean` - Check if domain is supported\n- `getSupportedDomains(): string[]` - Get all supported domains\n\n#### Scraper Functions\n- `getScraper(domain: string, options?: ScraperOptions): BaseScraper | undefined` - Get scraper for a domain\n- `getScraperByURL(url: string, options?: ScraperOptions): BaseScraper | undefined` - Get scraper by URL\n- `isScrapingSupported(domain: string): boolean` - Check if scraping is supported\n- `getScrapingSupportedDomains(): string[]` - Get all domains that support scraping\n\n## Examples\n\nThe library includes working examples that demonstrate both parsing and scraping:\n\n### Run Examples\n\n```bash\n# Scraper usage (recommended - shows all scraper features)\nnpm run example:scraper\n\n# Pagination example (scrape ALL chapters from multi-page lists)\nnpm run example:pagination\n\n# TruyenFull example (parse-only mode with manual fetching)\nnpm run example:truyenfull\n\n# TangThuVien example (parse-only mode with manual fetching)\nnpm run example:tangthuvien\n```\n\nThese examples will:\n1. Fetch HTML content from real story websites\n2. Parse metadata, chapter lists, and chapter content\n3. Save the parsed data to `tmp/` directory as JSON and HTML files\n\nExample output files:\n- `tmp/truyenfull/metadata.json` - Parsed story metadata\n- `tmp/truyenfull/chapters.json` - List of all chapters\n- `tmp/truyenfull/chapter-1.json` - Parsed chapter content (JSON)\n- `tmp/truyenfull/chapter-1.html` - Formatted chapter content (HTML)\n\n## Development\n\n### Setup\n\n```bash\n# Install dependencies\nnpm install\n\n# Run type checking\nnpm run typecheck\n\n# Build the library\nnpm run build\n\n# Run tests\nnpm test\n\n# Watch mode for development\nnpm run dev\n```\n\n### Project Structure\n\n```\nsrc/\n├── types/              # TypeScript interfaces and types\n│   └── index.ts\n├── parsers/            # Parser implementations\n│   ├── base/          # Base parser class\n│   ├── truyenfull/    # TruyenFull parser\n│   ├── tangthuvien/   # TangThuVien parser\n│   ├── ParserRegistry.ts\n│   └── index.ts\n├── utils/             # Utility functions\n│   └── dom.ts\n└── index.ts           # Main entry point\n```\n\n## Contributing\n\nContributions are welcome! To add support for a new website:\n\n1. Create a new parser class extending `BaseParser`\n2. Implement the required methods: `parseMetadata`, `parseChapterList`, `parseChapter`, and `getSupportedDomains`\n3. Register the parser in `src/index.ts`\n4. Add tests for your parser\n5. Submit a pull request\n\n## License\n\nISC\n\n## Notes\n\nThis library only parses HTML content. You need to fetch the HTML yourself (e.g., using fetch, axios, etc.). This design keeps the library lightweight and gives you full control over how you fetch content.\n\n## Example: Complete Workflow\n\n```typescript\nimport { getParser } from 'story-scraper';\n\nasync function parseStory(url: string) {\n  // 1. Fetch HTML (you need to implement this)\n  const response = await fetch(url);\n  const html = await response.text();\n\n  // 2. Get appropriate parser\n  const parser = getParserByURL(url);\n  if (!parser) {\n    throw new Error('No parser found for this URL');\n  }\n\n  // 3. Parse metadata\n  const metadataResult = parser.parseMetadata(html);\n  if (!metadataResult.success) {\n    throw new Error(metadataResult.error);\n  }\n\n  // 4. Parse chapter list\n  const chaptersResult = parser.parseChapterList(html);\n  if (!chaptersResult.success) {\n    throw new Error(chaptersResult.error);\n  }\n\n  return {\n    metadata: metadataResult.data,\n    chapters: chaptersResult.data,\n  };\n}\n```\n","readmeFilename":"README.md"}