trungking / Blocktruyen Helper

// ==UserScript==
// @name         Blocktruyen Helper
// @namespace    com.acbpro.bloctruyen.helper
// @version      2.8
// @description  Blogtruyen helper
// @author       You
// @match        http*://blogtruyen.com/*
// @match        http*://forum.blogtruyen.com/*
// @match        http*://blogtruyen.vn/*
// @match        http*://forum.blogtruyen.vn/*
// @match        http*://blogtruyenmoi.com/*
// @match        http*://forum.blogtruyenmoi.com/*
// @match        http*://blogtruyenmoi.vn/*
// @match        http*://forum.blogtruyenmoi.vn/*
// @grant        GM_xmlhttpRequest
// @require http://code.jquery.com/jquery-3.3.1.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/uikit/3.1.4/js/uikit.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/uikit/3.1.4/js/components/notification.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/uikit/3.1.4/js/uikit-icons.min.js
// @require      https://unpkg.com/jszip@3.2.1/dist/jszip.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/jszip-utils/0.0.2/jszip-utils.min.js
// @require      https://unpkg.com/file-saver@2.0.1/dist/FileSaver.min.js
// @downloadURL https://openuserjs.org/install/trungking/Blocktruyen_Helper.user.js
// @updateURL https://openuserjs.org/meta/trungking/Blocktruyen_Helper.meta.js
// @license MIT
// ==/UserScript==

