Auto All Page

Otomatis menampilkan semua halaman artikel berita dalam 1 halaman

当前为 2023-12-31 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Auto All Page
  3. // @version 2.2.6
  4. // @author reforget-id
  5. // @namespace autoallpage
  6. // @description Otomatis menampilkan semua halaman artikel berita dalam 1 halaman
  7. // @homepage https://github.com/reforget-id/AutoAllPage
  8. // @supportURL https://github.com/reforget-id/AutoAllPage/issues
  9. // @icon https://raw.githubusercontent.com/reforget-id/AutoAllPage/main/assets/icon.png
  10. // @run-at document-start
  11. // @grant GM_addStyle
  12. // @grant GM_xmlhttpRequest
  13. // @grant GM_registerMenuCommand
  14. // @noframes
  15. // @exclude https://*?single=1
  16. // @exclude https://*?showpage=all
  17. // @exclude https://*.inews.id/*/all
  18. // @exclude https://*?page=all#page*
  19. // @exclude https://*?page=all#sectionall
  20. // @exclude /^https:\/\/(?!.+\.(idntimes|fortuneidn|popbela)\.com).+\?page=all$/
  21. // @exclude https://*/amp/*
  22. // @exclude https://amp.*
  23. // @exclude https://*/amp-*/*
  24. // @exclude https://*/?amp*
  25. // @exclude https://*?amp=1*
  26. // @exclude https://*/*&amp*
  27. // @exclude https://*/*&amp=1*
  28. // @include https://*.20jam.com/*/*/*
  29. // @include https://*.100kpj.com/*/*
  30. // @include https://*.aboutmalang.com/*/*/*
  31. // @include https://akurat.co/*
  32. // @include https://*.antaranews.com/berita/*/*
  33. // @include https://*.ayocirebon.com/*/*/*
  34. // @include https://*.ayoindonesia.com/*/*/*
  35. // @include https://*.bolasport.com/read/*
  36. // @include https://*.cnbcindonesia.com/*/*/*
  37. // @include https://*.cnnindonesia.com/*/*/*
  38. // @include https://*.dagangberita.com/*/*/*
  39. // @include https://*.detik.com/*/d-*/*
  40. // @include https://*.fortuneidn.com/*
  41. // @include https://*.genpi.co/*/*/*
  42. // @include https://*.grid.id/read/*
  43. // @include https://*.gridoto.com/read/*
  44. // @include https://herstory.co.id/read*
  45. // @include https://*.hops.id/*/*/*
  46. // @include https://*.idntimes.com/*/*/*/*
  47. // @include https://*.idxchannel.com/*/*
  48. // @include https://*.inews.id/*/*
  49. // @include https://*.intipseleb.com/*/*
  50. // @include https://*.jatimnetwork.com/*/*/*
  51. // @include https://*.jpnn.com/*/*
  52. // @include https://*.kilat.com/*/*/*
  53. // @include https://*.kompas.com/read/*
  54. // @include https://*.kompas.com/*/read/*
  55. // @include https://*.kompas.tv/article/*
  56. // @include https://*.kompasiana.com/*/*/*
  57. // @include https://*.kontan.co.id/news/*
  58. // @include https://*.merdeka.com/*/*
  59. // @include https://*.motorplus-online.com/read/*
  60. // @include https://*.okezone.com/read/*
  61. // @include https://*.parapuan.co/read/*
  62. // @include https://*.pikiran-rakyat.com/*/pr-*/*
  63. // @include https://*.pojoksatu.id/*/*/*
  64. // @include https://*.popbela.com/*
  65. // @include https://*.republika.co.id/berita/*
  66. // @include https://republika.co.id/berita/*
  67. // @include https://*.sahijab.com/*/*
  68. // @include https://*.sindonews.com/read/*
  69. // @include https://*.sonora.id/read/*
  70. // @include https://*.suara.com/*/*/*/*
  71. // @include https://*.tempo.co/read/*
  72. // @include https://*.tribunnews.com/*/*/*/*
  73. // @include https://*.tvonenews.com/*/*
  74. // @include https://*.unews.id/*/*/*
  75. // @include https://*.viva.co.id/*/*
  76. // @include https://wartaekonomi.co.id/read*
  77. // ==/UserScript==
  78.  
  79. 'use strict';
  80.  
  81. (() => {
  82. GM_addStyle(`
  83. .aap-divider {
  84. font-size: 18px !important;
  85. font-weight: 600 !important;
  86. margin: 30px 0 30px 0 !important;
  87. text-align: center !important;
  88. }
  89. `)
  90.  
  91. GM_registerMenuCommand('Donate me on Trakteer', () => {
  92. window.open('https://trakteer.id/reforget-id', '_blank')
  93. })
  94.  
  95. class URLBuilder {
  96. constructor() {
  97. this._protocol = 'https'
  98. this._hostname = ''
  99. this._path = ''
  100. this._param = ''
  101. }
  102.  
  103. hostname(hostname) {
  104. this._hostname = hostname
  105. return this
  106. }
  107.  
  108. path(...pathname) {
  109. this._path = this._path + pathname.join('/')
  110. return this
  111. }
  112.  
  113. param(query) {
  114. this._param = '?' + query
  115. return this
  116. }
  117.  
  118. toString() {
  119. let url = `${this._protocol}://${this._hostname}/${this._path}`
  120. if (this._param !== '') url = url + this._param
  121. return url
  122. }
  123. }
  124.  
  125. const url = {
  126. get url() {
  127. return window.location
  128. },
  129. href: () => url.url.href,
  130. hostname: () => url.url.hostname,
  131. path: () => url.url.pathname,
  132. param: () => url.url.search,
  133. }
  134.  
  135. function splitPath(pathname) {
  136. return pathname.split('/').filter(v => v)
  137. }
  138.  
  139. function redirect(url) {
  140. window.location.replace(url)
  141. }
  142.  
  143. function hostnameChecker(website) {
  144. return website.hostname.test(url.hostname())
  145. }
  146.  
  147. function urlChecker(website) {
  148. return hostnameChecker(website) && website.path.test(url.path())
  149. }
  150.  
  151. function log(message) {
  152. console.log('[AutoAllPage] ' + message)
  153. }
  154.  
  155. function pageDivider(currentPage, totalPages) {
  156. const divider = new DOMParser().parseFromString(`
  157. <div class="aap-divider">
  158. === [AutoAllPage] Halaman ${currentPage} dari ${totalPages} ===
  159. </div>
  160. `, 'text/html')
  161. return divider.body.firstElementChild
  162. }
  163.  
  164. // https://stackoverflow.com/a/52809105
  165. function watchURL(website) {
  166. let oldPushState = history.pushState
  167. history.pushState = function pushState() {
  168. let ret = oldPushState.apply(this, arguments)
  169. window.dispatchEvent(new Event('pushstate'))
  170. window.dispatchEvent(new Event('locationchange'))
  171. return ret
  172. }
  173.  
  174. let oldReplaceState = history.replaceState
  175. history.replaceState = function replaceState() {
  176. let ret = oldReplaceState.apply(this, arguments)
  177. window.dispatchEvent(new Event('replacestate'))
  178. window.dispatchEvent(new Event('locationchange'))
  179. return ret
  180. }
  181.  
  182. window.addEventListener('popstate', () => {
  183. window.dispatchEvent(new Event('locationchange'))
  184. })
  185.  
  186. window.addEventListener('locationchange', () => {
  187. if (urlChecker(website)) {
  188. log(url.href())
  189. redirect(url.href())
  190. }
  191. })
  192. }
  193.  
  194. //******************************************************************************
  195.  
  196. const websiteList = [
  197. {
  198. id: 'akurat',
  199. description: 'akurat.co',
  200. hostname: /(^|\.)akurat\.co$/,
  201. path: /^\/.+(?<!\/\w+)$/,
  202. method: 'param',
  203. dynamic: false,
  204. fullpage: 'page=all',
  205. },
  206. {
  207. id: 'antara',
  208. description: 'antaranews.com',
  209. hostname: /(^|\.)antaranews\.com$/,
  210. path: /\/berita\/\d+\/.+(?<!\/\w+)$/,
  211. method: 'param',
  212. dynamic: false,
  213. fullpage: 'page=all',
  214. },
  215. {
  216. id: 'cnbc',
  217. description: 'cnbcindonesia.com',
  218. hostname: /(^|\.)cnbcindonesia\.com$/,
  219. path: /\/\d+-\d+-\d+\/.+(\/\d+|(?<!\/\w+))$/,
  220. method: 'param',
  221. dynamic: false,
  222. fullpage: 'page=all',
  223. },
  224. {
  225. id: 'detik',
  226. description: 'detik.com',
  227. hostname: /(^|\.)detik\.com$/,
  228. path: /\/d-\d+\/.+(\/\d+|(?<!\/\w+))$/,
  229. method: 'param',
  230. dynamic: false,
  231. fullpage: 'single=1',
  232. },
  233. {
  234. id: 'fajar',
  235. description: 'fajar.co.id',
  236. hostname: /(^|\.)fajar\.co\.id$/,
  237. path: /\/\d{4}\/\d{2}\/\d{2}\/.+(?<!\/\w+)$/,
  238. method: 'param',
  239. dynamic: false,
  240. fullpage: 'page=all',
  241. },
  242. {
  243. id: 'fortuneidn',
  244. description: 'fortuneidn.com',
  245. hostname: /(^|\.)fortuneidn\.com$/,
  246. path: /\/[\w-]+\/[\w-]+\/.+(?<!\/\w+)$/,
  247. method: 'param',
  248. dynamic: true,
  249. fullpage: 'page=all',
  250. },
  251. {
  252. id: 'grid',
  253. description: 'bolasport.com, grid.id, gridoto.com, motorplus-online.com, parapuan.co, sonora.id',
  254. hostname: /(^|\.)(parapuan\.co|(grid|sonora)\.id|(bolasport|gridoto|motorplus-online)\.com)$/,
  255. path: /^\/read\/.+(?<!\/\w+)$/,
  256. method: 'param',
  257. dynamic: false,
  258. fullpage: 'page=all',
  259. },
  260. {
  261. id: 'idntimes',
  262. description: 'idntimes.com',
  263. hostname: /(^|\.)idntimes\.com$/,
  264. path: /\/[\w-]+\/[\w-]+\/[\w-]+\/.+(?<!\/\w+)$/,
  265. method: 'dom',
  266. dynamic: false,
  267. pagination: 'page=all',
  268. },
  269. {
  270. id: 'idx',
  271. description: 'idxchannel.com',
  272. hostname: /(^|\.)idxchannel\.com$/,
  273. path: /\/.+\/.+(\/\d+|(?<!\/\w+))$/,
  274. method: 'path',
  275. dynamic: false,
  276. fullpage: 'all',
  277. },
  278. {
  279. id: 'inews',
  280. description: 'inews.id',
  281. hostname: /(^|\.)inews\.id$/,
  282. path: /\/(berita|read\/\d+|[a-z-]+\/[a-z-]+)\/.+(\/\d+|(?<!\/\w+))$/,
  283. method: 'path',
  284. dynamic: false,
  285. fullpage: 'all',
  286. },
  287. {
  288. id: 'kompascom',
  289. description: 'kompas.com',
  290. hostname: /(^|\.)kompas\.com$/,
  291. path: /\/read\/.+(?<!\/\w+)$/,
  292. method: 'param',
  293. dynamic: false,
  294. fullpage: 'page=all',
  295. },
  296. {
  297. id: 'kompasiana',
  298. description: 'kompasiana.com',
  299. hostname: /(^|\.)kompasiana\.com$/,
  300. path: /\/.+(?<!series)\/\w{24}\/.+(?<!\/\w+)$/,
  301. method: 'param',
  302. dynamic: false,
  303. fullpage: 'page=all',
  304. },
  305. {
  306. id: 'kompastv',
  307. description: 'kompas.tv',
  308. hostname: /(^|\.)kompas\.tv$/,
  309. path: /^\/article\/\d+\/.+(?<!\/\w+)$/,
  310. method: 'param',
  311. dynamic: false,
  312. fullpage: 'page=all',
  313. },
  314. {
  315. id: 'kontan',
  316. description: 'kontan.co.id',
  317. hostname: /(^|\.)kontan\.co\.id$/,
  318. path: /^\/news\/.+(?<!\/\w+)$/,
  319. method: 'param',
  320. dynamic: false,
  321. fullpage: 'page=all',
  322. },
  323. {
  324. id: 'merdeka',
  325. description: 'merdeka.com',
  326. hostname: /(^|\.)merdeka\.com$/,
  327. path: /\/[\w-]+\/.+\.html(?<!\/\w+)$/,
  328. method: 'dom',
  329. dynamic: false,
  330. },
  331. {
  332. id: 'popbela',
  333. description: 'popbela.com',
  334. hostname: /(^|\.)popbela\.com$/,
  335. path: /\/[\w-]+\/[\w-]+\/[\w-]+\/.+(?<!\/\w+)$/,
  336. method: 'param',
  337. dynamic: true,
  338. fullpage: 'page=all',
  339. },
  340. {
  341. id: 'pr',
  342. description: 'pikiran-rakyat.com',
  343. hostname: /(^|\.)pikiran-rakyat\.com$/,
  344. path: /\/pr-\d+\/.+(?<!\/\w+)$/,
  345. method: 'param',
  346. dynamic: false,
  347. fullpage: 'page=all',
  348. },
  349. {
  350. id: 'promedia',
  351. description: '20jam.com, aboutmalang.com, ayocirebon.com, jatimnetwork.com, hops.id, unews.id',
  352. hostname: /(^|\.)((20jam|aboutmalang|ayocirebon|ayoindonesia|dagangberita|kilat|jatimnetwork)\.com|(hops|pojoksatu|unews)\.id)$/,
  353. path: /\/(pr-|)\d+\/.+(?<!\/\w+)$/,
  354. method: 'param',
  355. dynamic: false,
  356. fullpage: 'page=all',
  357. },
  358. {
  359. id: 'sindo',
  360. description: 'sindonews.com',
  361. hostname: /(^|\.)sindonews\.com$/,
  362. path: /^\/read\/\d+\/\d+\/.+(\/\d+0|(?<!\/\w+))$/,
  363. method: 'param',
  364. dynamic: false,
  365. fullpage: 'showpage=all',
  366. },
  367. {
  368. id: 'suara',
  369. description: 'suara.com',
  370. hostname: /(^|\.)suara\.com$/,
  371. path: /\/\d{4}\/\d{2}\/\d{2}\/\d+\/.+(?<!\/\w+)$/,
  372. method: 'param',
  373. dynamic: false,
  374. fullpage: 'page=all',
  375. },
  376. {
  377. id: 'tribun',
  378. description: 'tribunnews.com',
  379. hostname: /(^|\.)tribunnews\.com$/,
  380. path: /\/\d{4}\/\d{2}\/\d{2}\/.+(?<!\/\w+)$/,
  381. method: 'param',
  382. dynamic: false,
  383. fullpage: 'page=all',
  384. },
  385. {
  386. id: 'viva',
  387. description: 'viva.co.id, tvonenews.com, intipseleb.com, sahijab.com, 100kpj.com',
  388. hostname: /(^|\.)(viva\.co\.id|(tvonenews|intipseleb|sahijab|100kpj)\.com)$/,
  389. path: /\/.+\/\d+-.+(?<!\/\w+)$/,
  390. method: 'param',
  391. dynamic: false,
  392. fullpage: 'page=all',
  393. },
  394. {
  395. id: 'wartaekonomi',
  396. description: 'wartaekonomi.co.id, herstory.co.id',
  397. hostname: /(^|\.)(wartaekonomi|herstory)\.co\.id$/,
  398. path: /^\/read\d+\/.+(?<!\/\w+)$/,
  399. method: 'param',
  400. dynamic: false,
  401. fullpage: 'page=all',
  402. },
  403. {
  404. id: 'cnn',
  405. description: 'cnnindonesia.com',
  406. hostname: /(^|\.)cnnindonesia\.com$/,
  407. path: /\/\d+-\d+-\d+\/.+(\/\d+|(?<!\/\w+))$/,
  408. method: 'xhr',
  409. dynamic: false,
  410. nextURL: '/',
  411. urlHelper: 0,
  412. desktop: {
  413. pagination: '.mb-8 > .gap-2.text-base',
  414. totalPages: 'a:last-of-type',
  415. content: '.detail-text',
  416. },
  417. mobile: {
  418. pagination: '.mb-8 > .gap-2.text-base',
  419. totalPages: 'a:last-of-type',
  420. content: '.detail-text',
  421. },
  422. },
  423. {
  424. id: 'disway',
  425. description: 'disway.id',
  426. hostname: /(^|\.)disway\.id$/,
  427. path: /\/read\/\d+\/.+(\/\d+|(?<!\/\w+))$/,
  428. method: 'xhr',
  429. dynamic: false,
  430. nextURL: '/',
  431. urlHelper: -13,
  432. desktop: {
  433. pagination: '.pagination',
  434. totalPages: 'li.active:nth-last-of-type(1), li:nth-last-of-type(2) a',
  435. content: '.post',
  436. },
  437. mobile: {
  438. pagination: '.pagination',
  439. totalPages: 'li.active:nth-last-of-type(1), li:nth-last-of-type(2) a',
  440. content: '.post',
  441. },
  442. },
  443. {
  444. id: 'genpi',
  445. description: 'genpi.co',
  446. hostname: /(^|\.)genpi\.co$/,
  447. path: /\/\d+\/.+(?<!\/\w+)$/,
  448. method: 'xhr',
  449. dynamic: false,
  450. nextURL: '?page=',
  451. urlHelper: 0,
  452. desktop: {
  453. pagination: '.mnmd-pagination',
  454. totalPages: 'li:nth-last-of-type(3) a',
  455. content: 'div.entry-content div.col-md-10',
  456. },
  457. mobile: {
  458. pagination: '.mnmd-pagination',
  459. totalPages: 'li:nth-last-of-type(3) a',
  460. content: '.entry-content',
  461. },
  462. },
  463. {
  464. id: 'jpnn',
  465. description: 'jpnn.com',
  466. hostname: /(^|\.)jpnn\.com$/,
  467. path: /\/(news|[a-z-]+\/\d+)\/.+(?<!\/\w+)$/,
  468. method: 'xhr',
  469. dynamic: false,
  470. nextURL: '?page=',
  471. urlHelper: 0,
  472. desktop: {
  473. pagination: '.pagination',
  474. totalPages: 'li:nth-last-of-type(3) a',
  475. content: 'div[itemprop=articleBody]',
  476. },
  477. mobile: {
  478. pagination: '.pagination',
  479. totalPages: 'li:nth-last-of-type(3) a',
  480. content: '.page-content',
  481. },
  482. },
  483. {
  484. id: 'okezone',
  485. description: 'okezone.com',
  486. hostname: /(^|\.)okezone\.com$/,
  487. path: /^\/read\/.+(?<!\/\w+)$/,
  488. method: 'xhr',
  489. dynamic: false,
  490. nextURL: '?page=',
  491. urlHelper: 0,
  492. desktop: {
  493. pagination: '.paging',
  494. totalPages: '.second-paging',
  495. content: '#contentx, #article-box',
  496. },
  497. mobile: {
  498. pagination: '.pagingxm',
  499. totalPages: '.halnext',
  500. content: '.read, #article-box',
  501. },
  502. },
  503. {
  504. id: 'republika',
  505. description: 'republika.co.id',
  506. hostname: /(^|\.)republika\.co\.id$/,
  507. path: /^\/berita\/.+(?<!\/\w+)$/,
  508. method: 'xhr',
  509. dynamic: false,
  510. nextURL: '-part',
  511. urlHelper: 1,
  512. desktop: {
  513. pagination: '.pagination',
  514. totalPages: 'a:nth-last-of-type(2)',
  515. content: 'article',
  516. },
  517. mobile: {
  518. pagination: '.pagination',
  519. totalPages: 'li:nth-last-of-type(2) a',
  520. content: 'article',
  521. },
  522. },
  523. {
  524. id: 'tempo',
  525. description: 'tempo.co',
  526. hostname: /(^|\.)tempo\.co$/,
  527. path: /^\/read\/.+(?<!\/\w+)$/,
  528. method: 'xhr',
  529. dynamic: false,
  530. nextURL: '?page_num=',
  531. urlHelper: 0,
  532. desktop: {
  533. pagination: '.pagging',
  534. totalPages: 'li:nth-last-of-type(2) a',
  535. content: '#isi',
  536. },
  537. mobile: {
  538. pagination: '.pagging',
  539. totalPages: 'li:nth-last-of-type(2) a',
  540. content: '#isi',
  541. },
  542. },
  543. ]
  544.  
  545. //******************************************************************************
  546.  
  547. const isValidURL = websiteList.find(urlChecker)
  548. if (isValidURL !== undefined) urlRedirector(isValidURL)
  549.  
  550. function urlRedirector(website) {
  551. const redirectURL = new URLBuilder().hostname(url.hostname())
  552. switch (website.method) {
  553. case 'param' :
  554. if (website.id === 'cnbc' || website.id === 'detik') {
  555. const newPath = url.path().replace(/\/\d+$/, '')
  556. redirectURL.path(...splitPath(newPath))
  557. } else {
  558. redirectURL.path(...splitPath(url.path()))
  559. }
  560. redirectURL.param(website.fullpage)
  561. const newURL = redirectURL.toString()
  562. if (url.href() !== newURL) redirect(newURL)
  563. break
  564. case 'path' :
  565. inewsRedirect(redirectURL, website.fullpage)
  566. break
  567. case 'dom' :
  568. case 'xhr' :
  569. neutralizeURL(redirectURL, website.id)
  570. }
  571. }
  572.  
  573. function inewsRedirect(redirectURL, fullPage) {
  574. const newPath = url.path().replace(/\/\d+$/, '')
  575. redirectURL.path(...splitPath(newPath), fullPage)
  576. redirect(redirectURL.toString())
  577. }
  578.  
  579. function neutralizeURL(redirectURL, id) {
  580. switch (id) {
  581. case 'genpi' :
  582. case 'idntimes' :
  583. case 'jpnn' :
  584. case 'merdeka':
  585. case 'okezone' :
  586. case 'tempo' :
  587. clearParamRedirect(redirectURL)
  588. break
  589. case 'cnn' :
  590. cnnRedirect(redirectURL)
  591. break
  592. case 'republika' :
  593. republikaRedirect(redirectURL)
  594. }
  595. }
  596.  
  597. function clearParamRedirect(redirectURL) {
  598. if (url.href().includes('?')) {
  599. redirectURL.path(...splitPath(url.path()))
  600. redirect(redirectURL.toString())
  601. }
  602. }
  603.  
  604. function cnnRedirect(redirectURL) {
  605. if (/\/\d+$/.test(url.path())) {
  606. const newPath = url.path().replace(/\/\d+$/, '')
  607. redirectURL.path(...splitPath(newPath))
  608. redirect(redirectURL.toString())
  609. }
  610. }
  611.  
  612. function republikaRedirect(redirectURL) {
  613. if (/-part\d+$/.test(url.path())) {
  614. const newPath = url.path().replace(/-part\d+$/, '')
  615. redirectURL.path(...splitPath(newPath))
  616. redirect(redirectURL)
  617. }
  618. }
  619.  
  620. //******************************************************************************
  621.  
  622. window.addEventListener('DOMContentLoaded', async () => {
  623. log('DOM telah selesai dimuat')
  624. const isValidHostname = websiteList.find(hostnameChecker)
  625. if (isValidHostname.dynamic === true) watchURL(isValidHostname)
  626. if (isValidURL !== undefined) {
  627. switch (isValidURL.method) {
  628. case 'dom':
  629. generalDOM(isValidURL)
  630. break
  631. case 'xhr':
  632. await generalXHR(isValidURL)
  633. break
  634. }
  635. }
  636. })
  637.  
  638. const isMobile = /(^|\.)m\./.test(url.hostname()) || window.navigator.userAgent.includes('Mobi')
  639. const isDesktop = !isMobile
  640.  
  641. function generalDOM(website) {
  642. switch (website.id) {
  643. case 'idntimes':
  644. idntimesDOM()
  645. break
  646. case 'merdeka':
  647. merdekaDOM()
  648. break
  649. }
  650. }
  651.  
  652. function idntimesDOM() {
  653. const readMoreButton = document.querySelector('.read-more-btn-check')
  654. const splitPage = document.getElementsByClassName('split-page')
  655.  
  656. if (readMoreButton !== null) {
  657. readMoreButton.remove()
  658. for (let i = 1; i < splitPage.length; i++) {
  659. splitPage[i].classList.add('open')
  660. }
  661. }
  662. }
  663.  
  664. function merdekaDOM() {
  665. const readMoreButton = document.querySelector('.btn--readarticle')
  666. if (readMoreButton != null) {
  667. (function findExpand() {
  668. setTimeout(() => {
  669. if (document.body.classList.contains('expand')) {
  670. document.body.classList.remove('expand')
  671. readMoreButton?.parentElement.classList.add('hidden')
  672. } else {
  673. findExpand()
  674. }
  675. }, 1000)
  676. })()
  677. }
  678. }
  679.  
  680. async function generalXHR(website) {
  681. const selector = isMobile ? website.mobile : website.desktop
  682. const totalPages = findTotalPages(selector.pagination, selector.totalPages)
  683. if (totalPages === 1) return
  684. const mainPageNode = document.querySelector(selector.content)
  685. cleaner(website.id, mainPageNode, 1, selector.pagination)
  686.  
  687. for (let i = 2; i <= totalPages; i++) {
  688. let nextPageUrl = url.href() + website.nextURL + (i - website.urlHelper)
  689. let nextPageNode = await getNextPage(nextPageUrl, i, selector.content)
  690. if (nextPageNode === null) return
  691. cleaner(website.id, nextPageNode, i, selector.pagination)
  692. let divider = pageDivider(i, totalPages)
  693. mainPageNode.append(divider, ...nextPageNode.children)
  694. log('Menambahkan halaman ke ' + i)
  695. }
  696. }
  697.  
  698. function findTotalPages(paginationSelector, totalPagesSelector) {
  699. let pagination, totalPages
  700. try {
  701. pagination = document.querySelector(paginationSelector)
  702. totalPages = pagination.querySelector(totalPagesSelector)
  703. .textContent
  704. .match(/\d+/)
  705. } catch (e) {
  706. totalPages = 1
  707. log(e)
  708. } finally {
  709. if (totalPages > 1) {
  710. //pagination.style.display = 'none'
  711. log('Pagination ditemukan, halaman berjumlah ' + totalPages)
  712. } else {
  713. totalPages = 1
  714. log('Pagination tidak ditemukan')
  715. }
  716. }
  717. return totalPages
  718. }
  719.  
  720. function getNextPage(url, pageNumber, target) {
  721. log('Bersiap membuat XHR')
  722. return new Promise((resolve, reject) => {
  723. const xhrParameter = {
  724. method: 'GET',
  725. url: url,
  726. overrideMimeType: 'text/html; charset=UTF-8',
  727. responseType: 'document',
  728. binary: false,
  729. timeout: 0,
  730. headers: {
  731. 'user-agent': window.navigator.userAgent,
  732. },
  733. onerror: function () {
  734. alert('[AutoAllPage] Tidak bisa membuka halaman ke ' + pageNumber)
  735. log('Gagal membuat request XHR')
  736. reject(null)
  737. },
  738. onload: function (res) {
  739. if (res.status === 429) {
  740. log('Retry page ' + pageNumber)
  741. setTimeout(() => GM_xmlhttpRequest(xhrParameter), 2000)
  742. } else {
  743. const content = res.response.querySelector(target)
  744. if (content != null) {
  745. log('Berhasil mendapatkan halaman ke ' + pageNumber)
  746. resolve(content)
  747. } else {
  748. alert('[AutoAllPage] Gagal mendapatkan halaman ke ' + pageNumber)
  749. log('Gagal mendapatkan halaman ke ' + pageNumber)
  750. reject(null)
  751. }
  752. }
  753. },
  754. }
  755. GM_xmlhttpRequest(xhrParameter)
  756. })
  757. }
  758.  
  759. //******************************************************************************
  760.  
  761. function cleaner(id, pageNode, pageNumber, pagination) {
  762. switch (id) {
  763. case 'cnn' :
  764. cnnCleaner(pageNode, pageNumber, pagination)
  765. break
  766. case 'genpi' :
  767. genpiCleaner(pageNode, pageNumber, pagination)
  768. break
  769. case 'okezone' :
  770. okezoneCleaner(pageNode, pageNumber)
  771. break
  772. case 'republika' :
  773. republikaCleaner(pageNode, pageNumber, pagination)
  774. break
  775. case 'tempo' :
  776. tempoCleaner(pageNode, pageNumber, pagination)
  777. }
  778. }
  779.  
  780. function cnnCleaner(pageNode, pageNumber, pagination) {
  781. if (pageNumber === 1) {
  782. document.querySelector('select[name="multipage"]')?.parentElement.remove()
  783. if (isDesktop) document.querySelector('.skybanner')?.remove()
  784. if (isMobile) {
  785. document.querySelector(pagination)?.parentElement.remove()
  786. document.querySelector('.inline-block > a')?.parentElement.remove()
  787. }
  788. }
  789.  
  790. if (isDesktop) {
  791. pageNode.querySelector('.inline-block > a[dtr-evt="halaman"]')?.remove()
  792. pageNode.querySelector(pagination)?.parentElement.remove()
  793. }
  794. log('Membersihkan halaman ke ' + pageNumber)
  795. }
  796.  
  797. function genpiCleaner(pageNode, pageNumber, pagination) {
  798. if (isDesktop && pageNumber > 1) pageNode.querySelector('.entry-thumb')?.remove()
  799. const footer = pageNode.querySelector(pagination)
  800. footer?.nextElementSibling.remove()
  801. footer?.remove()
  802. log('Membersihkan halaman ke ' + pageNumber)
  803. }
  804.  
  805. function okezoneCleaner(pageNode, pageNumber) {
  806. let footerArticle = pageNode.querySelector('#rctiplus')
  807. if (footerArticle === null) footerArticle = pageNode.querySelector('.box-gnews')
  808. if (footerArticle !== null) {
  809. while (pageNode.contains(footerArticle)) {
  810. pageNode.lastElementChild.remove()
  811. }
  812. log('Membersihkan halaman ke ' + pageNumber)
  813. }
  814. }
  815.  
  816. function republikaCleaner(pageNode, pageNumber, pagination) {
  817. pageNode.querySelector('.baca-juga')?.remove()
  818. pageNode.querySelector(pagination)?.remove()
  819. log('Membersihkan halaman ke ' + pageNumber)
  820. }
  821.  
  822. function tempoCleaner(pageNode, pageNumber, pagination) {
  823. pageNode.querySelector(pagination)?.remove()
  824. log('Membersihkan halaman ke ' + pageNumber)
  825. }
  826. })()