AnilistLiker

Allows users to quickly like posts on Anilist just by one click ,this version allow you to blacklist or whitelist any user for ease of use

  1. // ==UserScript==
  2. // @name AnilistLiker
  3. // @namespace https://github.com/Makhloufbel/AnilistLiker
  4. // @homepage https://github.com/Makhloufbel
  5. // @version 0.3.9a
  6. // @description Allows users to quickly like posts on Anilist just by one click ,this version allow you to blacklist or whitelist any user for ease of use
  7. // @author Makhloufbel
  8. // @match https://anilist.co/*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=anilist.co
  10.  
  11. // ==/UserScript==
  12.  
  13. (function() {
  14.  
  15. 'use strict';
  16. const svgns = 'http://www.w3.org/2000/svg';
  17. const BLACKLIST_BUTTON_CLASSNAMES = ['btn', 'btn-primary', 'mmd1'];
  18. /******** CSS of buttons divs uls ... ect ********/
  19. const css = [
  20. `
  21. .btn-primary {
  22. color: rgb(var(--color-text));
  23. background-color: rgb(var(--color-foreground-blue));
  24. }
  25.  
  26. .btn {
  27. display: inline-block;
  28. width: max-content;
  29. font-weight: bold;
  30. line-height: 1.5;
  31. color: rgb(var(--color-text));
  32. text-align: center;
  33. text-decoration: none;
  34. vertical-align: middle;
  35. cursor: pointer;
  36. -webkit-user-select: none;
  37. -moz-user-select: none;
  38. user-select: none;
  39. padding: 0.275rem 0.5rem;
  40. font-size: 1rem;
  41. border-radius: 0.25rem;
  42. transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
  43. }
  44.  
  45. .btn.mmd1 {
  46. box-sizing: border-box;
  47. font-size: 1.2rem;
  48. border: none;
  49. opacity: 0;
  50. position: absolute;
  51. top: .7em;
  52. left: 58%;
  53. }
  54.  
  55. .btn:hover {
  56. background-color: rgb(var(--color-foreground-blue-dark));
  57. color: rgb(var(--color-blue));
  58. transition: .02s;
  59. }
  60.  
  61. div.details:hover > .mmd1 {
  62. opacity: 1!important;
  63. transition: inherit;
  64. transform-origin: center;
  65. }
  66.  
  67. .POPUP {
  68. padding: 5px;
  69. margin: 5px;
  70. background: #eee;
  71. border: 1px solid #aaa;
  72. }
  73.  
  74. .mackDisplayBox {
  75. position: fixed;
  76. top: 80px;
  77. left: 200px;
  78. z-index: 999;
  79. min-width: 300px;
  80. min-height: 200px;
  81. padding: 20px;
  82. background-color: rgb(var(--color-foreground));
  83. border: solid 1px;
  84. border-radius: 4px;
  85. box-shadow: black 2px 2px 20px;
  86. overflow: hidden;
  87. filter: brightness(110%);
  88. }
  89.  
  90. .mackDisplayBox .scrollableContent {
  91. overflow: auto;
  92. height: 100%;
  93. scrollbar-width: thin;
  94. margin-top: 5px;
  95. padding: 30px;
  96. padding-top: 35px;
  97. padding-left: 15px;
  98. }
  99.  
  100. .mackDisplayBoxClose {
  101. position: absolute;
  102. right: 15px;
  103. top: 15px;
  104. cursor: pointer;
  105. background-color: red;
  106. border: solid;
  107. border-width: 1px;
  108. border-radius: 2px;
  109. color: white;
  110. border-color: rgb(var(--color-text));
  111. filter: drop-shadow(0 0 0.2rem crimson);
  112. z-index: 20;
  113. }
  114.  
  115. .mackDisplayBoxClose:hover {
  116. filter: drop-shadow(0 0 0.75rem crimson);
  117. }
  118.  
  119. .mackNewChapter .mackDisplayBoxClose {
  120. display: none;
  121. top: 7px;
  122. }
  123.  
  124. .mackNewChapter:hover .mackDisplayBoxClose {
  125. display: inline;
  126. }
  127.  
  128. .mackDisplayBoxTitle {
  129. position: absolute;
  130. top: 5px;
  131. left: 5px;
  132. padding: 1rem;
  133. font-weight: bold;
  134. font-size: 1.2em;
  135. background-color: inherit;
  136. z-index: 9999;
  137. }
  138.  
  139. .mackResizePearl {
  140. position: absolute;
  141. right: 2px;
  142. bottom: 2px;
  143. width: 20px;
  144. height: 20px;
  145. border: solid;
  146. border-radius: 10px;
  147. background: rgb(var(--color-foreground));
  148. cursor: se-resize;
  149. }
  150.  
  151. .mackGuideHeading,
  152. .mackGuideHeading:visited {
  153. color: rgb(var(--color-blue));
  154. }
  155.  
  156. * {
  157. scrollbar-color: rgb(var(--color-blue)) rgba(0, 0, 0, 0);
  158. scrollbar-width: thin;
  159. }
  160.  
  161. ::-webkit-scrollbar {
  162. width: 4px;
  163. height: 8px;
  164. }
  165.  
  166. ::-webkit-scrollbar-button {
  167. display: none;
  168. }
  169.  
  170. ::-webkit-scrollbar-track {
  171. background-color: #1110;
  172. width: 0px;
  173. }
  174.  
  175. ::-webkit-scrollbar-track-piece {
  176. display: none;
  177. }
  178.  
  179. ::-webkit-scrollbar-thumb {
  180. background-color: rgb(var(--color-blue));
  181. }
  182.  
  183. #myContainer {
  184. position: fixed;
  185. left: 5px;
  186. align-items: center;
  187. height: 7rem;
  188. width: 100px;
  189. }
  190.  
  191. .mmd2 {
  192. border: 2px solid rgb(var(--color-foreground-blue-dark));
  193. width: 9em;
  194. height: 2.125em;
  195. cursor: pointer;
  196. display: inline-block;
  197. font-weight: bold;
  198. font-size: inherit;
  199. padding: 0 5px;
  200. line-height: 1.2em;
  201. text-align: center;
  202. text-decoration: none;
  203. user-select: none;
  204. -webkit-user-select: none;
  205. touch-action: manipulation;
  206. }
  207.  
  208. .mmd2.btntop {
  209. border-radius: 10px 10px 0 0;
  210. }
  211.  
  212. .mmd2.btnbottom {
  213. border-radius: 0 0 10px 10px;
  214. }
  215.  
  216. .mmd2:active {
  217. box-shadow: rgb(var(--color-foreground-blue)) 2px 2px 0 0;
  218. transform: translate(2px, 2px);
  219. }
  220.  
  221. .mmd2.btnbottom[disabled] {
  222. border: 1px solid #999;
  223. background-color: darkgrey;
  224. color: #fff;
  225. cursor: not-allowed;
  226. }
  227.  
  228. .scrollableContent >p {
  229. display: flex;
  230. flex-direction: column;
  231. justify-content: center;
  232. width: 100%;
  233. height: 2em;
  234. margin: 0;
  235. font-weight: bold;
  236. font-size: inherit;
  237. padding: 10px 50px;
  238. }
  239.  
  240. .scrollableContent >p {
  241. font-size: 1.8rem;
  242. }
  243.  
  244. .scrollableContent p:nth-child(2n) {
  245. background-color: rgba(var(--color-foreground-blue),.0);
  246. }
  247.  
  248. .scrollableContent p:nth-child(2n-1) {
  249. background-color: rgba(var(--color-foreground-blue-dark),.2);
  250. }
  251.  
  252. p >.mackDisplayBoxClose {
  253. display: inline-block;
  254. right: 30px;
  255. font-weight: normal;
  256. background-color: red;
  257. transform: translateY(30%);
  258. }
  259.  
  260. .mackDisplayBox .scrollableContent {
  261. padding: 30px 0 0 0;
  262. margin: 0 -20px 0 -20px;
  263. }
  264.  
  265. div.scrollableContent {
  266. counter-reset: section1;
  267. }
  268.  
  269. p.mackNewChapter::before {
  270. position: absolute;
  271. left: 1.4em;
  272. counter-increment: section1;
  273. content: counter(section1) " - ";
  274. transform: translateX(-5%);
  275. }
  276.  
  277. .profile-btn {
  278. display: flex;
  279. transform: translate(0px, -40%);
  280. place-content: flex-start center;
  281. background: rgba(var(--color-blue),.8);
  282. border-radius: 4px;
  283. color: rgb(var(--color-white));
  284. cursor: pointer;
  285. display: inline-block;
  286. margin-left: 10px;
  287. margin-right: 10px;
  288. padding: 10px 12px;
  289. text-align: center;
  290. transition: .4s;
  291. border: none;
  292. }
  293.  
  294. .el-message.el-message--error {
  295. display: none !important;
  296. }
  297. `,
  298. ];
  299. /*********** verify if logged in**********/
  300. let userObject;
  301. let whoAmI = '';
  302. let whoAmIid = 0;
  303. try {
  304. userObject = JSON.parse(localStorage.getItem('auth'));
  305. } catch (err) {
  306. console.warn('could not get userObject');
  307. }
  308. if (userObject) {
  309. whoAmI = userObject.name;
  310. whoAmIid = userObject.id;
  311. } else {
  312. try {
  313. whoAmI = document
  314. .querySelector(".nav .links .link[href^='/user/']")
  315. .href.match(/\/user\/(.*)\//)[1]; //looks at the navbar
  316. } catch (e) {
  317. console.warn('could not get username');
  318. alert('Please login before to use this script!!!');
  319. return;
  320. }
  321. }
  322. /********* add CSS ********/
  323. document.head.insertAdjacentHTML('beforeend', '<style>' + css + '</style>');
  324.  
  325. let username = String('https://anilist.co/user/' + whoAmI + '/');
  326. //document.querySelector(".nav .links .link[href^='/user/']").href;
  327.  
  328. /********* functions to store data *********/
  329. const setObj = function (key, obj) {
  330. localStorage.setItem(key, JSON.stringify(obj));
  331. };
  332. const getObj = function (key) {
  333. return JSON.parse(localStorage.getItem(key));
  334. };
  335.  
  336. if (getObj('blacklist') === null || getObj('blacklist').length == 0) {
  337. setObj('blacklist', [username]);
  338. }
  339. /****** the Main function *******/
  340. (function main() {
  341. let div = create(
  342. 'div',
  343. '#myContainer',
  344. false,
  345. document.querySelector('#nav > div.wrap')
  346. );
  347. let blacklistbtn = create(
  348. 'button',
  349. ['btn', 'btn-primary', 'mmd2', 'btntop'],
  350. 'Show blacklist',
  351. div
  352. );
  353. var likeAllbtn = create(
  354. 'button',
  355. ['btn', 'btn-primary', 'mmd2', 'btnbottom'],
  356. 'Like all posts',
  357. div
  358. );
  359. blacklistbtn.onclick = () => {
  360. POPUP();
  361. };
  362.  
  363. likeAllbtn.onclick = () => {
  364. likeBtnHandler();
  365. };
  366. })();
  367. /******** Utilities functions *********/
  368. function homePageHandler() {
  369. let divs = document.querySelectorAll('div.details:not(.ided)');
  370. for (let e of divs) {
  371. createbtn(e);
  372. }
  373. }
  374. function createbtn(e) {
  375. if (e.closest('.wrap').getElementsByClassName('name')[0].href ===username) return;
  376.  
  377. addAttribute(e);
  378. let btn = create(
  379. 'button',
  380. ['btn', 'btn-primary', 'mmd1'],
  381. String(e.getAttribute('data-status')) === 'blacklisted'
  382. ? 'whitelist'
  383. : 'blacklist',
  384. false,
  385. 'position : absolute;'
  386. );
  387. btn.onclick = () => {
  388. switch (String(e.getAttribute('data-status'))) {
  389. case 'whitelisted':
  390. blacklistbtn(e);
  391. btn.remove();
  392. addAttribute(e);
  393. createbtn(e);
  394. break;
  395. case 'blacklisted':
  396. whitelistbtn(e);
  397. btn.remove();
  398. addAttribute(e);
  399. createbtn(e);
  400. break;
  401. }
  402. deleteAllBtn();
  403. };
  404. e.children[0].after(btn);
  405. e.classList.add('ided');
  406. }
  407. function userProfileHandler() {
  408. let div = document.querySelector('.name-wrapper');
  409. createProfilebtn(div);
  410. }
  411. function createProfilebtn(e) {
  412. if (String('https://anilist.co/user/' + e.innerText + '/') === username) return;
  413. addAttributeToProfile(e);
  414. let btn = create(
  415. 'button',
  416. ['nav-btn', 'profile-btn'],
  417. String(e.getAttribute('data-status')) === 'blacklisted'
  418. ? 'whitelist'
  419. : 'blacklist',
  420. false,
  421. false
  422. );
  423. btn.onclick = () => {
  424. switch (String(e.getAttribute('data-status'))) {
  425. case 'whitelisted':
  426. blacklistbtn(e);
  427. break;
  428. case 'blacklisted':
  429. whitelistbtn(e);
  430. break;
  431. default:
  432. console.log('Error');
  433. break;
  434. }
  435. deleteAllBtn();
  436. userProfileHandler(e);
  437. };
  438. e.after(btn);
  439. }
  440.  
  441. function addAttributeToProfile(b) {
  442. let blacklist = getObj('blacklist');
  443. if (String('https://anilist.co/user/' + b.innerText + '/') == username) return;
  444.  
  445. if (blacklist.includes(String('https://anilist.co/user/' + b.innerText + '/')))
  446. {
  447. b.setAttribute('data-status', 'blacklisted');
  448. } else {
  449. b.setAttribute('data-status', 'whitelisted');
  450. }
  451. }
  452. function deleteAllBtn() {
  453. document
  454. .querySelectorAll('button.btn.btn-primary.mmd1')
  455. .forEach((e) => {
  456. e.remove();
  457. });
  458. document.querySelectorAll('div.details').forEach((e) => {
  459. e.classList.remove('ided');
  460. });
  461. document.querySelectorAll('.profile-btn').forEach((e) => {
  462. e.remove();
  463. });
  464. }
  465.  
  466. function POPUP() {
  467. let blacklist = getObj('blacklist');
  468. let box = createDisplayBox(
  469. 'width:600px;height:500px;top:100px;left:220px;',
  470. 'Blacklisted'
  471. );
  472. for (let e of blacklist) {
  473. let listing = create(
  474. 'p',
  475. 'mackNewChapter',
  476. false,
  477. false,
  478. 'position:relative;'
  479. );
  480. create('a', ['link', 'newTab'], getName(e), listing).href =
  481. '/user/' + getName(e) + '/';
  482. let listClose = create(
  483. 'span',
  484. 'mackDisplayBoxClose',
  485. '✕',
  486. listing,
  487. 'top:0 !important;'
  488. );
  489. listClose.onclick = function () {
  490. whitelistbtn(listing);
  491. listing.remove();
  492. blacklist.filter((item) => item !== e);
  493. deleteAllBtn();
  494. userProfileHandler();
  495. };
  496. box.appendChild(listing);
  497. }
  498. }
  499.  
  500. function addAttribute(b) {
  501. let blacklist = getObj('blacklist');
  502. if (b.firstChild.href == username) return;
  503.  
  504. if (blacklist.includes(b.firstChild.href)) {
  505. b.setAttribute('data-status', 'blacklisted');
  506. } else {
  507. b.setAttribute('data-status', 'whitelisted');
  508. }
  509. }
  510. /********* Create a DOMElement *********/
  511. function create(HTMLtag, classes, text, appendLocation, cssText) {
  512. let element = document.createElement(HTMLtag);
  513. if (Array.isArray(classes)) {
  514. element.classList.add(...classes);
  515. if (classes.includes('newTab')) {
  516. element.setAttribute('target', '_blank');
  517. }
  518. } else if (classes) {
  519. if (classes[0] === '#') {
  520. element.id = classes.substring(1);
  521. } else {
  522. element.classList.add(classes);
  523. if (classes === 'newTab') {
  524. element.setAttribute('target', '_blank');
  525. }
  526. }
  527. }
  528. if (text || text === 0) {
  529. element.innerText = text;
  530. }
  531. if (appendLocation && appendLocation.appendChild) {
  532. appendLocation.appendChild(element);
  533. }
  534. if (cssText) {
  535. element.style.cssText = cssText;
  536. }
  537. return element;
  538. }
  539. /********* Create hovering box *********/
  540. function createDisplayBox(cssProperties, windowTitle) {
  541. let displayBox = create(
  542. 'div',
  543. 'mackDisplayBox',
  544. false,
  545. document.querySelector('#app') ||
  546. document.querySelector('.termsFeed') ||
  547. document.body,
  548. cssProperties
  549. );
  550. if (windowTitle) {
  551. create('span', 'mackDisplayBoxTitle', windowTitle, displayBox);
  552. }
  553. let mousePosition;
  554. let offset = [0, 0];
  555. let isDown = false;
  556. let isDownResize = false;
  557. let displayBoxClose = create(
  558. 'span',
  559. 'mackDisplayBoxClose',
  560. '✕',
  561. displayBox
  562. );
  563. displayBoxClose.onclick = function () {
  564. displayBox.remove();
  565. };
  566. let resizePearl = create('span', 'mackResizePearl', false, displayBox);
  567. displayBox.addEventListener(
  568. 'mousedown',
  569. function (e) {
  570. if (!['P', 'PRE'].includes(e.target.tagName)) {
  571. //don't annoy people trying to copy-paste
  572. isDown = true;
  573. offset = [
  574. displayBox.offsetLeft - e.clientX,
  575. displayBox.offsetTop - e.clientY,
  576. ];
  577. }
  578. },
  579. true
  580. );
  581. resizePearl.addEventListener(
  582. 'mousedown',
  583. function (event) {
  584. event.stopPropagation();
  585. event.preventDefault();
  586. isDownResize = true;
  587. offset = [displayBox.offsetLeft, displayBox.offsetTop];
  588. },
  589. true
  590. );
  591. document.addEventListener(
  592. 'mouseup',
  593. function () {
  594. isDown = false;
  595. isDownResize = false;
  596. },
  597. true
  598. );
  599. document.addEventListener(
  600. 'mousemove',
  601. function (event) {
  602. if (isDownResize) {
  603. mousePosition = {
  604. x: event.clientX,
  605. y: event.clientY,
  606. };
  607. displayBox.style.width =
  608. mousePosition.x - offset[0] + 5 + 'px';
  609. displayBox.style.height =
  610. mousePosition.y - offset[1] + 5 + 'px';
  611. return;
  612. }
  613. if (isDown) {
  614. mousePosition = {
  615. x: event.clientX,
  616. y: event.clientY,
  617. };
  618. displayBox.style.left = mousePosition.x + offset[0] + 'px';
  619. displayBox.style.top = mousePosition.y + offset[1] + 'px';
  620. }
  621. },
  622. true
  623. );
  624. let innerSpace = create('div', 'scrollableContent', false, displayBox);
  625. return innerSpace;
  626. }
  627.  
  628. function getName(link) {
  629. if (link === null) return;
  630. return link.split('/')[4];
  631. }
  632.  
  633. function whitelistbtn(b) {
  634. let blacklist = getObj('blacklist');
  635. var value = String(
  636. 'https://anilist.co/user/' + b.children[0].innerText + '/'
  637. );
  638. var val = b.children[0].innerText;
  639.  
  640. if (blacklist.includes(value)) {
  641. blacklist.splice(blacklist.indexOf(value), 1);
  642. blacklist = setObj('blacklist', blacklist);
  643. //alert(val +' has been whitelisted !');
  644. //console.log(blacklist);
  645. } else {
  646. //alert(val +' is not blacklisted !');
  647. }
  648. }
  649. function blacklistbtn(b) {
  650. let blacklist = getObj('blacklist');
  651. var value = (value = String(
  652. 'https://anilist.co/user/' + b.children[0].innerText + '/'
  653. ));
  654. var val = b.children[0].innerText;
  655.  
  656. if (!blacklist.includes(value)) {
  657. blacklist.push(value);
  658. setObj('blacklist', blacklist);
  659. // alert(val +' has been blacklisted !');
  660. //console.log(blacklist);
  661. } else {
  662. // alert(val +' is already blacklisted !');
  663. }
  664. }
  665.  
  666. function eventFire(el, etype) {
  667.  
  668. if (el.fireEvent) {
  669. el.fireEvent('on' + etype);
  670. } else {
  671. var evObj = document.createEvent('Events');
  672. evObj.initEvent(etype, true, false);
  673. el.dispatchEvent(evObj);
  674. }
  675.  
  676. }
  677.  
  678.  
  679. let isAlerted = false;
  680. function countdownHandler(){
  681. const Alerted = document.querySelectorAll('.el-message.el-message--error')
  682. if(Alerted.length == 0){
  683. isAlerted = false;
  684. return;
  685. }
  686. isAlerted = true;
  687. console.log("please wait 1 min!");
  688.  
  689. const countDownDate = (new Date().getTime())+60*1000;
  690. const count = document.querySelector(".btn.btn-primary.mmd2.btnbottom");
  691. count.disabled = true;
  692. const Int = setInterval(function() {
  693.  
  694. let now = new Date().getTime();
  695. let distance = countDownDate - now;
  696.  
  697. let seconds = Math.floor((distance % (1000 * 60)) / 1000);
  698. if(seconds>9){
  699. count.innerHTML = "wait 00 : " + seconds ;
  700. }else{
  701. count.innerHTML = "wait 00 : 0" + seconds ;
  702. }
  703. if (distance < 0) {
  704. clearInterval(Int);
  705. count.innerHTML = "Like all posts";
  706. count.disabled = false;
  707. isAlerted = false;
  708. }
  709. }, 1000);
  710.  
  711.  
  712. }
  713.  
  714. function likeBtnHandler() {
  715. let likes = document.querySelectorAll('.button:not(.liked)');
  716. let notBlacklisted = blacklistedarray(likes);
  717. //console.log(likes, notBlacklisted);
  718. for (let e of notBlacklisted) {
  719. eventFire(e, 'click');
  720. }
  721. }
  722.  
  723. function blacklistedarray(array) {
  724. let blacklist = getObj('blacklist');
  725. if (!blacklist.includes(username)) {
  726. blacklist.push(username);
  727. }
  728. let notBlacklisted = new Array();
  729. let isBlacklisted;
  730. for (let c of array) {
  731. isBlacklisted = false;
  732. for (let e of blacklist) {
  733. if (
  734. c.closest('.wrap').getElementsByClassName('name')[0].href ==
  735. e
  736. ) {
  737. isBlacklisted = true;
  738. break;
  739. }
  740. }
  741. if (isBlacklisted == false) {
  742. notBlacklisted.push(c);
  743. }
  744. }
  745. return notBlacklisted;
  746. }
  747. function profileBtnHandler() {
  748. let isAdded = document.querySelector('button.nav-btn.profile-btn');
  749. //console.log([...isAdded].length);
  750. if (isAdded !== null) return;
  751. window.onload = userProfileHandler();
  752. }
  753.  
  754. const onMutate = function (mutationsList) {
  755. if (window.location.href == 'https://anilist.co/home') {homePageHandler() }
  756. if (window.location.href.match(/(^https?:\/\/)?(www\.)?anilist.co\/user\/\w+/gi)!= null) {profileBtnHandler() }
  757. if( !isAlerted ) {countdownHandler()}
  758.  
  759. };
  760. const observer = new MutationObserver(onMutate);
  761. observer.observe(document.body, { childList: true, subtree: true })
  762. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址