Auto All Page

Otomatis menampilkan semua halaman artikel berita dalam 1 halaman

当前为 2024-11-08 提交的版本,查看 最新版本

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