`);
}
KG.spinnerText = (str) => {
$("#KG-spinner-text").text(str);
}
//hides the linkdisplay
KG.closeLinkdisplay = () => {
$("#KG-linkdisplay").slideUp();
KG.clearStatus();
}
//saves a new preferred server
KG.updatePreferredServer = () => {
localStorage["KG-preferredServer"] = $("#KG-input-server").val();
}
//loads preferred server
KG.loadPreferredServer = () => {
$("#KG-input-server").val(localStorage["KG-preferredServer"]);
}
KG.showPreferences = () => {
$("#KG-preferences").slideDown();
}
KG.closePreferences = () => {
KG.savePreferences();
$("#KG-preferences").slideUp();
}
//applies regex to html page to find a link
KG.findLink = (html, regexString) => {
var re = new RegExp(regexString);
var result = html.match(re);
if (result && result.length > 0) {
return result[0].split('"')[1];
}
return "";
}
//wildcard-enabled string comparison
KG.if = (str, rule) => {
return new RegExp("^" + rule.split("*").join(".*") + "$").test(str);
}
//iterates over an array with supplied function
//either (array, min, max, func)
//or (array, func)
KG.for = (array, min, max, func) => {
if (typeof min == "function") {
func = min;
max = array.length - 1;
}
min = Math.max(0, min) || 0;
max = Math.min(array.length - 1, max);
for (var i = min; i <= max; i++) {
func(i, array[i]);
}
}
//removes characters that have special meaning in a batch file or are forbidden in directory names
KG.makeBatSafe = (str) => {
return str.replace(/[%^&<>|:\\/?*"]/g, "_");
}
KG.get = (url) => {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: url,
onload: (o) => {
resolve(o.response);
},
onerror: () => {
reject();
}
});
});
}
KG.head = (url) => {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "HEAD",
url: url,
onload: (o) => {
resolve(o.status);
},
onerror: () => {
reject();
}
});
});
}
//allows multiple different approaches to collecting links, if sites differ greatly
KG.steps = {};
//default
KG.steps.defaultBegin = () => {
KG.status.func = "defaultGetLink";
KG.saveStatus();
location.href = KG.status.episodes[KG.status.current].kissLink + `&s=${KG.status.server}`;
}
KG.steps.defaultGetLink = () => {
if (!KG.if(location.pathname, KG.supportedSites[location.hostname].contentPath)) { //captcha
return;
}
link = KG.findLink(document.body.innerHTML, KG.knownServers[KG.status.server].regex);
KG.status.episodes[KG.status.current].grabLink = link || "error (selected server may not be available)";
KG.status.current++;
if (KG.status.current >= KG.status.episodes.length) {
KG.status.func = "defaultFinished";
location.href = KG.status.url;
} else {
location.href = KG.status.episodes[KG.status.current].kissLink + `&s=${KG.status.server}`;
}
KG.saveStatus();
}
KG.steps.defaultFinished = () => {
KG.displayLinks();
}
KG.steps.turboBegin = async () => {
$("#KG-linkdisplay").slideDown();
KG.showSpinner();
var progress = 0;
var func = async (ep) => {
var html = await KG.get(ep.kissLink + `&s=${KG.status.server}`);
var link = KG.findLink(html, KG.knownServers[KG.status.server].regex);
ep.grabLink = link || "error: server not available or captcha";
progress++;
KG.spinnerText(`${progress}/${promises.length}`)
};
var promises = [];
KG.for(KG.status.episodes, (i, obj) => {
promises.push(func(obj));
});
KG.spinnerText(`0/${promises.length}`)
await Promise.all(promises);
KG.status.func = "defaultFinished";
KG.saveStatus();
KG.displayLinks();
}
//allows for multiple ways to export collected data
KG.exporters = {};
KG.exporters.list = {
name: "list",
extension: "txt",
requireSamePage: false,
requireDirectLinks: false,
export: (data) => {
var str = "";
for (var i in data.episodes) {
str += data.episodes[i].grabLink + "\n";
}
return str;
}
}
KG.exporters.m3u = {
name: "m3u8 playlist",
extension: "m3u8",
requireSamePage: true,
requireDirectLinks: true,
export: (data) => {
var listing = $(".listing a").get().reverse();
var str = "#EXTM3U\n";
KG.for(data.episodes, (i, obj) => {
str += `#EXTINF:0,${listing[obj.num-1].innerText}\n${obj.grabLink}\n`;
});
return str;
}
}
KG.exporters.json = {
name: "json",
extension: "json",
requireSamePage: true,
requireDirectLinks: false,
export: (data) => {
var listing = $(".listing a").get().reverse();
var json = {
title: data.title,
server: data.server,
linkType: data.linkType,
episodes: []
};
for (var i in data.episodes) {
json.episodes.push({
number: data.episodes[i].num,
name: listing[data.episodes[i].num - 1].innerText,
link: data.episodes[i].grabLink
});
}
return JSON.stringify(json);
},
}
KG.exporters.html = {
name: "html list",
extension: "html",
requireSamePage: true,
requireDirectLinks: true,
export: (data) => {
var listing = $(".listing a").get().reverse();
var str = "\n \n";
KG.for(data.episodes, (i, obj) => {
str += `
${listing[obj.num-1].innerText}\n`;
});
str += " \n\n";
return str;
}
}
KG.exporters.csv = {
name: "csv",
extension: "csv",
requireSamePage: true,
requireDirectLinks: false,
export: (data) => {
var listing = $(".listing a").get().reverse();
var str = "episode, name, url\n";
for (var i in data.episodes) {
str += `${data.episodes[i].num}, ${listing[data.episodes[i].num-1].innerText}, ${data.episodes[i].grabLink}\n`;
}
return str;
}
}
KG.exporters.aria2c = {
name: "aria2c file",
extension: "txt",
requireSamePage: false,
requireDirectLinks: true,
export: (data) => {
var listing = $(".listing a").get().reverse();
var str = "";
KG.for(data.episodes, (i, obj) => {
str += `${obj.grabLink}\n out=${listing[obj.num-1].innerText}.mp4\n`;
});
return str;
}
}
KG.exporters.idmbat = {
name: "IDM bat file",
extension: "bat",
requireSamePage: true,
requireDirectLinks: true,
export: (data) => {
var listing = $(".listing a").get().reverse();
var title = KG.makeBatSafe(data.title);
var str = `::download and double click me!
@echo off
set title=${title}
set idm=${KG.preferences.internet_download_manager.idm_path}
set args=${KG.preferences.internet_download_manager.arguments}
set path=%~dp0
if not exist "%idm%" echo IDM not found && echo check your IDM path in preferences && goto end
mkdir "%title%" > nul
start "" "%idm%"\n\n`;
KG.for(data.episodes, (i, obj) => {
var epTitle = KG.makeBatSafe(listing[obj.num - 1].innerText);
if (!KG.preferences.internet_download_manager.keep_title_in_episode_name &&
epTitle.slice(0, title.length) === title) {
epTitle = epTitle.slice(title.length + 1);
}
str += `"%idm%" /n /p "%path%\\%title%" /f "${epTitle}.mp4" /d "${obj.grabLink}" %args%\n`;
});
str += "\necho done.\necho.\n:end\npause";
return str;
}
}
//further options after grabbing, such as converting embed to direct links
KG.actions = {};
KG.actionAux = {};
KG.actions.rapidvideo_getDirect = {
name: "get direct links",
requireLinkType: "embed",
servers: ["rapidvideo", "rapid"],
execute: async (data) => {
KG.showSpinner();
var promises = [];
var progress = [0];
for (var i in data.episodes) {
promises.push(KG.actionAux["rapidvideo_getDirect"](data.episodes[i], progress, promises));
}
KG.spinnerText(`0/${promises.length}`);
await Promise.all(promises);
data.linkType = "direct";
KG.saveStatus();
KG.displayLinks();
},
}
//additional function to reduce clutter
//asynchronously gets the direct link
KG.actionAux.rapidvideo_getDirect = async (ep, progress, promises) => {
$html = $(await KG.get(ep.grabLink));
$sources = $html.find("source");
if ($sources.length == 0) {
ep.grabLink = "error: no sources found";
return;
}
var sources = {};
KG.for($sources, (i, obj) => {
sources[obj.dataset.res] = obj.src;
});
progress[0]++;
KG.spinnerText(`${progress[0]}/${promises.length}`);
var parsedQualityPrefs = KG.preferences.general.quality_order.replace(/\ /g, "").split(",");
for (var i of parsedQualityPrefs) {
if (sources[i]) {
ep.grabLink = sources[i];
return;
}
}
ep.grabLink = "error: preferred qualities not found";
}
KG.actions.beta_setQuality = {
name: "set quality",
requireLinkType: "direct",
servers: ["beta", "beta2"],
automatic: true,
execute: async (data) => {
KG.showSpinner();
var promises = [];
var progress = [0];
for (var i in data.episodes) {
promises.push(KG.actionAux["beta_tryGetQuality"](data.episodes[i], progress, promises));
}
KG.spinnerText(`0/${promises.length}`);
await Promise.all(promises);
data.automaticDone = true;
KG.saveStatus();
KG.displayLinks();
},
}
KG.actionAux.beta_tryGetQuality = async (ep, progress, promises) => {
var rawLink = ep.grabLink.slice(0, -4);
var qualityStrings = {"1080": "=m37", "720": "=m22", "360": "=m18"};
var parsedQualityPrefs = KG.preferences.general.quality_order.replace(/\ /g, "").split(",");
for (var i of parsedQualityPrefs) {
if (qualityStrings[i]) {
if (await KG.head(rawLink + qualityStrings[i]) == 200) {
ep.grabLink = rawLink + qualityStrings[i];
progress[0]++;
KG.spinnerText(`${progress[0]}/${promises.length}`);
return;
}
}
}
}
//if something doesn't look right on a specific site, a fix can be written here
KG.fixes = {}
KG.fixes["kimcartoon.to_UIFix"] = () => {
//linkdisplay
var $ld = $("#KG-linkdisplay");
$ld.find(".barTitle").removeClass("barTitle")
.css({
"height": "20px",
"padding": "5px",
});
$("#KG-linkdisplay-title").css({
"font-size": "20px",
"color": $("a.bigChar").css("color"),
})
$ld.find(".arrow-general").remove();
//preference panel
var $pf = $("#KG-preferences");
$pf.find(".barTitle").removeClass("barTitle")
.css({
"height": "20px",
"padding": "5px",
});
$("#KG-linkdisplay-title").css({
"font-size": "20px",
"color": $("a.bigChar").css("color"),
});
$pf.find(".arrow-general").remove();
//opts
var $opts = $("#KG-opts-widget");
var title = $opts.find(".barTitle").html();
$opts.before(`
${title}
`);
$(".icon:eq(1)").css({ "width": "100%", "box-sizing": "border-box" });
$(".KG-preferences-button").css("margin-top", "5px");
$opts.find(".barTitle").remove();
$opts.find(".arrow-general").remove();
//general
$(".KG-dialog-title").css("font-size", "18px");
}
KG.fixes["kissasian.sh_UIFix"] = () => {
$(".KG-preferences-button").css("filter", "invert(0.7)");
$(".KG-dialog-close").css("color", "#000");
$(".KG-dialog-close").hover((e) => {
$(e.target).css("color", e.type == "mouseenter" ? "#fff" : "#000");
});
}
//HTML and CSS pasted here because Tampermonkey apparently doesn't allow resources to be updated
//if you have a solution for including extra files that are updated when the script is reinstalled please let me know: thorio.git@gmail.com
//the grabber widget injected into the page
var optsHTML = `
`;
//initially hidden HTML that is revealed and filled in by the grabber script
var linkListHTML = `
`;
//initially hidden HTML that is revealed and filled in by the grabber script
var prefsHTML = `
`;
//css to make it all look good
var grabberCSS = `.KG-episodelist-header {
width: 3%;
text-align: center !important;
}
.KG-episodelist-number {
text-align: right;
padding-right: 4px;
}
.KG-episodelist-button {
background-color: #527701;
color: #ffffff;
border: none;
cursor: pointer;
}
.KG-input-episode {
width: 40px;
border: 1px solid #666666;
background: #393939;
padding: 3px;
color: #ffffff;
}
.KG-input-text {
width: 150px;
border: 1px solid #666666;
background: #393939;
padding: 3px;
margin-left: 5px;
color: #ffffff;
}
.KG-input-checkbox {
height: 22px;
}
#KG-input-server {
width: 100%;
font-size: 14.5px;
color: #fff;
}
#KG-input-export {
margin: 6px;
float: left;
color: #fff;
}
.KG-button {
background-color: #548602;
color: #ffffff;
border: none;
padding: 5px;
padding-left: 12px;
padding-right: 12px;
font-size: 15px;
margin: 3px;
float: left;
}
.KG-button-container {
margin-top: 10px;
height: 34px;
}
.KG-dialog-title {
width: 80%;
float: left;
}
#KG-linkdisplay-text {
word-break: break-all;
}
.KG-linkdisplay-row {
display: flex;
flex-direction: row;
}
.KG-linkdisplay-episodenumber {
min-width: 30px;
text-align: right;
user-select: none;
margin-right: 5px;
}
#KG-linkdisplay-export {
margin-top: 10px;
}
#KG-linkdisplay-export-text {
width: 100%;
height: 150px;
min-height: 40px;
resize: vertical;
background-color: #222;
color: #fff;
border: none;
}
.KG-dialog-close {
float: right;
cursor: pointer;
font-size: 17px;
}
.KG-dialog-close:hover {
color: #eee;
}
#KG-preferences-container-outer {
overflow: auto;
}
.KG-preferences-header {
font-size: 17px;
letter-spacing: 0px;
width: 100%;
margin: 10px 0 5px 0;
}
#KG-preferences-container {
overflow: auto;
}
#KG-preferences-container div {
box-sizing: border-box;
height: 26px;
width: 50%;
padding: 0 5px;
margin: 2px 0;
float: left;
line-height: 26px;
font-size: 14px;
}
#KG-preferences-container div span {
padding-top: 5px;
}
.KG-preferences-button {
width: 18px;
height: 18px;
margin: 3px;
float: right;
border: none;
background-color: #0000;
opacity: 0.7;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAC4jAAAuIwF4pT92AAAFHGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOCAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDE5LTA1LTMxVDE0OjQ5OjI5KzAyOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxOS0wNS0zMVQxNToxMzozNCswMjowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxOS0wNS0zMVQxNToxMzozNCswMjowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpkYTg5NGI2Mi1lOWEwLTg2NGYtYTg0Mi1lM2JkOTY3ZWI4ZTgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ZGE4OTRiNjItZTlhMC04NjRmLWE4NDItZTNiZDk2N2ViOGU4IiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6ZGE4OTRiNjItZTlhMC04NjRmLWE4NDItZTNiZDk2N2ViOGU4Ij4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDpkYTg5NGI2Mi1lOWEwLTg2NGYtYTg0Mi1lM2JkOTY3ZWI4ZTgiIHN0RXZ0OndoZW49IjIwMTktMDUtMzFUMTQ6NDk6MjkrMDI6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE4IChXaW5kb3dzKSIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7gRsl1AAAB4klEQVRIia2WO2tUQRiGn91EIUJQCzGFREwX0MUbKBaBSBRNYSGCLFY2goXgpVH8KbYighArsRDWSrAJBizSJBgtRFQMJlrENXkszi7OTuacHSUvDJzzXd75LjPfOahkrAl1WV0J1uUc3zp5OA3sAoaDNZnjmNqgCcwAewLZjoTd7uB5CHgK3NtkFaXU9C++qcfUo+qCm/FZnVIb6odAfjvkDMmvJkj+Fze7vDW1m8wb4HBOXTNRBwx7cAH4sUXk54Ei8qgHp9R2Rerr6lqf8ty34piuALVERKvADWC0sy4B8yXRfwlfauo4MAE0gIvASIL8CLAYyQeA18DxRJAPgFlgjoyUr1l+Uw/18W3X1I2SsnRxAFiq0H8C9pboNupAu8IZYL2Pvsp/rQ5s70NwokK3H9hXoR+qqVPAGYpSnAV2RkbvgYOk78gzYDqS/QZawDvgVdy0k+qvRLMW1XPqYMeuob4oaeytkHMw2n2hE8G2SD4GPAc+dvSjFWX52vMW7Dagvu1z7HKwqo6bmKYPt4C8i7ZFwD2jolWR9r/iCSXD7koUyR2Lb+9SIsqf6nV1Uv0eyB+HnKnr31Tn1elAdjexQSvQj6hz6qOYL+ePAot5FGMmxzc+pmWYBZahx/5ljuMfM3Ph5QSIQroAAAAASUVORK5CYII=");
background-size: cover;
cursor: pointer;
}
.KG-preferences-button:hover {
opacity: 1;
}
.KG-preferences-help-button {
position: absolute;
font-size: 20px;
margin-left: 10px;
}
.KG-preferences-help-button:hover {
color: #fff;
}
.right {
float: right;
}
#KG-spinner-text {
width: 100%;
text-align: center;
margin-top: -40px;
margin-bottom: 40px;
min-height: 20px;
}
/*
https://projects.lukehaas.me/css-loaders/
*/
.loader,
.loader:after {
border-radius: 50%;
width: 10em;
height: 10em;
}
.loader {
margin: 0px auto;
font-size: 5px;
position: relative;
text-indent: -9999em;
border-top: 1.1em solid rgba(255, 255, 255, 0.2);
border-right: 1.1em solid rgba(255, 255, 255, 0.2);
border-bottom: 1.1em solid rgba(255, 255, 255, 0.2);
border-left: 1.1em solid #ffffff;
-webkit-transform: translateZ(0);
-ms-transform: translateZ(0);
transform: translateZ(0);
-webkit-animation: load8 1.1s infinite linear;
animation: load8 1.1s infinite linear;
}
@-webkit-keyframes load8 {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes load8 {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}`;
KG.siteLoad();