KissAnime Downloader

This is a userscript that will download multi episodes form KissAnime.

  1. // ==UserScript==
  2. // @name KissAnime Downloader
  3. // @namespace https://greasyfork.org/en/users/135934-anime-bro1
  4. // @version 3.3.1
  5. // @description This is a userscript that will download multi episodes form KissAnime.
  6. // @author AnimeBro1
  7. // @homepage https://github.com/Eltion/Kissanime-Downloader
  8. // @match http://kissanime.ru/Anime/*
  9. // @include http://kissanime.ru/Anime/*
  10. // @exclude http://kissanime.ru/Anime/*/*
  11. // @grant GM_getValue
  12. // @grant GM_listValues
  13. // @run-at document-end
  14. // @grant GM_deleteValue
  15. // @grant GM_setValue
  16. // @grant GM_xmlhttpRequest
  17. // @require http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
  18.  
  19. // @require https://cdn.rawgit.com/Eltion/Kissanime-Downloader/ee154d713ce5af9c031b4abdd20fae8bb7cc2dc5/css.js
  20. // @require https://cdn.rawgit.com/Eltion/Kissanime-Downloader/4fc64d92baba62fb52de03a3472464c2b6466ed9/vr2.js
  21. // @require https://cdn.rawgit.com/Stuk/jszip/579beb1d45c8d586d8be4411d5b2e48dea018c06/dist/jszip.min.js
  22. // @require https://cdn.rawgit.com/Eltion/Kissanime-Downloader/b24ffcadd00a4f3eda526e213f4d4c8d5196af6c/FlieSaver.js
  23.  
  24. // ==/UserScript==
  25.  
  26. var curretEP = "";
  27. var currnetEpIndex = 0;
  28. var EpisodesName = [];
  29. var EpisodesLinks = [];
  30. var EpisodesVideoLinks = [];
  31. var isEval = false;
  32.  
  33.  
  34. var images = ["","","",""];
  35. var imagecount = 0;
  36. var imagesURL;
  37. var imageURLcount = 0;
  38. var clickNr = 0;
  39. var w;
  40.  
  41. var nameOfAnime = "";
  42.  
  43. var start = "";
  44. var end = "";
  45. var isText = false;
  46. var isHTML = false;
  47. var isM3U8 = false;
  48. var isRapid = false;
  49. var isBeta = false;
  50. var isIDM = false;
  51. var server = 1;
  52. var quality = [];
  53.  
  54. var coutFailedCh = 0;
  55.  
  56. var max = 1;
  57.  
  58.  
  59.  
  60. (function() {
  61. if(!isBasicJson()){
  62. factoryReset();
  63. getBasicJson();
  64. }
  65. //curretEP = "http://kissanime.ru/Anime/Shokugeki-no-Souma-San-no-Sara/Episode-005?id=140040";
  66. //getEp(curretEP);
  67. //getE();
  68. max = $(".listing").find("a").toArray().length;
  69. setUI();
  70. $("#aend").attr('value',max+"");
  71. $("#startscript").on('click',function(){
  72. start = $("#astart").val();
  73. end = $("#aend").val();
  74. if($("#aquality").val().includes(",")){
  75. quality = $("#aquality").val().split(",");
  76. }else{
  77. quality = [$("#aquality").val()];
  78. }
  79. isText = $("#atxt").get(0).checked;
  80. isHTML = $("#ahtml").get(0).checked;
  81. isM3U8 = $("#am3u8").get(0).checked;
  82. isIDM = $("#idm").get(0).checked;
  83. isBeta = $("#abeta").get(0).checked;
  84. isRapid = $("#arapid").get(0).checked;
  85. if(isBeta){
  86. server = 1;
  87. }else if(isRapid){
  88. server = 2;
  89. }else{
  90. alert("Select a server");
  91. return;
  92. }
  93. nameOfAnime = location.href.split("/")[4].replace(/-/g," ");
  94. //alert(nameOfAnime);
  95. $("#adownloader").hide(500);
  96. $("#ainfo").show(500);
  97. getAllEpisodes();
  98. });
  99. })();
  100.  
  101. function getE(){
  102. var x = GM_listValues();
  103. var b = "";
  104. for(var i =0; i < x.length; i++){
  105. b += '"'+x[i]+'":"'+GM_getValue(x[i])+'",';
  106. }
  107. $('body').html("<p>"+b+"</p>");
  108. }
  109.  
  110. function setUI(){
  111. $("body").append('<div id="CaptchaInfo" style="z-index: 99999999; display:none;width:200px;height:150px;font-size:14px;position:fixed; top: 10px; left:10px; background: #14dd3edb; border-radius: 25px;padding:40px;"><p></p></div>');
  112. var imgSrc = "https://cdn.rawgit.com/Eltion/Kissanime-Downloader/024c2d98b5580a14d1eaf74276d641c88f04764a/Download%20ButtonGreen.png";
  113. var html = '<div id="adownloader" style="position:fixed; bottom:10px; left:10px; z-index: 99999999;"><img id="startscript" style="cursor:pointer;float:left;position: relative; top:5px;margin-right:10px;" width="90px" src="'+imgSrc+'"><div style="background: #14dd3edb; position: relative;height:90px;padding:10px;border-radius: 10px;/* text-align:center; */color: white;float: left;"><div style="display: inline-block;float: left;margin-top: 13px;margin-left: 10px;">Start: <input value="1" id="astart" style="color:white;text-align:center;width: 30px;background: transparent;border: 0.5px solid white;border-radius:5px;" type="text"><input id="aend" value="7" style="color:white;text-align:center;width: 30px;background: transparent;border: 0.5px solid white;border-radius:5px;float: right;" type="text"><span style=" float: right; margin-right: 5px; ">End:</span><br><br>Quality: <input id="aquality" value="1080,720,480,360" style="color:white;text-align:center;width: 120px;background: transparent;border: 0.5px solid white;border-radius:5px;" type="text"></div><div style="display:inline-block;float:left;margin: 0px 10px;vertical-align: middle;"><input id="atxt" type="checkbox" style=" vertical-align: middle; ">Text<br><input id="ahtml" type="checkbox" style=" vertical-align: middle; ">Html<br><input id="am3u8" type="checkbox" style=" vertical-align: middle; ">M3u8<br><input id="idm" type="checkbox" style=" vertical-align: middle; ">IDM</div><div style="display:inline-block;float:left;margin: 0px 10px;vertical-align: middle;"><input id="abeta" type="checkbox" style=" vertical-align: middle; ">Beta<br><input id="arapid" type="checkbox" style=" vertical-align: middle; ">RapidVideo <br /><div style="text-align: center; font-size: 14pt;margin-top:10px;"><a href="https://github.com/Eltion/Kissanime-Downloader" target="_blank" >Help?</a></div></div></div></div>';
  114. var html2 = "<div id='ainfo' style=' padding:10px;z-index: 99999999; border-radius:20px;position:fixed; display: none; bottom:10px; right:10px; background:#14dd3edb;height:100px;width:400px;'><h3 style='text-align: center'>KissAnime Downloader</h3><p style='width:100%; word-wrap: break-word;' id='aoutput'></p><p id='aprogress'></p></div>";
  115. //var html3 = "<div id='ainfo2' style='background: red; padding: 10px; position: a'>"
  116. $('body').append(html);
  117. $('body').append(html2);
  118. }
  119.  
  120. function getEp(url){
  121. console.log(currnetEpIndex);
  122. $('#aoutput').html("Grabbing: "+url+"...");
  123. var msg = $.ajax({type: "GET", url: url, async: false}).responseText;
  124. if(isCapacha(msg)){
  125. GetWords(msg,function(){
  126. getImages(msg);
  127. });
  128. }else{
  129. if(server == 1){
  130. beta(msg);
  131. }else if(server == 2){
  132. rapidvideo(msg);
  133. }
  134. }
  135. }
  136.  
  137. function getAllEpisodes(){
  138. EpisodesLinks =[];
  139. EpisodesName = [];
  140. var x = $(".listing").find("a").toArray();
  141. console.log(x);
  142. for(var i =0; i < x.length; i++){
  143. if(!x[i].href.includes("reddit")){
  144. var ee = "";
  145. if(server == 1){
  146. ee = x[i].href+"&s=beta&pfail=1";
  147. }else{
  148. ee = x[i].href+"&s=rapidvideo";
  149. }
  150. EpisodesLinks.push(ee);
  151. EpisodesName.push(x[i].innerText);
  152. }
  153. }
  154.  
  155. if(parseInt(start) < 0){
  156. alert("Error: Start < 0");
  157. return;
  158. }else if(parseInt(end) < parseInt(start)){
  159. alert(end+" "+start);
  160. alert("Error: Start > End");
  161. return;
  162. }else if(parseInt(end) > EpisodesLinks.length){
  163. alert("End > total nr of episodes. Max nr "+EpisodesLinks.length);
  164. return;
  165. }else if(!(isText || isHTML || isM3U8 || isIDM)){
  166. alert("Please select one of the opitons");
  167. return;
  168. }
  169.  
  170. EpisodesLinks.reverse();
  171. EpisodesName.reverse();
  172. EpisodesLinks = EpisodesLinks.slice( parseInt(start)-1, parseInt(end));
  173. EpisodesName = EpisodesName.slice(parseInt(start)-1,parseInt(end));
  174.  
  175. console.log(EpisodesLinks);
  176. curretEP = EpisodesLinks[0];
  177. getEp(curretEP);
  178. }
  179.  
  180.  
  181.  
  182.  
  183. function getImages(html){
  184. //console.log(html);
  185. imagesURL = html.match(/CapImg[^"']*/g);
  186. //console.log(imagesURL);
  187. toDataURL(imagesURL[0],function(data){allDone(data);});
  188. }
  189.  
  190. function GetWords(html,callbackGetImages){
  191. var form = html.split("formVerify")[1].split("</form")[0];
  192. var x = form.match(/(?:<span[^>]*>\s*)([^<]*)/g);
  193.  
  194. var word1 = x[0].split(">")[1].replace(/\s\s/g,"");
  195.  
  196. var word2 = x[1].split(">")[1].replace(/\s\s/g,"");
  197. w = [word1,word2];
  198. callbackGetImages();
  199. }
  200.  
  201.  
  202. function allDone(d){
  203. console.log(d);
  204. imageURLcount++;
  205. images[imagecount] = cutImage64(cutImage64(d,3),2);
  206. if(imagecount == 3){
  207. console.log(images);
  208. Complete();
  209. }else{
  210. toDataURL(imagesURL[imageURLcount],function(data){allDone(data);});
  211. imagecount++;
  212. }
  213. }
  214.  
  215. function Complete() {
  216. var postData = "";
  217. //console.log(w);
  218. for(var j = 0; j <2; j++){
  219. var w1 = GM_getValue(w[j], false);
  220. if(w1 !== false){
  221. if(w1.includes(" ")){
  222. w1 = w1.split(" ");
  223. }else{
  224. w1 = [w1];
  225. }
  226. for(var k =0; k < w1.length; k++){
  227. for(var i = 0; i < images.length; i++){
  228. if(images[i] === w1[k]){
  229. postData += i+",";
  230. }
  231. }
  232. }
  233. }
  234. }
  235.  
  236. if(postData.length == 4){
  237. postdata(postData);
  238. }else{
  239. coutFailedCh++;
  240. if(coutFailedCh < 3){
  241. getNextEpisode(false);
  242. }else{
  243. coutFailedCh =0;
  244. MobileFallBack();
  245. }
  246. }
  247. }
  248.  
  249. function MobileFallBack(){
  250. console.log("MobileFallBack: "+ EpisodesLinks[currnetEpIndex]);
  251. var id = EpisodesLinks[currnetEpIndex].split("?id=")[1].split("&")[0];
  252. var x = $.ajax({type: "POST", url:"http://kissanime.ru/Mobile/GetEpisode", data:{eID:id},async: false}).responseText;
  253. x = x.split("|||")[0];
  254.  
  255. if(x.includes("rapidvideo")){
  256. rapidvideo(x+'"');
  257. }else{
  258. EpisodesVideoLinks.push(x);
  259. getNextEpisode(true);
  260. }
  261. }
  262.  
  263. function isCapacha(html){
  264. return html.includes("formVerify");
  265. }
  266.  
  267. function postdata(answer){
  268. var data = {reUrl: curretEP, answerCap: answer};
  269. var msg = $.ajax({type: "POST", url: "http://kissanime.ru/Special/AreYouHuman2",data: data ,async: false}).responseText;
  270. if(server == 1){
  271. beta(msg);
  272. }else if(server == 2){
  273. rapidvideo(msg);
  274. }
  275. }
  276.  
  277. function getNextEpisode(a){
  278. images = ["","","",""];
  279. imagecount = 0;
  280. imagesURL = [];
  281. imageURLcount = 0;
  282. clickNr = 0;
  283. w= ["",""];
  284. if(a){currnetEpIndex++;}
  285. if(currnetEpIndex < EpisodesLinks.length){
  286. curretEP = EpisodesLinks[currnetEpIndex];
  287. getEp(curretEP);
  288. }else{
  289. console.log(EpisodesVideoLinks);
  290. ALLDONE();
  291. console.log("DONE");
  292. }
  293. }
  294.  
  295. function ALLDONE(){
  296. if(isText){
  297. createTxtList();
  298. }if(isHTML){
  299. createHTMLlist();
  300. }if(isM3U8){
  301. createM3U8();
  302. }if(isIDM){
  303. createIDM();
  304. }
  305. }
  306.  
  307. function createTxtList(){
  308. var list ="";
  309. for(var i = 0; i < EpisodesVideoLinks.length; i++){
  310. list += encodeURI(EpisodesVideoLinks[i]) + "[" + EpisodesName[i].replace(/[\s:\|\[\]\{\}]+/g,"_") + ".mp4\n";
  311. }
  312. $("#CaptchaInfo").show();
  313. $("#CaptchaInfo").find("p").html("You need to download <a href='https://cdn.rawgit.com/Eltion/Kissanime-Downloader/040e60bfcfc57c1b27e3ca7faf65204abf435056/KissAnime%20Downloader.zip'>KissAnime Downloader.zip</a><br /><br /> <a href='https://cdn.rawgit.com/Eltion/Kissanime-Downloader/5f62b6848a62d208ee799d6a8b256741fd7b9229/README.md'>Read this.</a>");
  314.  
  315. download("list.txt","text/plain",list);
  316. }
  317.  
  318. function createHTMLlist(){
  319. var list ="";
  320. for(var i = 0; i < EpisodesVideoLinks.length; i++){
  321. list += '<a href="' + EpisodesVideoLinks[i] + '" download="' + EpisodesName[i] + '">' + EpisodesName[i] + '</a> <span onclick="e(this)"><u>(WATCH)</u></span><br>';
  322. }
  323. list += '<div id="ee" style="display:none;position:absolute;top:0;left:0;background:black;width:100%;height:100%;"><video style="display:block;position:fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);" id="video" src="" width="700" autoplay controls></video><img onclick=\'document.getElementById("ee").style.display = "none";document.getElementById("video").src= "";\' style="position: absolute; top:0;right:0;width:75px;" src="http://www.hccs.edu/media/hcc-redesign/style-assets/images/img/close.png" /></div> <script type="text/javascript">function e(a){document.getElementById("ee").style.display = "block"; document.getElementById("video").src = a.previousSibling.previousSibling.href; } </script>';
  324. download("list.html","text/html",list);
  325. }
  326.  
  327. function createM3U8(){
  328. var list =" #EXTM3U\n\n";
  329. for(var i = 0; i < EpisodesVideoLinks.length; i++){
  330. list += '#EXTINF:-1,'+EpisodesName[i]+"\n"+encodeURI(EpisodesVideoLinks[i])+"\n\n";
  331. }
  332. $("#CaptchaInfo").show();
  333. $("#CaptchaInfo").find("p").html("You can play this with VLC player.");
  334.  
  335. download("list.m3u8","text/plain",list);
  336. }
  337.  
  338. function createIDM(){
  339. var list ='IF EXIST %PROGRAMFILES(X86)%\n(cd "%ProgramFiles(x86)%\\Internet Download Manager")\nELSE (cd "%ProgramFiles%\\Internet Download Manager")\n';
  340. for(var i = 0; i < EpisodesVideoLinks.length; i++){
  341. //list += encodeURI(EpisodesVideoLinks[i]) + "[" + EpisodesName[i].replace(/[\s:\|\[\]\{\}]+/g,"_") + ".mp4\n";
  342. list += 'IDMan.exe /n /p "%UserProfile%\\Downloads\\Anime\\'+ nameOfAnime+ '" /a /f "' + EpisodesName[i].replace(/[\s:\|\[\]\{\}]+/g,"_")+'.mp4" /d "'+encodeURI(EpisodesVideoLinks[i])+'"\n';
  343. }
  344. list += "IDMan.exe /s \n";
  345. list += "IDMan.exe";
  346. var zip = new JSZip();
  347. zip.file("IDMan.bat", list);
  348. zip.generateAsync({type:"blob"}).then(function(content) {
  349. saveAs(content, nameOfAnime+".zip");
  350. });
  351. $("#CaptchaInfo").show();
  352. $("#CaptchaInfo").find("p").html("You need to install <a href='https://www.internetdownloadmanager.com/download.html'>Internet Download Manager</a><br /><br />If Internet Download Manager shows errors just run IDMan.bat again.");
  353. }
  354.  
  355. function download(filename, datatype, text) {
  356. var element = document.createElement('a');
  357. element.setAttribute('href', 'data:' + datatype + ';charset=utf-8,' + encodeURIComponent(text));
  358. element.setAttribute('download', filename);
  359. // element.setAttribute('target', '_blank');
  360. // ^^ problems with safari
  361.  
  362. element.style.display = 'none';
  363. document.body.appendChild(element);
  364.  
  365. element.click();
  366.  
  367. document.body.removeChild(element);
  368. }
  369. function beta(html){
  370. var $htmlP = $($.parseHTML(html,document,true));
  371. if(!isEval){
  372. var script1 = $htmlP.find("script").toArray();
  373. for(var i = 0; i < script1.length; i++){
  374. var e = script1[i].innerHTML;
  375. if(e.includes(" key ") || e.includes(" skH ") ){
  376. eval(e);
  377. isEval = true;
  378. }
  379. }
  380. }
  381. var x = $htmlP.find("#slcQualix").find("option").toArray();
  382. loop1:for(var k =0; k < quality.length; k++){
  383. for(var j =0; j < x.length; j++){
  384. if(x[j].innerText.includes(quality[k])){
  385. var decodedVideoLink = ovelWrap(x[j].value);
  386. if(decodedVideoLink !== 0){
  387. EpisodesVideoLinks.push(decodedVideoLink);
  388. }else{
  389. alert("Dekoding failed");
  390. return;
  391. }
  392. break loop1;
  393. }
  394. }
  395. }
  396. getNextEpisode(true);
  397. }
  398.  
  399. function rapidvideo(html){
  400. var qS = ["720","480","360"];
  401. var setQuality = "";
  402. var url = html.match(/https:\/\/www.rapidvideo.com\/e\/[^"']*/g);
  403. for(var i = 0; i < quality.length; i++){
  404. if(qS.includes(quality[i])){
  405. setQuality = quality[i]; break;
  406. }
  407. }
  408. console.log(setQuality);
  409. url += "&q="+setQuality+"p";
  410. //alert(url);
  411. GM_xmlhttpRequest({
  412. method: "GET",
  413. url: ""+url,
  414. synchronous: true,
  415. onload: function(response) {
  416. //console.log(response);
  417. var e = response.responseText.split('<source src="')[1].split('"')[0];
  418. if (e === undefined || e === null) {
  419. console.log(response.responseText);
  420. }else{
  421. console.log(e);
  422. EpisodesVideoLinks.push(e);
  423. getNextEpisode(true);
  424. //epsLinks.push(e);
  425. }
  426. }
  427. });
  428. }
  429.  
  430. function factoryReset(){
  431. var keys = GM_listValues();
  432. for (var i=0; i < keys.length; i++) {
  433. GM_deleteValue(keys[i]);
  434. }
  435. }
  436.  
  437. function cutImage64(base64,s){
  438. var a = "";
  439. for(var i = 0; i < base64.length; i=i+s){
  440. a += base64.charAt(i);
  441. }
  442. return a;
  443. }
  444.  
  445. function isBasicJson(){
  446. return GM_getValue("AnimeBro3",false);
  447. }
  448.  
  449. function getBasicJson(){
  450.  
  451. $("#CaptchaInfo").show();
  452. $("#CaptchaInfo").find("p").html("First time running, fetching some files... Page will reload.");
  453. var msg='';
  454. //msg = $.ajax({type: "GET", url: "https://cdn.rawgit.com/Eltion/Kissanime-Chaptcha-Auto-Complete/111255eebd4ee25aaa2ad6d072b75ae446217d97/KissAnime.Downloader.Chaptcha.Database.json", async: false}).responseText;
  455. GM_xmlhttpRequest({
  456. method: "GET",
  457. url: "https://cdn.rawgit.com/Eltion/Kissanime-Chaptcha-Auto-Complete/eee0c4153d22cec5a5327efc8d7d8ba3b37394d9/KissAnime.Downloader.Chaptcha.Database2.json",
  458. synchronous: true,
  459. onload: function(response) {
  460. msg = response.responseText;
  461. msg = JSON.parse(msg);
  462. for(var i = 0; i < msg.length; i++){
  463. GM_setValue(msg[i].n,msg[i].v);
  464. }
  465. location.reload();
  466. }
  467. });
  468. }
  469.  
  470.  
  471. function toDataURL(url, callback) {
  472. var xhr = new XMLHttpRequest();
  473. xhr.onload = function() {
  474. var reader = new FileReader();
  475. reader.onloadend = function() {
  476. callback(reader.result);
  477. };
  478. reader.readAsDataURL(xhr.response);
  479. };
  480. //alert("http://kissanime.ru/Special/"+url);
  481. xhr.open('GET', "http://kissanime.ru/Special/"+url);
  482. xhr.responseType = 'blob';
  483. xhr.send();
  484. }
  485.