├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── bin └── javbus.js ├── exmaple └── index.js ├── index.js ├── package.json ├── parsers ├── index.js ├── magnet.js ├── page.js └── show.js └── test ├── index.js └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.log 3 | yarn.lock 4 | 5 | node_modules/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | 2 | *.log 3 | 4 | node_modules/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Lsong 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## node-javbus 2 | 3 | > simple javbus api in node.js 4 | 5 | [![node-javbus](https://img.shields.io/npm/v/node-javbus.svg)](https://npmjs.org/node-javbus) 6 | 7 | ### Installation 8 | 9 | ```bash 10 | $ npm install node-javbus 11 | ``` 12 | 13 | ### Example 14 | 15 | ```js 16 | const javbus = require('node-javbus')(); 17 | 18 | (async () => { 19 | 20 | const videos = await javbus.page(1); 21 | console.log(videos); 22 | 23 | const show = await javbus.show(videos[0].id); 24 | console.log(show); 25 | 26 | const files = await javbus.magnet(show.gid); 27 | console.log(files); 28 | 29 | })(); 30 | ``` 31 | 32 | ### Contributing 33 | - Fork this Repo first 34 | - Clone your Repo 35 | - Install dependencies by `$ npm install` 36 | - Checkout a feature branch 37 | - Feel free to add your features 38 | - Make sure your features are fully tested 39 | - Publish your local branch, Open a pull request 40 | - Enjoy hacking <3 41 | 42 | ### MIT 43 | 44 | This work is licensed under the [MIT license](./LICENSE). 45 | 46 | --- -------------------------------------------------------------------------------- /bin/javbus.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const pkg = require('../package'); 4 | const javbus = require('..')(); 5 | 6 | const [command, ...args] = process.argv.slice(2); 7 | 8 | const pad = (str, n = 10) => { 9 | while (str.length < n) { 10 | str += ' '; 11 | } 12 | return str; 13 | } 14 | 15 | const commands = { 16 | async ls(page = 1) { 17 | const list = await javbus.page(page); 18 | for (const show of list) { 19 | console.log(pad(show.id), show.name); 20 | } 21 | }, 22 | async search(keyword) { 23 | const list = await javbus.search(keyword); 24 | for (const show of list) { 25 | console.log(pad(show.id), show.name); 26 | } 27 | }, 28 | async show(id) { 29 | const show = await javbus.show(id); 30 | if (args.includes('--magnet')) { 31 | show.files = await javbus.magnet(show.gid); 32 | } 33 | if (args.includes('--json')) { 34 | const text = JSON.stringify(show, null, 2); 35 | process.stdout.write(text); 36 | return; 37 | } 38 | 39 | console.log(); 40 | console.log(show.title); 41 | console.log(show.cover); 42 | console.log(); 43 | console.log(pad('Director', 15), show.director); 44 | console.log(pad('Stars', 15), show.stars.map(star => star.name).join(' / ')); 45 | console.log(pad('Length', 15), show.length); 46 | console.log(pad('Release Date', 15), show.release_date); 47 | console.log(); 48 | console.log('==== images ===='); 49 | for (const image of show.images) { 50 | console.log(image); 51 | } 52 | console.log(); 53 | console.log('==== stars ===='); 54 | for (const star of show.stars) { 55 | console.log(star.name, star.avatar); 56 | } 57 | console.log(); 58 | const files = await javbus.magnet(show.gid); 59 | console.log('==== download links ===='); 60 | for (const file of files) { 61 | console.log(); 62 | console.log(file.name); 63 | console.log(file.size); 64 | console.log(file.date); 65 | console.log(file.link); 66 | } 67 | }, 68 | help() { 69 | console.log(); 70 | console.log(` ${pkg.name}@${pkg.version}`); 71 | console.log(); 72 | console.log(' - ls'); 73 | console.log(' - search '); 74 | console.log(' - show '); 75 | console.log(' - help'); 76 | } 77 | }; 78 | 79 | (commands[command] || commands.help).apply(this, args); -------------------------------------------------------------------------------- /exmaple/index.js: -------------------------------------------------------------------------------- 1 | const javbus = require('..')(); 2 | 3 | (async () => { 4 | 5 | const videos = await javbus.page(); 6 | console.log(videos); 7 | 8 | const show = await javbus.show(videos[0].id); 9 | console.log(show); 10 | 11 | const files = await javbus.magnet(show.gid); 12 | console.log(files); 13 | 14 | })(); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { 2 | parsePage, 3 | parseShow, 4 | parseMagnet, 5 | } = require('./parsers'); 6 | const https = require('https'); 7 | const assert = require('assert'); 8 | const cheerio = require('cheerio'); 9 | 10 | const parseHTML = html => cheerio.load(html); 11 | const readStream = (stream, buffer = '') => 12 | new Promise((resolve, reject) => stream 13 | .on('error', reject) 14 | .on('data', chunk => buffer += chunk) 15 | .on('end', () => resolve(buffer))); 16 | 17 | const get = (url, options = {}) => 18 | new Promise(done => https.get(url, options, done)); 19 | 20 | const ensureStatusCode = expected => { 21 | if (!Array.isArray(expected)) 22 | expected = [expected]; 23 | return res => { 24 | const { statusCode } = res; 25 | assert.ok(expected.includes(statusCode), `status code must be "${expected}" but actually "${statusCode}"`); 26 | return res; 27 | }; 28 | } 29 | 30 | const www = 'https://www.javbus.com'; 31 | 32 | /** 33 | * javbus 34 | * @param {*} param0 35 | */ 36 | const javbus = ({ homepage = www } = {}) => { 37 | return { 38 | /** 39 | * page 40 | * @param {*} n 41 | * @param {*} uncensored 42 | */ 43 | page(n = 1, uncensored = false) { 44 | return this.list('/' + [uncensored ? 'uncensored' : null, 'page', n].filter(Boolean).join('/')); 45 | }, 46 | /** 47 | * star 48 | * @param {*} who 49 | * @param {*} n 50 | * @param {*} uncensored 51 | */ 52 | star(who, n, uncensored = false) { 53 | return this.list('/' + [uncensored ? 'uncensored' : null, 'star', who, n].filter(Boolean).join('/')); 54 | }, 55 | /** 56 | * genre 57 | * @param {*} genre 58 | * @param {*} n 59 | * @param {*} uncensored 60 | */ 61 | genre(genre, n = 1, uncensored = false) { 62 | return this.list('/' + [uncensored ? 'uncensored' : null, 'genre', genre, n].filter(Boolean).join('/')); 63 | }, 64 | /** 65 | * search 66 | * @param {*} keyword 67 | * @param {*} n 68 | */ 69 | search(keyword, n = 1) { 70 | return this.list(`/search/${keyword}/${n}`); 71 | }, 72 | /** 73 | * list 74 | * @param {*} path 75 | */ 76 | list(path) { 77 | return Promise 78 | .resolve(homepage + path) 79 | .then(get) 80 | .then(ensureStatusCode([200, 301])) 81 | .then(readStream) 82 | .then(parseHTML) 83 | .then(parsePage) 84 | }, 85 | /** 86 | * show 87 | * @param {*} id 88 | */ 89 | show(id) { 90 | return Promise 91 | .resolve(`${homepage}/en/${id}`) 92 | .then(get) 93 | .then(ensureStatusCode(200)) 94 | .then(readStream) 95 | .then(parseHTML) 96 | .then(parseShow); 97 | }, 98 | /** 99 | * magnet 100 | * @param {*} gid 101 | */ 102 | magnet(gid) { 103 | const headers = { referer: homepage }; 104 | const query = `gid=${gid}&uc=0&lang=en&floor=` + Date.now() % 1e3; 105 | const url = `${homepage}/ajax/uncledatoolsbyajax.php?${query}`; 106 | return Promise 107 | .resolve() 108 | .then(() => get(url, { headers })) 109 | .then(ensureStatusCode(200)) 110 | .then(readStream) 111 | .then(x => parseHTML(`${x}
`)) 112 | .then(parseMagnet) 113 | .then(files => files.filter(x => x.size && x.date)) 114 | } 115 | }; 116 | }; 117 | 118 | module.exports = javbus; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-javbus", 3 | "version": "0.0.9", 4 | "description": "simple javbus api in node.js", 5 | "main": "index.js", 6 | "bin": { 7 | "javbus": "./bin/javbus.js" 8 | }, 9 | "scripts": { 10 | "test": "node test" 11 | }, 12 | "keywords": [ 13 | "javbus" 14 | ], 15 | "author": "Lsong", 16 | "license": "MIT", 17 | "dependencies": { 18 | "cheerio": "latest" 19 | }, 20 | "directories": { 21 | "test": "test" 22 | }, 23 | "devDependencies": {}, 24 | "repository": { 25 | "type": "git", 26 | "url": "git+https://github.com/song940/javbus.git" 27 | }, 28 | "bugs": { 29 | "url": "https://github.com/song940/javbus/issues" 30 | }, 31 | "homepage": "https://github.com/song940/javbus#readme" 32 | } 33 | -------------------------------------------------------------------------------- /parsers/index.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | parsePage: require('./page'), 4 | parseShow: require('./show'), 5 | parseMagnet: require('./magnet'), 6 | }; -------------------------------------------------------------------------------- /parsers/magnet.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = $ => { 3 | return $('table tr').map((i, row) => { 4 | const cols = $('td', row); 5 | return { 6 | name: $(cols.get(0)).text().trim(), 7 | size: $(cols.get(1)).text().trim(), 8 | date: $(cols.get(2)).text().trim(), 9 | link: $('a', cols.get(1)).attr('href') 10 | }; 11 | }).get(); 12 | }; -------------------------------------------------------------------------------- /parsers/page.js: -------------------------------------------------------------------------------- 1 | 2 | const innerText = x => 3 | x.children[0].data; 4 | 5 | module.exports = $ => { 6 | const list = []; 7 | $('#waterfall > .item').each(function (i, item) { 8 | const info = $('.photo-info > span', item).get(0); 9 | const [id, date] = $('date', info); 10 | list.push({ 11 | id: innerText(id), 12 | date: innerText(date), 13 | name: innerText(info), 14 | img: $('img', item).attr('src') 15 | }); 16 | }); 17 | return list; 18 | }; -------------------------------------------------------------------------------- /parsers/show.js: -------------------------------------------------------------------------------- 1 | 2 | const www = 'https://www.javbus.com'; 3 | 4 | module.exports = $ => { 5 | const movie = $('.movie'); 6 | const stars = $('.star-box img', movie).map((i, star) => { 7 | const img = $(star).attr('src'); 8 | return { 9 | name: $(star).attr('title'), 10 | avatar: img.indexOf('http') === 0 ? img : www + img, 11 | } 12 | }).get() 13 | const [gid] = $('body') 14 | .find('script') 15 | .map((i, item) => item.children[0]) 16 | .get() 17 | .filter(Boolean) 18 | .map(script => script.data) 19 | .filter(script => /gid/.test(script)) 20 | .map(script => script.match(/gid = (\d+);/)[1]) 21 | 22 | const obj = { 23 | gid, 24 | stars, 25 | title: $('h3').text(), 26 | cover: www + $('img', movie).attr('src'), 27 | genre: $('.info .genre a', movie).map((i, x) => $(x).text()).get(), 28 | images: $('#sample-waterfall a').map((i, anchor) => $(anchor).attr('href')).get(), 29 | }; 30 | 31 | $('.info p', movie).map((i, item) => { 32 | const line = $(item).text(); 33 | const idx = line.indexOf(':'); 34 | const key = line 35 | .substr(0, idx) 36 | .replace(/\s+/, '_') 37 | .toLowerCase(); 38 | const value = line 39 | .substring(idx + 1) 40 | .trim() 41 | if (key && value) 42 | obj[key] = value; 43 | }); 44 | return obj; 45 | }; 46 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | const javbus = require('..')(); 2 | const assert = require('assert'); 3 | 4 | (async () => { 5 | 6 | const list = await javbus.page(1); 7 | 8 | assert.ok(list); 9 | assert.ok(Array.isArray(list)); 10 | assert.ok(list.length); 11 | 12 | const item = list[0]; 13 | 14 | 15 | assert.ok(item.id); 16 | assert.ok(item.name); 17 | assert.ok(item.img); 18 | assert.ok(item.date); 19 | 20 | const show = await javbus.show(item.id); 21 | 22 | assert.ok(show.id); 23 | assert.ok(show.title); 24 | assert.ok(show.cover); 25 | assert.ok(show.length); 26 | assert.ok(show.label); 27 | assert.ok(show.series); 28 | assert.ok(show.director); 29 | assert.ok(show.release_date); 30 | assert.ok(Array.isArray(show.stars)); 31 | assert.ok(Array.isArray(show.genre)); 32 | assert.ok(Array.isArray(show.images)); 33 | 34 | 35 | })(); -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsongdev/node-javbus/9c11ec35e15e80c95baad4b64af4fa0547650a85/test/test.js --------------------------------------------------------------------------------