Skip to content
This repository has been archived by the owner on Jul 1, 2024. It is now read-only.

Commit

Permalink
Add new grabber using captchaModal
Browse files Browse the repository at this point in the history
  • Loading branch information
thorio committed Dec 18, 2019
1 parent 6d91e18 commit a4ab030
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 11 deletions.
5 changes: 4 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ module.exports = {
"require-atomic-updates": "off",
"no-unused-vars": "warn",
"no-useless-escape": "warn",
"no-await-in-loop": "warn",
"no-await-in-loop": "off",
"dot-location": ["warn", "property"],
"semi": "warn",
"no-restricted-globals": ["error", "status"],
"comma-dangle": ["warn", {
"arrays": "always-multiline",
"objects": "always-multiline",
}],
"no-constant-condition": ["warn", {
"checkLoops": false,
}],
}
}
12 changes: 10 additions & 2 deletions src/js/UI/linkDisplay.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,28 @@ let load = exports.load = () => {
loadActions(actions.available(status.serverID, status.linkType, status.automaticDone));

shared.applyColors();
$("#KG-linkdisplay").show();
show(true);
};

/**
* @param {Boolean} instant
*/
let show = exports.show = (instant) =>
instant ? $("#KG-linkdisplay").show() : $("#KG-linkdisplay").slideDown();

let hide = exports.hide = () =>
$("#KG-linkdisplay").slideUp();

function setTitle(text) {
$("#KG-linkdisplay .KG-dialog-title").text(text);
}

// TODO convert to html table
// TODO add metadata display
/**
* @param {Episode[]} episodes
*/
function loadLinks(episodes) { // TODO refactor this
function loadLinks(episodes) {
let html = "";
let padLength = Math.max(2, page.episodeCount().toString().length);
util.for(episodes, (i, /** @type {Episode} */ obj) => {
Expand Down
2 changes: 0 additions & 2 deletions src/js/actions/beta.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ async function tryGetQuality(episode) {
let parsedQualityPrefs = preferences.general.quality_order.replace(/\s/g, "").split(",");
for (let i of parsedQualityPrefs) {
if (qualityStrings[i]) {
// don't want to needlessly spam the servers
// eslint-disable-next-line no-await-in-loop
if (await util.ajax.head(rawLink + qualityStrings[i]).status == HttpStatusCodes.OK) {
episode.processedLink = rawLink + qualityStrings[i];
return;
Expand Down
1 change: 1 addition & 0 deletions src/js/config/sites/kissanime.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ let servers = new Dictionary([
regex: /"https:\/\/www.novelplanet.me\/v\/.*?"/,
name: "Nova",
linkType: LinkTypes.EMBED,
customStep: "modalBegin",
}),

new Server("beta2", {
Expand Down
86 changes: 86 additions & 0 deletions src/js/steps/captchaModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// needed for jsdoc
/* eslint-disable no-unused-vars */
const Episode = require("../types/Episode");
/* eslint-enable no-unused-vars */

const util = require("../util"),
statusManager = require("../statusManager"),
config = require("../config"),
linkDisplay = require("../UI/linkDisplay"),
captchaModal = require("../UI/captchaModal"),
Captcha = require("../types/Captcha");

const status = statusManager.get(),
site = config.sites.current();

exports.modalBegin = async () => {
linkDisplay.show();
linkDisplay.showSpinner();
let progress = 0;
let func = async ( /** @type {Episode} */ episode) => {
let html = await doCaptcha(`${episode.kissLink}&s=${status.serverID}`);
getLink(html, episode);
progress++;
setStatusText(`${progress}/${promises.length}`);
};
let promises = [];
util.for(status.episodes, (i, /** @type {Episode} */ obj) => {
promises.push(func(obj));
});
setStatusText(`0/${promises.length}`);
await Promise.all(promises);
status.func = "defaultFinished";
statusManager.save();
linkDisplay.load();
};

function setStatusText(str) {
linkDisplay.setSpinnerText(str);
captchaModal.setStatusText(str);
}

/**
* Handles the entire captcha process
* @param {String} url
* @returns {String} html of or empty string if captcha failed
*/
async function doCaptcha(url) {
while (true) {
let html = (await util.ajax.get(url)).response;
let $form = $(html).find("form#formVerify1");
if ($form.length == 0) {
return html; // no captcha!
}
let texts = [];
$form.find("span:lt(2)").each((_i, obj) => texts.push(obj.innerText.replace(/[ \n]*(\w)/, "$1")));
let images = [];
$form.find("img").each((i, obj) => images.push(obj.src));
let answerCap = (await captchaModal.queue(new Captcha(texts, images))).join(",") + ","; // trailing comma because... kissanime
let response = (await util.ajax.post("/Special/AreYouHuman2", util.urlEncode({ reUrl: url, answerCap }), { "content-type": "application/x-www-form-urlencoded" })).response;
if (response.includes("AreYouHuman2")) {
continue; // captcha failed, retry
}
return response; // captcha completed
}
}

/**
* @param {String} html
* @param {Episode} episode
*/
function getLink(html, episode) {
let link = site.servers.get(status.serverID).findLink(html);
if (link) {
episode.grabbedLink = link;
} else {
episode.error = "error: server not available or captcha";
}
}

/**
* @param {String} html
* @returns {Boolean}
*/
function isCaptcha(html) {
return $(html).find("form#formVerify1").length > 0;
}
5 changes: 3 additions & 2 deletions src/js/steps/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//allows multiple different approaches to collecting links

module.exports = Object.assign(
module.exports = Object.assign({},
require("./default"),
require("./turbo")
require("./turbo"),
require("./captchaModal")
);
13 changes: 9 additions & 4 deletions src/js/util/ajax.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
/**
* @typedef {Object} Response
* @property {String} response
*/

/**
* Makes an HTTP request
* @param {String} method
* @param {String} url
* @param {Object} obj
* @param {any} obj.data
* @param {Object} obj.headers
* @returns {Promise<Object>} Response
* @returns {Promise<Response>} Response
* @private
*/
function request(method, url, { data, headers } = {}) {
Expand All @@ -25,7 +30,7 @@ function request(method, url, { data, headers } = {}) {
* Makes a HTTP GET request
* @param {String} url
* @param {Object} headers
* @returns {Promise<Object>} Response
* @returns {Promise<Response>} Response
*/
exports.get = (url, headers) => {
return request("GET", url, { headers });
Expand All @@ -36,7 +41,7 @@ exports.get = (url, headers) => {
* @param {String} url
* @param {Object} headers
* @param {Object} data
* @returns {Promise<Object>} Response
* @returns {Promise<Response>} Response
*/
exports.post = (url, data, headers) => {
return request("POST", url, { data, headers });
Expand All @@ -46,7 +51,7 @@ exports.post = (url, data, headers) => {
* Makes a HTTP HEAD request
* @param {String} url
* @param {Object} headers
* @returns {Promise<Object>} Response
* @returns {Promise<Response>} Response
*/
exports.head = (url, headers) => {
return request("HEAD", url, { headers });
Expand Down
13 changes: 13 additions & 0 deletions src/js/util/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,16 @@ exports.merge = (obj1, obj2) =>
*/
exports.last = (arr) =>
arr[arr.length - 1];

/**
* form/urlencodes the given object
* @param {Object} obj
* @returns {String}
*/
exports.urlEncode = (obj) => {
let str = "";
for (let i in obj) {
str += `${encodeURIComponent(i)}=${encodeURIComponent(obj[i])}&`;
}
return str.slice(0, -1); // remove trailing '&'
};

0 comments on commit a4ab030

Please sign in to comment.