Compare commits
No commits in common. "9b4a2636b2a552ca7acc68fdf0849ce181b7d859" and "ab65c9f15afeae98a0b63bdeab739f2c98b87994" have entirely different histories.
9b4a2636b2
...
ab65c9f15a
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,2 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
data/credentials.json
|
data/credentials.json
|
||||||
*.txt
|
|
24
README.md
24
README.md
@ -1,27 +1,3 @@
|
|||||||
# Kiss Asian Downloader
|
# Kiss Asian Downloader
|
||||||
|
|
||||||
Download content from Kiss Asian through JDownloader.
|
Download content from Kiss Asian through JDownloader.
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Clone this repository. Then, install the dependencies.
|
|
||||||
|
|
||||||
```text
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
Inside the `data` folder there is a `credentials.json.example` file. Rename this to `credentials.json` and fill it up with your own credentials.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
You can use the script with the following command:
|
|
||||||
|
|
||||||
```text
|
|
||||||
node . --display <links_file>
|
|
||||||
```
|
|
||||||
|
|
||||||
> The argument `--display` is used if you wish to see the puppeteer window.
|
|
||||||
>
|
|
||||||
> `links_file` must be a text file containing the links to KissAsian media pages separated by newlines.
|
|
||||||
|
@ -16,11 +16,6 @@ class JDownloaderClient {
|
|||||||
Logger.info(`Connected to JDownloader ${this.device.name}`);
|
Logger.info(`Connected to JDownloader ${this.device.name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async finish() {
|
|
||||||
await this.client.core.disconnect();
|
|
||||||
Logger.info(`Disconnected from JDownloader ${this.device.name}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async addLinks(media) {
|
async addLinks(media) {
|
||||||
if (!(media instanceof Media)) {
|
if (!(media instanceof Media)) {
|
||||||
throw new TypeError('Invalid Media instance passed to downloader!');
|
throw new TypeError('Invalid Media instance passed to downloader!');
|
||||||
@ -88,19 +83,17 @@ class JDownloaderClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async startDownload(crawledLinks = []) {
|
async startDownload(crawledLinks = []) {
|
||||||
|
if (!crawledLinks.packageUUID) {
|
||||||
|
throw new JDownloaderError('Cannot start download without packageUUID!');
|
||||||
|
}
|
||||||
|
|
||||||
const linkIDs = crawledLinks.map((link) => link.uuid);
|
const linkIDs = crawledLinks.map((link) => link.uuid);
|
||||||
|
|
||||||
if (linkIDs.length < 1) {
|
if (linkIDs.length < 1) {
|
||||||
throw new JDownloaderError('No links to download!');
|
throw new JDownloaderError('No links to download!');
|
||||||
}
|
}
|
||||||
|
|
||||||
const packageUUID = crawledLinks[0].packageUUID;
|
await this.client.core.callAction('/linkgrabberv2/moveToDownloadlist', this.device.id, [linkIDs, [crawledLinks.packageUUID]]);
|
||||||
|
|
||||||
if (!packageUUID) {
|
|
||||||
throw new JDownloaderError('Cannot start download without packageUUID!');
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.client.core.callAction('/linkgrabberv2/moveToDownloadlist', this.device.id, [linkIDs, [packageUUID]]);
|
|
||||||
Logger.success('Download started.');
|
Logger.success('Download started.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
const { FatalError } = require('../../errors');
|
|
||||||
|
|
||||||
class MediaLinksFile {
|
|
||||||
constructor(filename) {
|
|
||||||
this.file = path.join(process.cwd(), filename);
|
|
||||||
|
|
||||||
if (!fs.existsSync(this.file)) {
|
|
||||||
throw new FatalError('The specified file could not be found!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
read() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
fs.readFile(this.file, (err, data) => {
|
|
||||||
if (err) {
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolve(MediaLinksFile.parseBuffer(data));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
write(newContent) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
fs.writeFile(this.file, newContent, null, (err) => {
|
|
||||||
if (err) {
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async removeFirstLink() {
|
|
||||||
const items = await this.read();
|
|
||||||
const serialized = MediaLinksFile.serialize(items.slice(1));
|
|
||||||
await this.write(serialized);
|
|
||||||
}
|
|
||||||
|
|
||||||
remove() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
fs.unlink(this.file, (err) => {
|
|
||||||
if (err) {
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static serialize(content) {
|
|
||||||
return content.map((line) => `${line}\r`).join('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
static parseBuffer(buffer) {
|
|
||||||
return buffer.toString()
|
|
||||||
.split('\n')
|
|
||||||
.filter((line) => line)
|
|
||||||
.map((line) => {
|
|
||||||
const returnCarriageIndex = line.indexOf('\r');
|
|
||||||
if (returnCarriageIndex < 0) {
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
return line.substring(0, returnCarriageIndex);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = MediaLinksFile;
|
|
@ -15,7 +15,7 @@ class Movie extends Media {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getDownloadFilename(ext) {
|
getDownloadFilename(ext) {
|
||||||
return `${this.name} (${this.year}).${ext}`;
|
return `${this.name} (${this.year})${ext}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,12 +17,6 @@ class KissAsianScraper {
|
|||||||
Logger.info('Cloudflare DDOS Protection bypassed, redirected to main site.');
|
Logger.info('Cloudflare DDOS Protection bypassed, redirected to main site.');
|
||||||
}
|
}
|
||||||
|
|
||||||
async finish(browser) {
|
|
||||||
await this.page.close();
|
|
||||||
await browser.close();
|
|
||||||
Logger.info('Closed browser instance.');
|
|
||||||
}
|
|
||||||
|
|
||||||
async authenticate(credentials) {
|
async authenticate(credentials) {
|
||||||
await this.page.click('#topHolderBox a[href="/Login"]');
|
await this.page.click('#topHolderBox a[href="/Login"]');
|
||||||
await this.page.waitForSelector('#btnSubmit');
|
await this.page.waitForSelector('#btnSubmit');
|
||||||
@ -177,7 +171,7 @@ class KissAsianScraper {
|
|||||||
if (span.textContent === 'Status:') {
|
if (span.textContent === 'Status:') {
|
||||||
const status = span.nextSibling.textContent;
|
const status = span.nextSibling.textContent;
|
||||||
|
|
||||||
return status.includes('Completed');
|
return status === 'Completed';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,13 +10,8 @@ class ArgsParser {
|
|||||||
parse(argv) {
|
parse(argv) {
|
||||||
const parsedArgs = parseArgs(argv, this.options);
|
const parsedArgs = parseArgs(argv, this.options);
|
||||||
this.validate(parsedArgs);
|
this.validate(parsedArgs);
|
||||||
|
|
||||||
const { _: [directory], ...rest } = parsedArgs;
|
|
||||||
|
|
||||||
return {
|
return parsedArgs;
|
||||||
...rest,
|
|
||||||
directory
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(parsedArgs) {
|
validate(parsedArgs) {
|
||||||
|
30
src/index.js
30
src/index.js
@ -2,10 +2,8 @@ const puppeteer = require('puppeteer-extra');
|
|||||||
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
|
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
|
||||||
const AdBlockerPlugin = require('puppeteer-extra-plugin-adblocker');
|
const AdBlockerPlugin = require('puppeteer-extra-plugin-adblocker');
|
||||||
const ArgsParser = require('./classes/utils/ArgsParser');
|
const ArgsParser = require('./classes/utils/ArgsParser');
|
||||||
const MediaLinksFile = require('./classes/filesystem/MediaLinksFile');
|
|
||||||
const KissAsianScraper = require('./classes/scraping/KissAsianScraper');
|
const KissAsianScraper = require('./classes/scraping/KissAsianScraper');
|
||||||
const JDownloaderClient = require('./classes/download/JDownloaderClient');
|
const JDownloaderClient = require('./classes/download/JDownloaderClient');
|
||||||
const Utils = require('./classes/utils/Utils');
|
|
||||||
const credentials = require('../data/credentials.json');
|
const credentials = require('../data/credentials.json');
|
||||||
|
|
||||||
const args = new ArgsParser().parse(process.argv.slice(2));
|
const args = new ArgsParser().parse(process.argv.slice(2));
|
||||||
@ -13,26 +11,10 @@ const args = new ArgsParser().parse(process.argv.slice(2));
|
|||||||
puppeteer.use(StealthPlugin());
|
puppeteer.use(StealthPlugin());
|
||||||
puppeteer.use(AdBlockerPlugin({ blockTrackers: true }));
|
puppeteer.use(AdBlockerPlugin({ blockTrackers: true }));
|
||||||
|
|
||||||
const singleMediaProcedure = async(scraper, downloader, mediaURL) => {
|
|
||||||
const media = await scraper.getMediaData(mediaURL);
|
|
||||||
await scraper.populateMediaDownloadURLs(media);
|
|
||||||
|
|
||||||
await downloader.addLinks(media);
|
|
||||||
|
|
||||||
const crawledLinks = await downloader.getCrawledLinks(media.downloadURLs);
|
|
||||||
const renamedCrawledLinks = downloader.getRenamedCrawledLinks(crawledLinks, media);
|
|
||||||
await downloader.renameCrawledLinks(renamedCrawledLinks);
|
|
||||||
|
|
||||||
await downloader.startDownload(crawledLinks);
|
|
||||||
};
|
|
||||||
|
|
||||||
const main = async() => {
|
const main = async() => {
|
||||||
const browser = await puppeteer.launch({ headless: !args.display, slowMo: 250 });
|
const browser = await puppeteer.launch({ headless: !args.display, slowMo: 250 });
|
||||||
const page = await browser.newPage();
|
const page = await browser.newPage();
|
||||||
|
|
||||||
const file = new MediaLinksFile(args.directory);
|
|
||||||
const mediaToDownload = await file.read();
|
|
||||||
|
|
||||||
const scraper = new KissAsianScraper(page);
|
const scraper = new KissAsianScraper(page);
|
||||||
const downloader = new JDownloaderClient(credentials.jdownloader);
|
const downloader = new JDownloaderClient(credentials.jdownloader);
|
||||||
|
|
||||||
@ -40,15 +22,9 @@ const main = async() => {
|
|||||||
await scraper.load();
|
await scraper.load();
|
||||||
await scraper.authenticate(credentials.kissasian);
|
await scraper.authenticate(credentials.kissasian);
|
||||||
|
|
||||||
await Utils.mapSeries(mediaToDownload, async(url) => {
|
const media = await scraper.getMediaData('https://kissasian.li/Drama/My-Roommate-is-a-Gumiho');
|
||||||
await singleMediaProcedure(scraper, downloader, url);
|
|
||||||
await file.removeFirstLink();
|
await scraper.populateMediaDownloadURLs(media);
|
||||||
});
|
|
||||||
|
|
||||||
await file.remove();
|
|
||||||
await downloader.finish();
|
|
||||||
await scraper.finish(browser);
|
|
||||||
process.exit(0);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user