(function () {
  'use strict';
  log('Blogtruyen Helper started');
  var Promise = window.Promise;
  if (!Promise) {
    Promise = JSZip.external.Promise;
  }
  const http = GM_xmlhttpRequest;
  const outputExt = 'zip';
  const tit = document.title;
  let downloaded = 0;
  let total = 0;
  let downloading = false;
  let target = null;
  var referer = {
    'i.blogtruyen.com': 'blogtruyen.com',
    'i.imgur.com': 'imgur.com',
    'storage.fshare.vn': 'fshare.vn',
    'truyen.cloud': 'www.nettruyen.com'
  };
  const id = '#bt-helper-offcanvas';
  const body = 'body:not(#tinymce)';
  let dlCurrent = 1;
  const jsZip = new JSZip();

  loadCSS('https://css.acbpro.com/uikit.min.css');
  injectJS();
  const setting_button = '<button style="position: fixed;right: 0;top: 55px;border-radius:0" uk-toggle="target: #bt-helper-offcanvas" type="button" uk-icon="cog" class="uk-icon-button"></button>';
  const expand_button = '<button style="position: fixed;right: 0;top: 91px;border-radius:0" type="button" uk-icon="expand" class="uk-icon-button" onclick="expandSpoiler()"></button>';

  const block_button = '<button id="bt-helper-block-id" type="button" class="uk-button uk-button-danger uk-button-small" onclick="blockId()" style="font-size: 9px;padding: 0 7px;line-height: 26px; margin-bottom: 2px;">Chặn truyện</button>';
  $(block_button).prependTo($('#btnBookmart').parent());

  $(setting_button).appendTo(body);
  if (window.location.toString().indexOf('forum.blogtruyen.com') > -1 && $('.spoiler a,.top-spoiler a').length) {
    $(expand_button).appendTo(body);
  }

  const offcanvas = `
<div id="bt-helper-offcanvas" uk-offcanvas>
<div class="uk-offcanvas-bar">
<div class="uk-margin-small-bottom">
Block Tag
</div>
<input id='block-tag' class="uk-input uk-margin-bottom" type="text" placeholder="EX: ntr,shoujo">

<div class="uk-margin-small-bottom">
Block Poster ID
</div>
<input id='block-poster' class="uk-input uk-margin-bottom" type="text" placeholder="EX: 99079,99080">


<div class="uk-margin-small-bottom">
Block ID
</div>

<input id='block-id' class="uk-input" type="text" placeholder="EX: 99079,99080">
<br><br>

<label>
<input id='block-pinned' type="checkbox">
Block pinned
</label>
<br>

<button class="uk-button uk-button-primary uk-margin-top" onclick="saveSetting()">Save</button>

<div id='bt-helper-success' class="uk-margin-top" style='display:none; color: green'>Saved. Refresh page to see the change</div>

<button class="uk-offcanvas-close" type="button" uk-close>
</button></div></div>
`
  $(offcanvas).appendTo(body);
  var setting = readSetting();

//   if ($('#list-chapters').length !== 0) {
//     console.log('Append download');
//     $('<a href="#">download</a>').appendTo($('#list-chapters .download'))
//     $('#list-chapters .download a').on('click', function (e) {
//       e.preventDefault();
//       if (downloading) return;
//       downloading = true;
//       target = e.target;
//       const item = $(e.target).parents('p').find('.title a')[0];
//       const url = item.href;
//       const chapName = item.title;
//       let html = '';
//       download(url, function (data) {
//         const $html = $(data);
//         const $images = $html.find('#content img');
//         total = $images.length;
//         downloaded = 0;
//         $images.each((key, image) => {
//           const filename = ('0000' + dlCurrent++ + '.' + image.src.split('.').pop());
//           jsZip.file(filename, urlToPromise(image.src), {
//             binary: true
//           });
//         });
//         genZip(chapName);
//       }, function () {
//         log('Error download ', url);
//       });
//     });
//   }

  function download(url, success, error) {
    return http({
      method: 'GET',
      url: url,
      onload: function (response) {
        success(response.response);
      },
      onerror: function (err) {
        console.log(err);
      }
    });
  }

  // block pinned
  if (setting.pinned) {
    $('#storyPinked').remove()
  }
  $('#storyPinked .tiptip').toArray().forEach((item, index) => {
    var id = item.href.split('/')[3];
    if (setting.id.includes(id)) {
      item.remove();
      log('Remove pinned ', id);
      return;
    }
  })

  // Block manga list
  var mangaList = toArray($('.list-mainpage.listview div[class="col-sm-12"]'));

  mangaList.forEach((item, index) => {
    var categories = toArray($(item).find('.category a'));
    var poster = $(item).find('.poster');
    var title = $(item).find('a')[0].title;
    var id = $(item).find('a')[0].href.match(/\/([0-9]+)\//)[1];

    if (setting.id.includes(id)) {
      item.remove();
      log('Remove ', title, ' with id ', id);
      return;
    }
    if (poster && poster.length) {
      var href = poster[0].href.split('/');
      var posterID = href[href.length - 1];
      if (setting.poster.some(item => posterID.toString() == item)) {
        item.remove();
        if (title) {
          log('Remove ', title, ' with posterID ', posterID);
        }
      }
    }

    var blacklist = categories.some(cat => {
      var $cat = $(cat);
      var text = $cat.text();
      var href = $cat.attr('href').split('/');
      var slug = href[href.length - 1];
      if (setting.tag.indexOf(text.toLowerCase()) != -1 || setting.tag.indexOf(slug.toLowerCase()) != -1) {
        return true;
      }
      return false;
    });
    if (blacklist) {
      item.remove();
      var cats = toArray($(item).find('.category a')).map(item => item.title);
      if (title) {
        log('Remove ', title, ' with tag ', cats.join(','));
      }
    }
  });

  log('Blogtruyen Helper injected');

  function readSetting() {
    var setting = JSON.parse(localStorage.getItem("bt-helper-setting"));
    if (!setting) {
      return;
    }
    var tag = setting.tag ? setting.tag : [];
    var poster = setting.poster ? setting.poster : [];
    var id = setting.id ? setting.id : [];
    var pinned = setting.pinned ? setting.pinned : false;
    $('#block-tag').val(tag.join(','));
    $('#block-poster').val(poster.join(','));
    $('#block-id').val(id.join(','));
    $('#block-pinned')[0].checked = !!pinned;
    return setting;
  }

  function injectJS() {
    var script = document.createElement('script');
    script.type = "text/javascript";
    script.innerHTML = `
function saveSetting(){
var $tag = $('#block-tag').val().split(',').map(s => s.trim().toLowerCase());
var $poster = $('#block-poster').val().split(',').map(s => s.trim());
var $id = $('#block-id').val().split(',').map(s => s.trim());
var $pinned = $('#block-pinned')[0].checked;
var setting = JSON.stringify({tag: $tag, poster:  $poster, id: $id, pinned: $pinned});
localStorage.setItem("bt-helper-setting", setting);
$('#bt-helper-success').show();
console.log('bt-helper:::','Setting saved', setting);
}
function expandSpoiler(){
$('.spoiler a,.top-spoiler a').each(function (e) {
jsSpoiler(this)
});
}
function blockId(){
var $id = $('.entry-title').find('a')[0].href.match('/([0-9]+)/')[1];
var $blockIds = $('#block-id');
if (!$blockIds.val().includes($id)){
var ar = $blockIds.val().split(',').filter(a => a);
ar.push($id);
$blockIds.val(ar.join(','));
saveSetting();
$('#bt-helper-block-id').remove();
}
}
`;
    document.getElementsByTagName('head')[0].appendChild(script);
    log('Inject JS success');
  }
  // functions
  function genZip(chapName) {
    jsZip.generateAsync({
      type: "blob"
    }).then(function callback(blob) {
      var zipName = genFileName(chapName) + '.' + outputExt;
      saveAs(blob, zipName);
    }, function (e) {
      log(e);
    });
  }

  function genZip2(chapName) {
    log('call genzip');
    jsZip.generateAsync({
      type: 'blob'
    }).then(function (blob) {
      var zipName = genFileName(chapName) + '.' + outputExt;

      // noty('<a href="' + URL.createObjectURL(dlPrevZip) + '" download="' + zipName + '"><strong>Click vào đây</strong></a> nếu trình duyệt không tự tải xuống', 'success');

      saveAs(blob, zipName);

      document.title = '[⇓] ' + tit;
    }, function () {
      noty('Lỗi tạo file nén của <strong>' + chapName + '</strong>', 'error');
      cancelProgress();

      document.title = '[x] ' + tit;
      endZip();
    });
  }

  function genFileName(chapName) {
    return chapName.replace(/\s+/g, '_').replace(/\./g, '-');
  }

  function urlToPromise(url, key) {
    var urlObj = new URL(url),
      urlPro = urlObj.protocol,
      urlHost = urlObj.hostname,
      urlRef = referer[urlHost] ? referer[urlHost] : urlHost,
      urlOri = urlPro + '//' + urlRef;
    return new Promise(function (resolve, reject) {
      http({
        method: 'GET',
        url: url,
        headers: {
          referer: urlOri,
          origin: urlOri
        },
        responseType: 'arraybuffer',
        onload: function (response) {
          if (response.response.byteLength < 10000 || (response.statusText !== 'OK' && response.statusText !== '')) {
            log(response);
            reject();
          }
          else {
            downloaded++;
            updateStatus();
            resolve(response.response);
          }
        },
        onerror: function (err) {
          reject(err);
        }
      });
    });
  }

  function updateStatus() {
    log('Download ' + downloaded + '/' + total);
    if (downloaded < total) {
      target.innerText = downloaded + '/' + total;
    }
    else {
      downloading = false;
      target.innerText = 'completed';
    }
  }

})();

function toArray(obj) {
  return $.map(obj, function (value, index) {
    return [value];
  });
}

function loadCSS(url) {
  var link = window.document.createElement('link');
  link.rel = 'stylesheet';
  link.type = 'text/css';
  link.href = url;
  document.getElementsByTagName("HEAD")[0].appendChild(link);
}

function log() {
  var args = Array.prototype.slice.call(arguments);
  args.unshift('bt-helper:::');
  console.log.apply(console, args);
}