1+ // ==UserScript==
2+ // @name 3DM论坛增强
3+ // @version 1.0.0
4+ // @author X.I.U
5+ // @description 自动无缝翻页
6+ // @match *://bbs.3dmgame.com/*
7+ // @icon https://bbs.3dmgame.com/favicon.ico
8+ // @grant GM_xmlhttpRequest
9+ // @license GPL-3.0 License
10+ // @run -at document-end
11+ // @namespace https://greasyfork.org/scripts/412890
12+ // ==/UserScript==
13+
14+ ( function ( ) {
15+ // 默认 ID 为 0
16+ var curSite = { SiteTypeID : 0 } ;
17+
18+ // 自动翻页规则
19+ let DBSite = {
20+ forum : {
21+ SiteTypeID : 1
22+ } ,
23+ thread : {
24+ SiteTypeID : 2 ,
25+ pager : {
26+ nextLink : '//div[@id="pgt"]//a[contains(text(),"下一页")][@href]' ,
27+ pageElement : 'css;div#postlist > div[id^="post_"]' ,
28+ HT_insert : [ 'css;div#postlist' , 2 ] ,
29+ replaceE : '//div[@class="pg"] | //div[@class="pgbtn"]' ,
30+ }
31+ } ,
32+ guide : {
33+ SiteTypeID : 3 ,
34+ pager : {
35+ nextLink : '//div[@id="pgt"]//a[contains(text(),"下一页")][@href]' ,
36+ pageElement : 'css;div#threadlist div.bm_c table > tbody[id^="normalthread_"]' ,
37+ HT_insert : [ 'css;div#threadlist div.bm_c table' , 2 ] ,
38+ replaceE : 'css;div.pg' ,
39+ }
40+ }
41+ } ;
42+
43+ // 用于脚本内部判断当前 URL 类型
44+ let SiteType = {
45+ FORUM : DBSite . forum . SiteTypeID , // 各板块帖子列表
46+ THREAD : DBSite . thread . SiteTypeID , // 帖子内
47+ GUIDE : DBSite . guide . SiteTypeID // 导读帖子列表
48+ } ;
49+
50+ // URL 匹配正则表达式
51+ var patt_forum = / \/ f o r u m - \d + - \d + \. h t m l / ,
52+ patt_forum_2 = / m o d \= f o r u m d i s p l a y / ,
53+ patt_thread = / \/ t h r e a d - \d + - \d + \- \d + .h t m l / ,
54+ patt_thread_2 = / m o d \= v i e w t h r e a d / ,
55+ patt_guide = / m o d \= g u i d e \& v i e w \= ( h o t | d i g e s t ) /
56+
57+ // URL 判断
58+ if ( patt_thread . test ( location . pathname ) || patt_thread_2 . test ( location . search ) ) {
59+ curSite = DBSite . thread ;
60+ } else if ( patt_forum . test ( location . pathname ) || patt_forum_2 . test ( location . search ) ) {
61+ curSite = DBSite . forum ;
62+ } else if ( patt_guide . test ( location . search ) ) {
63+ curSite = DBSite . guide ;
64+ }
65+ curSite . pageUrl = "" ; // 下一页URL
66+
67+
68+ pageLoading ( ) ; // 自动翻页
69+
70+
71+ // 自动翻页
72+ function pageLoading ( ) {
73+ if ( curSite . SiteTypeID > 0 ) {
74+ windowScroll ( function ( direction , e ) {
75+ if ( direction === "down" ) { // 下滑才准备翻页
76+ var scrollTop = document . documentElement . scrollTop || window . pageYOffset || document . body . scrollTop ;
77+ let scrollDelta = 666 ;
78+ if ( document . documentElement . scrollHeight <= document . documentElement . clientHeight + scrollTop + scrollDelta ) {
79+ if ( curSite . SiteTypeID === SiteType . FORUM ) { // 如果是各版块帖子列表则直接点下一页就行了
80+ var autopbn = document . querySelector ( '#autopbn' ) ;
81+ if ( autopbn && autopbn . innerText == "下一页 »" ) { // 如果已经在加载中了,就忽略
82+ autopbn . click ( ) ;
83+ }
84+ } else {
85+ ShowPager . loadMorePage ( ) ;
86+ }
87+ }
88+ }
89+ } ) ;
90+ }
91+ }
92+
93+
94+ // 滚动条事件
95+ function windowScroll ( fn1 ) {
96+ var beforeScrollTop = document . documentElement . scrollTop ,
97+ fn = fn1 || function ( ) { } ;
98+ setTimeout ( function ( ) { // 延时执行,避免刚载入到页面就触发翻页事件
99+ window . addEventListener ( "scroll" , function ( e ) {
100+ var afterScrollTop = document . documentElement . scrollTop ,
101+ delta = afterScrollTop - beforeScrollTop ;
102+ if ( delta == 0 ) return false ;
103+ fn ( delta > 0 ? "down" : "up" , e ) ;
104+ beforeScrollTop = afterScrollTop ;
105+ } , false ) ;
106+ } , 1000 )
107+ }
108+
109+
110+ var ShowPager = { // 修改自 https://greasyfork.org/scripts/14178
111+ getFullHref : function ( e ) {
112+ if ( e == null ) return '' ;
113+ "string" != typeof e && ( e = e . getAttribute ( "href" ) ) ;
114+ var t = this . getFullHref . a ;
115+ return t || ( this . getFullHref . a = t = document . createElement ( "a" ) ) , t . href = e , t . href ;
116+ } ,
117+ createDocumentByString : function ( e ) {
118+ if ( e ) {
119+ if ( "HTML" !== document . documentElement . nodeName ) return ( new DOMParser ) . parseFromString ( e , "application/xhtml+xml" ) ;
120+ var t ;
121+ try {
122+ t = ( new DOMParser ) . parseFromString ( e , "text/html" ) ;
123+ } catch ( e ) {
124+ }
125+ if ( t ) return t ;
126+ if ( document . implementation . createHTMLDocument ) t = document . implementation . createHTMLDocument ( "ADocument" ) ; else try {
127+ ( t = document . cloneNode ( ! 1 ) ) . appendChild ( t . importNode ( document . documentElement , ! 1 ) ) ,
128+ t . documentElement . appendChild ( t . createElement ( "head" ) ) , t . documentElement . appendChild ( t . createElement ( "body" ) ) ;
129+ } catch ( e ) {
130+ }
131+ if ( t ) {
132+ var r = document . createRange ( ) ;
133+ r . selectNodeContents ( document . body ) ;
134+ var n = r . createContextualFragment ( e ) ;
135+ t . body . appendChild ( n ) ;
136+ for ( var a , o = {
137+ TITLE : ! 0 ,
138+ META : ! 0 ,
139+ LINK : ! 0 ,
140+ STYLE : ! 0 ,
141+ BASE : ! 0
142+ } , i = t . body , s = i . childNodes , c = s . length - 1 ; c >= 0 ; c -- ) o [ ( a = s [ c ] ) . nodeName ] && i . removeChild ( a ) ;
143+ return t ;
144+ }
145+ } else console . error ( "没有找到要转成DOM的字符串" ) ;
146+ } ,
147+ loadMorePage : function ( ) {
148+ if ( curSite . pager ) {
149+ let curPageEle = getElementByXpath ( curSite . pager . nextLink ) ;
150+ var url = this . getFullHref ( curPageEle ) ;
151+ //console.log(`${url} ${curPageEle} ${curSite.pageUrl}`);
152+ if ( url === '' ) return ;
153+ if ( curSite . pageUrl === url ) return ; // 不会重复加载相同的页面
154+ curSite . pageUrl = url ;
155+ // 读取下一页的数据
156+ curSite . pager . startFilter && curSite . pager . startFilter ( ) ;
157+ GM_xmlhttpRequest ( {
158+ url : url ,
159+ method : "GET" ,
160+ timeout : 5000 ,
161+ onload : function ( response ) {
162+ try {
163+ var newBody = ShowPager . createDocumentByString ( response . responseText ) ;
164+ let pageElems = getAllElements ( curSite . pager . pageElement , newBody , newBody ) ;
165+ let toElement = getAllElements ( curSite . pager . HT_insert [ 0 ] ) [ 0 ] ;
166+ if ( pageElems . length >= 0 ) {
167+ let addTo = "beforeend" ;
168+ if ( curSite . pager . HT_insert [ 1 ] == 1 ) addTo = "beforebegin" ;
169+ // 插入新页面元素
170+ pageElems . forEach ( function ( one ) {
171+ toElement . insertAdjacentElement ( addTo , one ) ;
172+ } ) ;
173+ // 替换待替换元素
174+ try {
175+ let oriE = getAllElements ( curSite . pager . replaceE ) ;
176+ let repE = getAllElements ( curSite . pager . replaceE , newBody , newBody ) ;
177+ if ( oriE . length === repE . length ) {
178+ for ( var i = 0 ; i < oriE . length ; i ++ ) {
179+ oriE [ i ] . outerHTML = repE [ i ] . outerHTML ;
180+ }
181+ }
182+ } catch ( e ) {
183+ console . log ( e ) ;
184+ }
185+ }
186+ } catch ( e ) {
187+ console . log ( e ) ;
188+ }
189+ }
190+ } ) ;
191+ }
192+ } ,
193+ } ;
194+
195+
196+ function getElementByXpath ( e , t , r ) {
197+ r = r || document , t = t || r ;
198+ try {
199+ return r . evaluate ( e , t , null , XPathResult . FIRST_ORDERED_NODE_TYPE , null ) . singleNodeValue ;
200+ } catch ( t ) {
201+ return void console . error ( "无效的xpath" ) ;
202+ }
203+ }
204+
205+
206+ function getAllElements ( e , t , r , n , o ) {
207+ let getAllElementsByXpath = function ( e , t , r ) {
208+ return r = r || document , t = t || r , r . evaluate ( e , t , null , XPathResult . ORDERED_NODE_SNAPSHOT_TYPE , null ) ;
209+ }
210+
211+ var i , s = [ ] ;
212+ if ( ! e ) return s ;
213+ if ( r = r || document , n = n || window , o = o || void 0 , t = t || r , "string" == typeof e ) i = 0 === e . search ( / ^ c s s ; / i) ? function getAllElementsByCSS ( e , t ) {
214+ return ( t || document ) . querySelectorAll ( e ) ;
215+ } ( e . slice ( 4 ) , t ) : getAllElementsByXpath ( e , t , r ) ; else {
216+ if ( ! ( i = e ( r , n , o ) ) ) return s ;
217+ if ( i . nodeType ) return s [ 0 ] = i , s ;
218+ }
219+ return function makeArray ( e ) {
220+ var t , r , n , o = [ ] ;
221+ if ( e . pop ) {
222+ for ( t = 0 , r = e . length ; t < r ; t ++ ) ( n = e [ t ] ) && ( n . nodeType ? o . push ( n ) : o = o . concat ( makeArray ( n ) ) ) ;
223+ return a ( ) ( o ) ;
224+ }
225+ if ( e . item ) {
226+ for ( t = e . length ; t ; ) o [ -- t ] = e [ t ] ;
227+ return o ;
228+ }
229+ if ( e . iterateNext ) {
230+ for ( t = e . snapshotLength ; t ; ) o [ -- t ] = e . snapshotItem ( t ) ;
231+ return o ;
232+ }
233+ } ( i ) ;
234+ }
235+ } ) ( ) ;
0 commit comments