├── .gitignore ├── .github └── FUNDING.yml ├── LICENSE ├── package.json ├── CONTRIBUTING.md ├── example └── index.js ├── DOCUMENTATION.md ├── README.md ├── tests └── index.test.js └── lib └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | *~ 4 | *.log 5 | node_modules 6 | *.env 7 | .DS_Store 8 | package-lock.json 9 | .bloggify/* 10 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: ionicabizau 2 | patreon: ionicabizau 3 | open_collective: ionicabizau 4 | custom: https://www.buymeacoffee.com/h96wwchmy -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021-25 Ionică Bizău (https://ionicabizau.net) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bible-scraper", 3 | "description": "Retrieve verses from bible.com/YouVersion.", 4 | "keywords": [ 5 | "bible", 6 | "scraper", 7 | "retrieve", 8 | "verses", 9 | "from", 10 | "com", 11 | "youversion" 12 | ], 13 | "license": "MIT", 14 | "version": "2.2.1", 15 | "main": "lib/index.js", 16 | "scripts": { 17 | "test": "jest tests/index.test.js" 18 | }, 19 | "author": "Ionică Bizău (https://ionicabizau.net)", 20 | "homepage": "https://github.com/IonicaBizau/bible-scraper#readme", 21 | "files": [ 22 | "bin/", 23 | "app/", 24 | "lib/", 25 | "dist/", 26 | "src/", 27 | "scripts/", 28 | "resources/", 29 | "menu/", 30 | "cli.js", 31 | "index.js", 32 | "index.d.ts", 33 | "package-lock.json", 34 | "bloggify.js", 35 | "bloggify.json", 36 | "bloggify/" 37 | ], 38 | "repository": { 39 | "type": "git", 40 | "url": "git+ssh://git@github.com/IonicaBizau/bible-scraper.git" 41 | }, 42 | "bugs": { 43 | "url": "https://github.com/IonicaBizau/bible-scraper/issues" 44 | }, 45 | "dependencies": { 46 | "scrape-it": "^6.0.1" 47 | }, 48 | "contributors": [ 49 | "Simone Guarnuccio " 50 | ], 51 | "devDependencies": { 52 | "jest": "^29.7.0" 53 | } 54 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 🌟 Contributing 2 | 3 | Want to contribute to this project? Great! Please read these quick steps to streamline the process and avoid unnecessary tasks. ✨ 4 | 5 | ## 💬 Discuss Changes 6 | Start by opening an issue in the repository using the [bug tracker][1]. Describe your proposed contribution or the bug you've found. If relevant, include platform info and screenshots. 🖼️ 7 | 8 | Wait for feedback before proceeding unless the fix is straightforward, like a typo. 📝 9 | 10 | ## 🔧 Fixing Issues 11 | 12 | Fork the project and create a branch for your fix, naming it `some-great-feature` or `some-issue-fix`. Commit changes while following the [code style][2]. If the project has tests, add one. ✅ 13 | 14 | If a `package.json` or `bower.json` exists, add yourself to the `contributors` array; create it if it doesn't. 🙌 15 | 16 | ```json 17 | { 18 | "contributors": [ 19 | "Your Name (http://your.website)" 20 | ] 21 | } 22 | ``` 23 | 24 | ## 📬 Creating a Pull Request 25 | Open a pull request and reference the initial issue (e.g., *fixes #*). Provide a clear title and consider adding visual aids for clarity. 📊 26 | 27 | ## ⏳ Wait for Feedback 28 | Your contributions will be reviewed. If feedback is given, update your branch as needed, and the pull request will auto-update. 🔄 29 | 30 | ## 🎉 Everyone Is Happy! 31 | Your contributions will be merged, and everyone will appreciate your effort! 😄❤️ 32 | 33 | Thanks! 🤩 34 | 35 | [1]: /issues 36 | [2]: https://github.com/IonicaBizau/code-style -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const BibleScraper = require("../lib"); 4 | 5 | (async () => { 6 | // Create a Vulgata Latina instance 7 | const VulgataLatina = new BibleScraper(BibleScraper.TRANSLATIONS.VULG) 8 | const verse = await VulgataLatina.verse("1CO.13.4") 9 | console.log(verse) 10 | // => { content: 11 | // 'Caritas patiens est, benigna est. Caritas non æmulatur, non agit perperam, non inflatur', 12 | // reference: 'ad Corinthios I 13:4 VULG' } 13 | 14 | // Create a KJV instance 15 | const kjv = new BibleScraper(BibleScraper.TRANSLATIONS.KJV) 16 | kjv.verse("1CO.13.4").then(console.log) 17 | // => { content: 18 | // 'Charity suffereth long, and is kind; charity envieth not; charity vaunteth not itself, is not puffed up', 19 | // reference: '1 Corinthians 13:4 KJV' } 20 | 21 | // Create a NIV instance 22 | const niv = new BibleScraper(111) 23 | console.log(await niv.chapter("1CO.13")) 24 | // => { verses: 25 | // [ { content: 26 | // 'If I speak in the tongues of men or of angels, but do not have love, I am only a resounding gong or a clanging cymbal.', 27 | // reference: '1CO.13.1' }, 28 | // { content: 29 | // 'If I have the gift of prophecy and can fathom all mysteries and all knowledge, and if I have a faith that can move mountains, but do not have love, I am nothing.', 30 | // reference: '1CO.13.2' }, 31 | // ... 32 | // { content: 33 | // 'And now these three remain: faith, hope and love. But the greatest of these is love.', 34 | // reference: '1CO.13.13' } ] } 35 | })() 36 | -------------------------------------------------------------------------------- /DOCUMENTATION.md: -------------------------------------------------------------------------------- 1 | ## Documentation 2 | 3 | You can see below the API reference of this module. 4 | 5 | ### BibleScraper 6 | 7 | Retrieves verses from bible.com, provided by YouVersion. Initializes the `BibleScraper` instance. 8 | 9 | #### Params 10 | 11 | - **Number** `translationId`: - The translation id from bible.com. 12 | 13 | ### constructor 14 | 15 | Constructor for the class. 16 | 17 | #### Params 18 | 19 | - **type** `translationId`: - the ID of the Bible translation. 20 | 21 | ### `url(reference)` 22 | Returns the Bible url reference from bible.com. 23 | 24 | #### Params 25 | 26 | - **String** `reference`: The Bible reference to get the url for. 27 | 28 | #### Return 29 | - **String** The reference url. 30 | 31 | ### `getBibleReference(params, params.book, params.chapter, [params.verseNumStart], [params.verseNumEnd])` 32 | Generates a bible reference based on the provided book, chapter, and verse range. 33 | 34 | #### Params 35 | 36 | - **Object** `params`: - The parameters object. 37 | - **string** `params.book`: - The name of the book. 38 | - **number** `params.chapter`: - The chapter number. 39 | - **number** `[params.verseNumStart]`: - The starting verse number (optional). 40 | - **number** `[params.verseNumEnd]`: - The ending verse number (optional). 41 | 42 | #### Return 43 | - **string** The generated bible reference. 44 | 45 | verse 46 | Fetches the verse. 47 | 48 | #### Params 49 | 50 | - **String** `ref`: The Bible.com verse reference. 51 | 52 | #### Return 53 | - **Promise** A promise resolving the verse object. 54 | 55 | chapter 56 | Fetches the chapter verses. 57 | 58 | #### Params 59 | 60 | - **String** `ref`: The Bible.com chapter reference. 61 | 62 | #### Return 63 | - **Promise** A promise resolving the chapter object. 64 | 65 | ### BibleScraper.BOOKS 66 | 67 | The available books from bible.com. 68 | 69 | ### BibleScraper.TRANSLATIONS 70 | 71 | The translation ID's from bible.com. 72 | 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | # bible-scraper 21 | 22 | [![Support me on Patreon][badge_patreon]][patreon] [![Buy me a book][badge_amazon]][amazon] [![PayPal][badge_paypal_donate]][paypal-donations] [![Ask me anything](https://img.shields.io/badge/ask%20me-anything-1abc9c.svg)](https://github.com/IonicaBizau/ama) [![Version](https://img.shields.io/npm/v/bible-scraper.svg)](https://www.npmjs.com/package/bible-scraper) [![Downloads](https://img.shields.io/npm/dt/bible-scraper.svg)](https://www.npmjs.com/package/bible-scraper) [![Get help on Codementor](https://cdn.codementor.io/badges/get_help_github.svg)](https://www.codementor.io/@johnnyb?utm_source=github&utm_medium=button&utm_term=johnnyb&utm_campaign=github) 23 | 24 | Buy Me A Coffee 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | > Retrieve verses from bible.com/YouVersion. 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | ## :cloud: Installation 51 | 52 | ```sh 53 | # Using npm 54 | npm install --save bible-scraper 55 | 56 | # Using yarn 57 | yarn add bible-scraper 58 | ``` 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | ## :clipboard: Example 73 | 74 | 75 | 76 | ```js 77 | const BibleScraper = require("bible-scraper"); 78 | 79 | (async () => { 80 | // Create a Vulgata Latina instance 81 | const VulgataLatina = new BibleScraper(BibleScraper.TRANSLATIONS.VULG) 82 | const verse = await VulgataLatina.verse("1CO.13.4") 83 | console.log(verse) 84 | // => { content: 85 | // 'Caritas patiens est, benigna est. Caritas non æmulatur, non agit perperam, non inflatur', 86 | // reference: 'ad Corinthios I 13:4 VULG' } 87 | 88 | // Create a KJV instance 89 | const kjv = new BibleScraper(BibleScraper.TRANSLATIONS.KJV) 90 | kjv.verse("1CO.13.4").then(console.log) 91 | // => { content: 92 | // 'Charity suffereth long, and is kind; charity envieth not; charity vaunteth not itself, is not puffed up', 93 | // reference: '1 Corinthians 13:4 KJV' } 94 | 95 | // Create a NIV instance 96 | const niv = new BibleScraper(111) 97 | console.log(await niv.chapter("1CO.13")) 98 | // => { verses: 99 | // [ { content: 100 | // 'If I speak in the tongues of men or of angels, but do not have love, I am only a resounding gong or a clanging cymbal.', 101 | // reference: '1CO.13.1' }, 102 | // { content: 103 | // 'If I have the gift of prophecy and can fathom all mysteries and all knowledge, and if I have a faith that can move mountains, but do not have love, I am nothing.', 104 | // reference: '1CO.13.2' }, 105 | // ... 106 | // { content: 107 | // 'And now these three remain: faith, hope and love. But the greatest of these is love.', 108 | // reference: '1CO.13.13' } ] } 109 | })() 110 | ``` 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | ## :question: Get Help 124 | 125 | There are few ways to get help: 126 | 127 | 128 | 129 | 1. Please [post questions on Stack Overflow](https://stackoverflow.com/questions/ask). You can open issues with questions, as long you add a link to your Stack Overflow question. 130 | 2. For bug reports and feature requests, open issues. :bug: 131 | 3. For direct and quick help, you can [use Codementor](https://www.codementor.io/johnnyb). :rocket: 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | ## :memo: Documentation 140 | 141 | 142 | ### BibleScraper 143 | 144 | Retrieves verses from bible.com, provided by YouVersion. Initializes the `BibleScraper` instance. 145 | 146 | #### Params 147 | 148 | - **Number** `translationId`: - The translation id from bible.com. 149 | 150 | ### constructor 151 | 152 | Constructor for the class. 153 | 154 | #### Params 155 | 156 | - **type** `translationId`: - the ID of the Bible translation. 157 | 158 | ### `url(reference)` 159 | Returns the Bible url reference from bible.com. 160 | 161 | #### Params 162 | 163 | - **String** `reference`: The Bible reference to get the url for. 164 | 165 | #### Return 166 | - **String** The reference url. 167 | 168 | ### `getBibleReference(params, params.book, params.chapter, [params.verseNumStart], [params.verseNumEnd])` 169 | Generates a bible reference based on the provided book, chapter, and verse range. 170 | 171 | #### Params 172 | 173 | - **Object** `params`: - The parameters object. 174 | - **string** `params.book`: - The name of the book. 175 | - **number** `params.chapter`: - The chapter number. 176 | - **number** `[params.verseNumStart]`: - The starting verse number (optional). 177 | - **number** `[params.verseNumEnd]`: - The ending verse number (optional). 178 | 179 | #### Return 180 | - **string** The generated bible reference. 181 | 182 | verse 183 | Fetches the verse. 184 | 185 | #### Params 186 | 187 | - **String** `ref`: The Bible.com verse reference. 188 | 189 | #### Return 190 | - **Promise** A promise resolving the verse object. 191 | 192 | chapter 193 | Fetches the chapter verses. 194 | 195 | #### Params 196 | 197 | - **String** `ref`: The Bible.com chapter reference. 198 | 199 | #### Return 200 | - **Promise** A promise resolving the chapter object. 201 | 202 | ### BibleScraper.BOOKS 203 | 204 | The available books from bible.com. 205 | 206 | ### BibleScraper.TRANSLATIONS 207 | 208 | The translation ID's from bible.com. 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | ## :yum: How to contribute 224 | Have an idea? Found a bug? See [how to contribute][contributing]. 225 | 226 | 227 | ## :sparkling_heart: Support my projects 228 | I open-source almost everything I can, and I try to reply to everyone needing help using these projects. Obviously, 229 | this takes time. You can integrate and use these projects in your applications *for free*! You can even change the source code and redistribute (even resell it). 230 | 231 | However, if you get some profit from this or just want to encourage me to continue creating stuff, there are few ways you can do it: 232 | 233 | 234 | - Starring and sharing the projects you like :rocket: 235 | - [![Buy me a book][badge_amazon]][amazon]—I love books! I will remember you after years if you buy me one. :grin: :book: 236 | - [![PayPal][badge_paypal]][paypal-donations]—You can make one-time donations via PayPal. I'll probably buy a ~~coffee~~ tea. :tea: 237 | - [![Support me on Patreon][badge_patreon]][patreon]—Set up a recurring monthly donation and you will get interesting news about what I'm doing (things that I don't share with everyone). 238 | - **Bitcoin**—You can send me bitcoins at this address (or scanning the code below): `1P9BRsmazNQcuyTxEqveUsnf5CERdq35V6` 239 | 240 | ![](https://i.imgur.com/z6OQI95.png) 241 | 242 | 243 | Thanks! :heart: 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | ## :dizzy: Where is this library used? 261 | If you are using this library in one of your projects, add it in this list. :sparkles: 262 | 263 | - `bible-query` 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | ## :scroll: License 276 | 277 | [MIT][license] © [Ionică Bizău][website] 278 | 279 | 280 | 281 | 282 | 283 | 284 | [license]: /LICENSE 285 | [website]: https://ionicabizau.net 286 | [contributing]: /CONTRIBUTING.md 287 | [docs]: /DOCUMENTATION.md 288 | [badge_patreon]: https://ionicabizau.github.io/badges/patreon.svg 289 | [badge_amazon]: https://ionicabizau.github.io/badges/amazon.svg 290 | [badge_paypal]: https://ionicabizau.github.io/badges/paypal.svg 291 | [badge_paypal_donate]: https://ionicabizau.github.io/badges/paypal_donate.svg 292 | [patreon]: https://www.patreon.com/ionicabizau 293 | [amazon]: http://amzn.eu/hRo9sIZ 294 | [paypal-donations]: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=RVXDDLKKLQRJW 295 | -------------------------------------------------------------------------------- /tests/index.test.js: -------------------------------------------------------------------------------- 1 | const BibleScraper = require('../lib/index.js'); 2 | 3 | describe('BibleScraper', () => { 4 | const translationId = BibleScraper.TRANSLATIONS.KJV; 5 | 6 | describe('url', () => { 7 | it('should return the correct URL for a given reference', () => { 8 | const bibleScraper = new BibleScraper(translationId); 9 | const reference = 'GEN.1'; 10 | const expectedUrl = `https://www.bible.com/bible/${translationId}/${reference}`; 11 | 12 | const url = bibleScraper.url(reference); 13 | 14 | expect(url).toBe(expectedUrl); 15 | }); 16 | }); 17 | 18 | describe('getBibleReference', () => { 19 | it('should generate the correct bible reference', () => { 20 | const bibleScraper = new BibleScraper(translationId); 21 | const params = { 22 | book: 'Genesis', 23 | chapter: 1, 24 | verseNumStart: 1, 25 | verseNumEnd: 3, 26 | }; 27 | const expectedReference = `GEN.1.1-3.${translationId}`; 28 | 29 | const reference = bibleScraper.getBibleReference(params); 30 | 31 | expect(reference).toBe(expectedReference); 32 | }); 33 | 34 | it('should handle optional verseNumEnd', () => { 35 | const bibleScraper = new BibleScraper(translationId); 36 | const params = { 37 | book: 'Genesis', 38 | chapter: 1, 39 | verseNumStart: 1, 40 | }; 41 | const expectedReference = `GEN.1.1.${translationId}`; 42 | 43 | const reference = bibleScraper.getBibleReference(params); 44 | 45 | expect(reference).toBe(expectedReference); 46 | }); 47 | 48 | it('should log a warning for invalid book name', () => { 49 | const bibleScraper = new BibleScraper(translationId); 50 | const params = { 51 | book: 'InvalidBook', 52 | chapter: 1, 53 | verseNumStart: 1, 54 | verseNumEnd: 3, 55 | }; 56 | 57 | const consoleWarnSpy = jest.spyOn(console, 'warn'); 58 | bibleScraper.getBibleReference(params); 59 | 60 | expect(consoleWarnSpy).toHaveBeenCalledWith( 61 | 'Please provide a valid book name using the `BibleScraper.BOOKS` array.' 62 | ); 63 | }); 64 | 65 | it('should log a warning for missing chapter number', () => { 66 | const bibleScraper = new BibleScraper(translationId); 67 | const params = { 68 | book: 'Genesis', 69 | verseNumStart: 1, 70 | verseNumEnd: 3, 71 | }; 72 | 73 | const consoleWarnSpy = jest.spyOn(console, 'warn'); 74 | bibleScraper.getBibleReference(params); 75 | 76 | expect(consoleWarnSpy).toHaveBeenCalledWith('Please provide a chapter number.'); 77 | }); 78 | }); 79 | 80 | describe('verse', () => { 81 | it('should fetch the verse from bible.com', async () => { 82 | const bibleScraper = new BibleScraper(translationId); 83 | const reference = 'GEN.1.1'; 84 | const expectedVerse = { 85 | content: 'In the beginning God created the heaven and the earth.', 86 | reference: 'Genesis 1:1 KJV', 87 | version: 'KJV', 88 | }; 89 | 90 | const verse = await bibleScraper.verse(reference); 91 | 92 | expect(verse).toEqual(expectedVerse); 93 | }); 94 | }); 95 | 96 | describe('chapter', () => { 97 | it('should fetch the chapter verses from bible.com', async () => { 98 | const bibleScraper = new BibleScraper(translationId); 99 | const reference = 'GEN.1'; 100 | const expectedChapter = { 101 | reference: "Genesis 1 KJV", 102 | version: 'KJV', 103 | verses: [ 104 | { 105 | "content": "In the beginning God created the heaven and the earth.", 106 | "reference": "Genesis 1:1" 107 | }, 108 | { 109 | "content": "And the earth was without form, and void; and darkness was upon the face of the deep. And the Spirit of God moved upon the face of the waters.", 110 | "reference": "Genesis 1:2" 111 | }, 112 | { 113 | "content": "And God said, Let there be light: and there was light.", 114 | "reference": "Genesis 1:3" 115 | }, 116 | { 117 | "content": "And God saw the light, that it was good: and God divided the light from the darkness.", 118 | "reference": "Genesis 1:4" 119 | }, 120 | { 121 | "content": "And God called the light Day, and the darkness he called Night. And the evening and the morning were the first day.", 122 | "reference": "Genesis 1:5" 123 | }, 124 | { 125 | "content": "And God said, Let there be a firmament in the midst of the waters, and let it divide the waters from the waters.", 126 | "reference": "Genesis 1:6" 127 | }, 128 | { 129 | "content": "And God made the firmament, and divided the waters which were under the firmament from the waters which were above the firmament: and it was so.", 130 | "reference": "Genesis 1:7" 131 | }, 132 | { 133 | "content": "And God called the firmament Heaven. And the evening and the morning were the second day.", 134 | "reference": "Genesis 1:8" 135 | }, 136 | { 137 | "content": "And God said, Let the waters under the heaven be gathered together unto one place, and let the dry land appear: and it was so.", 138 | "reference": "Genesis 1:9" 139 | }, 140 | { 141 | "content": "And God called the dry land Earth; and the gathering together of the waters called he Seas: and God saw that it was good.", 142 | "reference": "Genesis 1:10" 143 | }, 144 | { 145 | "content": "And God said, Let the earth bring forth grass, the herb yielding seed, and the fruit tree yielding fruit after his kind, whose seed is in itself, upon the earth: and it was so.", 146 | "reference": "Genesis 1:11" 147 | }, 148 | { 149 | "content": "And the earth brought forth grass, and herb yielding seed after his kind, and the tree yielding fruit, whose seed was in itself, after his kind: and God saw that it was good.", 150 | "reference": "Genesis 1:12" 151 | }, 152 | { 153 | "content": "And the evening and the morning were the third day.", 154 | "reference": "Genesis 1:13" 155 | }, 156 | { 157 | "content": "And God said, Let there be lights in the firmament of the heaven to divide the day from the night; and let them be for signs, and for seasons, and for days, and years:", 158 | "reference": "Genesis 1:14" 159 | }, 160 | { 161 | "content": "and let them be for lights in the firmament of the heaven to give light upon the earth: and it was so.", 162 | "reference": "Genesis 1:15" 163 | }, 164 | { 165 | "content": "And God made two great lights; the greater light to rule the day, and the lesser light to rule the night: he made the stars also.", 166 | "reference": "Genesis 1:16" 167 | }, 168 | { 169 | "content": "And God set them in the firmament of the heaven to give light upon the earth,", 170 | "reference": "Genesis 1:17" 171 | }, 172 | { 173 | "content": "and to rule over the day and over the night, and to divide the light from the darkness: and God saw that it was good.", 174 | "reference": "Genesis 1:18" 175 | }, 176 | { 177 | "content": "And the evening and the morning were the fourth day.", 178 | "reference": "Genesis 1:19" 179 | }, 180 | { 181 | "content": "And God said, Let the waters bring forth abundantly the moving creature that hath life, and fowl that may fly above the earth in the open firmament of heaven.", 182 | "reference": "Genesis 1:20" 183 | }, 184 | { 185 | "content": "And God created great whales, and every living creature that moveth, which the waters brought forth abundantly, after their kind, and every winged fowl after his kind: and God saw that it was good.", 186 | "reference": "Genesis 1:21" 187 | }, 188 | { 189 | "content": "And God blessed them, saying, Be fruitful, and multiply, and fill the waters in the seas, and let fowl multiply in the earth.", 190 | "reference": "Genesis 1:22" 191 | }, 192 | { 193 | "content": "And the evening and the morning were the fifth day.", 194 | "reference": "Genesis 1:23" 195 | }, 196 | { 197 | "content": "And God said, Let the earth bring forth the living creature after his kind, cattle, and creeping thing, and beast of the earth after his kind: and it was so.", 198 | "reference": "Genesis 1:24" 199 | }, 200 | { 201 | "content": "And God made the beast of the earth after his kind, and cattle after their kind, and every thing that creepeth upon the earth after his kind: and God saw that it was good.", 202 | "reference": "Genesis 1:25" 203 | }, 204 | { 205 | "content": "And God said, Let us make man in our image, after our likeness: and let them have dominion over the fish of the sea, and over the fowl of the air, and over the cattle, and over all the earth, and over every creeping thing that creepeth upon the earth.", 206 | "reference": "Genesis 1:26" 207 | }, 208 | { 209 | "content": "So God created man in his own image, in the image of God created he him; male and female created he them.", 210 | "reference": "Genesis 1:27" 211 | }, 212 | { 213 | "content": "And God blessed them, and God said unto them, Be fruitful, and multiply, and replenish the earth, and subdue it: and have dominion over the fish of the sea, and over the fowl of the air, and over every living thing that moveth upon the earth.", 214 | "reference": "Genesis 1:28" 215 | }, 216 | { 217 | "content": "And God said, Behold, I have given you every herb bearing seed, which is upon the face of all the earth, and every tree, in the which is the fruit of a tree yielding seed; to you it shall be for meat.", 218 | "reference": "Genesis 1:29" 219 | }, 220 | { 221 | "content": "And to every beast of the earth, and to every fowl of the air, and to every thing that creepeth upon the earth, wherein there is life, I have given every green herb for meat: and it was so.", 222 | "reference": "Genesis 1:30" 223 | }, 224 | { 225 | "content": "And God saw every thing that he had made, and, behold, it was very good. And the evening and the morning were the sixth day.", 226 | "reference": "Genesis 1:31" 227 | } 228 | ], 229 | audioBibleUrl: 'https://audio-bible-cdn.youversionapi.com', 230 | copyright: "Rights in the Authorized (King James) Version in the United Kingdom are vested in the Crown. Published by permission of the Crown’s patentee, Cambridge University Press.", 231 | audioBibleCopyright: "Copyright 2007 Fellowship for the Performing Arts" 232 | } 233 | 234 | const chapter = await bibleScraper.chapter(reference); 235 | 236 | expect(chapter.verses).toEqual(expectedChapter.verses); 237 | expect(chapter.reference).toEqual(expectedChapter.reference); 238 | expect(chapter.version).toEqual(expectedChapter.version); 239 | expect(chapter.audioBibleCopyright).toEqual(expectedChapter.audioBibleCopyright); 240 | expect(chapter.copyright).toEqual(expectedChapter.copyright); 241 | expect(chapter.audioBibleUrl).toContain(expectedChapter.audioBibleUrl); 242 | }); 243 | }); 244 | }); 245 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const scrapeIt = require("scrape-it") 4 | 5 | // Bible version ID's were found on https://www.bible.com/versions. 6 | const ENGLISH_BIBLE_VERSION_IDS = { 7 | AMP: 1588, 8 | AMPC: 8, 9 | ASV: 12, 10 | BOOKS: 31, 11 | BSB: 3034, 12 | CEB: 37, 13 | CEV: 392, 14 | CEVDCI: 303, 15 | CEVUK: 294, 16 | CJB: 1275, 17 | CPDV: 42, 18 | CSB: 1713, 19 | DARBY: 478, 20 | DRC1752: 55, 21 | EASY: 2079, 22 | ERV: 406, 23 | ESV: 59, 24 | FBV: 1932, 25 | FNVNT: 3633, 26 | GNBDC: 416, 27 | GNBDK: 431, 28 | GNBUK: 296, 29 | GNT: 68, 30 | GNTD: 69, 31 | GNV: 2163, 32 | GW: 70, 33 | GWC: 1047, 34 | HCSB: 72, 35 | ICB: 1359, 36 | JUB: 1077, 37 | KJV: 1, 38 | KJVAAE: 546, 39 | KJVAE: 547, 40 | LEB: 90, 41 | LSB: 3345, 42 | MEV: 1171, 43 | MP1650: 1365, 44 | MP1781: 3051, 45 | MSG: 97, 46 | NABRE: 463, 47 | NASB1995: 100, 48 | NASB2020: 2692, 49 | NCV: 105, 50 | NET: 107, 51 | NIRV: 110, 52 | NIV: 111, 53 | NIVUK: 113, 54 | NKJV: 114, 55 | NLT: 116, 56 | NMV: 2135, 57 | NRSV: 2015, 58 | NRSVUE: 3523, 59 | PEV: 2530, 60 | RAD: 2753, 61 | RSV: 2017, 62 | RSVCI: 3548, 63 | RV1885: 477, 64 | RV1895: 1922, 65 | TCENT: 3427, 66 | TEG: 3010, 67 | TLV: 314, 68 | TOJB2011: 130, 69 | TPT: 1849, 70 | TS2009: 316, 71 | WBMS: 2407, 72 | WEBBE: 1204, 73 | WEBUS: 206, 74 | WMB: 1209, 75 | WMBBE: 1207, 76 | YLT98: 821 77 | } 78 | 79 | const TRANSLATIONS = Object.assign(ENGLISH_BIBLE_VERSION_IDS, { 80 | VULG: 823, 81 | ICL00D: 1196, 82 | NR06: 122, 83 | }) 84 | 85 | module.exports.TRANSLATIONS = TRANSLATIONS; 86 | 87 | // Bible book names each have a short code called a USFM code. 88 | // These can be found here: https://ubsicap.github.io/usfm/identification/books.html 89 | const booksAndUsfmShortcodes = { 90 | 'Genesis': 'GEN', 91 | 'Exodus': 'EXO', 92 | 'Leviticus': 'LEV', 93 | 'Numbers': 'NUM', 94 | 'Deuteronomy': 'DEU', 95 | 'Joshua': 'JOS', 96 | 'Judges': 'JDG', 97 | 'Ruth': 'RUT', 98 | '1 Samuel': '1SA', 99 | '2 Samuel': '2SA', 100 | '1 Kings': '1KI', 101 | '2 Kings': '2KI', 102 | '1 Chronicles': '1CH', 103 | '2 Chronicles': '2CH', 104 | 'Ezra': 'EZR', 105 | 'Nehemiah': 'NEH', 106 | 'Esther': 'EST', 107 | 'Job': 'JOB', 108 | 'Psalms': 'PSA', 109 | 'Psalm': 'PSA', 110 | 'Proverbs': 'PRO', 111 | 'Ecclesiastes': 'ECC', 112 | 'Song of Solomon': 'SNG', 113 | 'Isaiah': 'ISA', 114 | 'Jeremiah': 'JER', 115 | 'Lamentations': 'LAM', 116 | 'Ezekiel': 'EZK', 117 | 'Daniel': 'DAN', 118 | 'Hosea': 'HOS', 119 | 'Joel': 'JOL', 120 | 'Amos': 'AMO', 121 | 'Obadiah': 'OBA', 122 | 'Jonah': 'JON', 123 | 'Micah': 'MIC', 124 | 'Nahum': 'NAM', 125 | 'Habakkuk': 'HAB', 126 | 'Zephaniah': 'ZEP', 127 | 'Haggai': 'HAG', 128 | 'Zechariah': 'ZEC', 129 | 'Malachi': 'MAL', 130 | 'Matthew': 'MAT', 131 | 'Mark': 'MRK', 132 | 'Luke': 'LUK', 133 | 'John': 'JHN', 134 | 'Acts': 'ACT', 135 | 'Romans': 'ROM', 136 | '1 Corinthians': '1CO', 137 | '2 Corinthians': '2CO', 138 | 'Galatians': 'GAL', 139 | 'Ephesians': 'EPH', 140 | 'Philippians': 'PHP', 141 | 'Colossians': 'COL', 142 | '1 Thessalonians': '1TH', 143 | '2 Thessalonians': '2TH', 144 | '1 Timothy': '1TI', 145 | '2 Timothy': '2TI', 146 | 'Titus': 'TIT', 147 | 'Philemon': 'PHM', 148 | 'Hebrews': 'HEB', 149 | 'James': 'JAS', 150 | '1 Peter': '1PE', 151 | '2 Peter': '2PE', 152 | '1 John': '1JN', 153 | '2 John': '2JN', 154 | '3 John': '3JN', 155 | 'Jude': 'JUD', 156 | 'Revelation': 'REV' 157 | } 158 | 159 | /** 160 | * BibleScraper 161 | * 162 | * Retrieves verses from bible.com, provided by YouVersion. Initializes the `BibleScraper` instance. 163 | * 164 | * @class 165 | * @name BibleScraper 166 | * 167 | * @param {Number} translationId - The translation id from bible.com. 168 | * 169 | * @example 170 | * const NLTBibleScraper = new BibleScraper(BibleScraper.TRANSLATIONS.NLT); 171 | * const reference = NLTBibleScraper.getBibleReference({ 172 | * book: BibleScraper.BOOKS.GENESIS, 173 | * chapter: 1, 174 | * verseNumStart: 1, 175 | * verseNumEnd: 3 176 | * }); 177 | * console.log(reference); 178 | * // Output: "GEN.1.1-3.116" 179 | * 180 | * const verseData = await NLTBibleScraper.verse(reference); 181 | * console.log(verseData); 182 | * // Output: { content: "In the beginning God created the heavens and the earth.", reference: "Genesis 1:1" } 183 | * 184 | * const chapterData = await NLTBibleScraper.chapter('GEN.1'); 185 | * console.log(chapterData); 186 | * // Output: { verses: [ { content: "In the beginning God created the heavens and the earth.", reference: "Genesis 1:1" }, ... ] } 187 | */ 188 | module.exports = class BibleScraper { 189 | /** 190 | * Constructor for the class. 191 | * 192 | * @param {type} translationId - the ID of the Bible translation. 193 | * 194 | * @throws {Error} - if translationId is not provided. 195 | */ 196 | constructor(translationId) { 197 | if (!translationId) { 198 | throw new Error('Bible translation ID is required and is available via `BibleScraper.TRANSLATIONS`.') 199 | } 200 | 201 | this.translation_id = translationId 202 | } 203 | 204 | /** 205 | * url 206 | * Returns the Bible url reference from bible.com. 207 | * 208 | * @param {String} reference The Bible reference to get the url for. 209 | * @returns {String} The reference url. 210 | */ 211 | url(reference) { 212 | // TODO Validation 213 | return `https://www.bible.com/bible/${this.translation_id}/${reference}` 214 | } 215 | 216 | /** 217 | * Generates a bible reference based on the provided book, chapter, and verse range. 218 | * 219 | * @param {Object} params - The parameters object. 220 | * @param {string} params.book - The name of the book. 221 | * @param {number} params.chapter - The chapter number. 222 | * @param {number} [params.verseNumStart] - The starting verse number (optional). 223 | * @param {number} [params.verseNumEnd] - The ending verse number (optional). 224 | * 225 | * @return {string} The generated bible reference. 226 | */ 227 | getBibleReference({ book, chapter, verseNumStart, verseNumEnd }) { 228 | if (!BibleScraper.BOOKS.includes(book)) { 229 | console.warn('Please provide a valid book name using the `BibleScraper.BOOKS` array.') 230 | } 231 | 232 | if (!chapter) { 233 | console.warn('Please provide a chapter number.') 234 | } 235 | 236 | let bibleReference = `${booksAndUsfmShortcodes[book]}.${chapter}`; 237 | 238 | if (verseNumStart && verseNumEnd) { 239 | bibleReference = `${bibleReference}.${verseNumStart}-${verseNumEnd}.${this.translation_id}`; 240 | } else if (verseNumStart && !verseNumEnd) { 241 | bibleReference = `${bibleReference}.${verseNumStart}.${this.translation_id}`; 242 | } 243 | 244 | return bibleReference 245 | } 246 | 247 | /** 248 | * verse 249 | * Fetches the verse. 250 | * 251 | * @param {String} ref The Bible.com verse reference. 252 | * @returns {Promise} A promise resolving the verse object. 253 | */ 254 | async verse(ref) { 255 | const verse = { 256 | content: '', 257 | reference: '', 258 | version: '', 259 | } 260 | 261 | // This is a more robust way to get the verse. The old way 262 | // was fragile. If a className changed, then it'd break this 263 | // entire package. Bible.com is built using NextJS and on this 264 | // page the __NEXT_DATA__ provides us with all the verse data 265 | // we need. In the event that this method fails, there is a fallback 266 | // to the old way. 267 | const { data: nextJSDataString } = await scrapeIt(this.url(ref), { 268 | json: { 269 | selector: "script#__NEXT_DATA__", 270 | eq: 0 271 | }, 272 | }) 273 | 274 | if (nextJSDataString) { 275 | const nextJSData = JSON.parse(nextJSDataString.json || '{}') 276 | const content = nextJSData.props.pageProps.verses[0].content 277 | const reference = nextJSData.props.pageProps.verses[0].reference.human 278 | const version = nextJSData.props.pageProps.version.local_abbreviation 279 | 280 | verse.version = version 281 | verse.content = content 282 | verse.reference = reference + ' ' + version 283 | 284 | if (verse.content && verse.reference) { 285 | 286 | return verse 287 | } 288 | } 289 | 290 | // fallback to old way 291 | const { data } = await scrapeIt(this.url(ref), { 292 | content: { 293 | selector: "p.text-19", 294 | eq: 0 295 | }, 296 | reference: { 297 | selector: "h2.mbe-2", 298 | eq: 0 299 | } 300 | }) 301 | 302 | return data 303 | } 304 | 305 | /** 306 | * chapter 307 | * Fetches the chapter verses. 308 | * 309 | * @param {String} ref The Bible.com chapter reference. 310 | * @returns {Promise} A promise resolving the chapter object. 311 | */ 312 | async chapter(ref) { 313 | const chapter = { 314 | verses: [{ 315 | content: '', 316 | reference: '', 317 | }], 318 | version: '', 319 | reference: '', 320 | audioBibleUrl: '', 321 | copyright: '', 322 | audioBibleCopyright: '', 323 | } 324 | 325 | const { data } = await scrapeIt(this.url(ref), { 326 | verses: { 327 | listItem: 'span[data-usfm][class*="ChapterContent_verse_"]', 328 | data: { 329 | content: { 330 | selector: 'span[class*="ChapterContent_content_"]', 331 | how: "text" 332 | }, 333 | reference: { 334 | attr: "data-usfm" 335 | } 336 | } 337 | }, 338 | nextJSDataString: { 339 | selector: "script#__NEXT_DATA__", 340 | eq: 0 341 | }, 342 | }) 343 | 344 | let bibleReferenceWithoutVersion = ''; 345 | if (data.nextJSDataString) { 346 | const nextJSData = JSON.parse(data.nextJSDataString || '{}') 347 | 348 | bibleReferenceWithoutVersion = nextJSData.props.pageProps.chapterInfo.reference.human 349 | let audioBibleUrl 350 | try { 351 | audioBibleUrl = nextJSData.props.pageProps.chapterInfo.audioChapterInfo[0].download_urls.format_mp3_32k; 352 | } catch (error) { 353 | audioBibleUrl = null 354 | } 355 | 356 | chapter.version = nextJSData.props.pageProps.versionData.local_abbreviation 357 | chapter.reference = bibleReferenceWithoutVersion + ' ' + chapter.version 358 | try { 359 | chapter.audioBibleUrl = audioBibleUrl.replace('//', 'https://'); 360 | } catch (error) { 361 | chapter.audioBibleUrl = null 362 | } 363 | chapter.copyright = nextJSData.props.pageProps.chapterInfo.copyright.text 364 | try { 365 | chapter.audioBibleCopyright = nextJSData.props.pageProps.audioVersionInfo.copyright_short.text; 366 | } catch (error) { 367 | chapter.audioBibleCopyright = null 368 | } 369 | } 370 | 371 | chapter.verses = (data.verses || []).reduce((acc, c) => { 372 | const latest = acc[acc.length - 1] 373 | 374 | if (latest && latest.reference === c.reference) { 375 | latest.content = (latest.content + " " + c.content).trim() 376 | } else { 377 | acc.push(c) 378 | } 379 | 380 | return acc 381 | }, []) 382 | 383 | // Adding a readable verse reference to each verse. 384 | chapter.verses.forEach((verse) => { 385 | const verseNum = verse.reference.split('.')[2] 386 | verse.reference = `${bibleReferenceWithoutVersion}:${verseNum}` 387 | }) 388 | 389 | return chapter 390 | } 391 | } 392 | 393 | /** 394 | * The available books from bible.com. 395 | * 396 | * @name BibleScraper.BOOKS 397 | * @type {BOOKS} 398 | * @readonly 399 | * 400 | */ 401 | module.exports.BOOKS = Object.keys(booksAndUsfmShortcodes); 402 | 403 | /** 404 | * The translation ID's from bible.com. 405 | * 406 | * @name BibleScraper.TRANSLATIONS 407 | * @type {TRANSLATIONS} 408 | * @readonly 409 | * 410 | */ 411 | module.exports.TRANSLATIONS = TRANSLATIONS; 412 | 413 | 414 | module.exports.BOOK_NAMES = Object.keys(booksAndUsfmShortcodes) 415 | --------------------------------------------------------------------------------