forked from cadence/breezewiki
Compare commits
6 commits
9386d1c93e
...
411ebb3ab6
Author | SHA1 | Date | |
---|---|---|---|
411ebb3ab6 | |||
d5f992b7d8 | |||
2277c53956 | |||
e8923d3f5c | |||
c9eba0b5c3 | |||
d345fb8ff4 |
15 changed files with 206 additions and 238 deletions
|
@ -8,7 +8,6 @@
|
|||
racket/promise
|
||||
racket/port
|
||||
racket/runtime-path
|
||||
racket/sequence
|
||||
racket/string
|
||||
file/gunzip
|
||||
db
|
||||
|
@ -157,16 +156,8 @@
|
|||
(define data
|
||||
(cond
|
||||
[(and (read-from-cache?) (file-exists? "cache.rkt"))
|
||||
(define size (file-size "cache.rkt"))
|
||||
(call-with-input-file "cache.rkt"
|
||||
(λ (in)
|
||||
(define quit (make-progress (λ () (progress^ (ceiling (/ (file-position in) 64 1024))
|
||||
(ceiling (/ size 64 1024))
|
||||
"Reading in..."))
|
||||
2))
|
||||
(begin0
|
||||
(read in)
|
||||
(quit))))]
|
||||
(displayln "Reading in...")
|
||||
(with-input-from-file "cache.rkt" (λ () (read)))]
|
||||
[else
|
||||
(define x (box (progress^ 0 1 "...")))
|
||||
(define quit (make-progress (λ () (unbox x))))
|
||||
|
@ -192,22 +183,18 @@
|
|||
|
||||
(display "Converting... ")
|
||||
(flush-output)
|
||||
(define slice-size 30000)
|
||||
(define slices (ceiling (/ (length data) slice-size)))
|
||||
(for ([slice (in-slice slice-size data)]
|
||||
[i (in-naturals 1)])
|
||||
(define ser (jsexpr->bytes slice))
|
||||
(define ser-port (open-input-bytes ser))
|
||||
(define quit (make-progress (λ () (progress^ (ceiling (/ (file-position ser-port) 64 1024))
|
||||
(ceiling (/ (bytes-length ser) 64 1024))
|
||||
(format "Posting... (~a/~a)" i slices)))
|
||||
2))
|
||||
(define res
|
||||
(post (format "http://localhost:8983/solr/~a/update?commit=true" wikiname)
|
||||
#:data ser-port
|
||||
#:headers '#hasheq((Content-Type . "application/json"))
|
||||
#:timeouts (make-timeout-config #:lease 5 #:connect 5 #:request 300)))
|
||||
(quit)
|
||||
(displayln (response-status-line res))))
|
||||
(define ser (jsexpr->bytes data))
|
||||
(define ser-port (open-input-bytes ser))
|
||||
(define quit (make-progress (λ () (progress^ (ceiling (/ (file-position ser-port) 64 1024))
|
||||
(ceiling (/ (bytes-length ser) 64 1024))
|
||||
"Posting..."))
|
||||
2))
|
||||
(define res
|
||||
(post (format "http://localhost:8983/solr/~a/update?commit=true" wikiname)
|
||||
#:data ser-port
|
||||
#:headers '#hasheq((Content-Type . "application/json"))
|
||||
#:timeouts (make-timeout-config #:lease 5 #:connect 5 #:request 300)))
|
||||
(quit)
|
||||
(displayln (response-status-line res)))
|
||||
|
||||
(run start)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#lang racket/base
|
||||
(require "../src/data.rkt"
|
||||
(require (prefix-in easy: net/http-easy)
|
||||
"../src/data.rkt"
|
||||
"xexpr-utils.rkt")
|
||||
|
||||
(provide
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
(provide
|
||||
; headers to always send on all http responses
|
||||
always-headers
|
||||
; timeout durations for http-easy requests
|
||||
timeouts
|
||||
; generates a consistent footer
|
||||
application-footer
|
||||
; generates a consistent template for wiki page content to sit in
|
||||
|
@ -37,6 +39,7 @@
|
|||
(define always-headers
|
||||
(list (header #"Referrer-Policy" #"same-origin") ; header to not send referers to fandom
|
||||
(header #"Link" (string->bytes/latin-1 link-header))))
|
||||
(define timeouts (easy:make-timeout-config #:lease 5 #:connect 5))
|
||||
|
||||
(define-runtime-path path-static "../static")
|
||||
(define theme-icons
|
||||
|
@ -110,7 +113,7 @@
|
|||
(div (@ (class "niwa__left"))
|
||||
(p ,((extwiki-group^-description group) props))
|
||||
(p ,((extwiki^-description xt) props))
|
||||
(p "This wiki's core community has largely migrated away from Fandom. You should "
|
||||
(p "This wiki's core community has wholly migrated away from Fandom. You should "
|
||||
(a (@ (href ,go)) "go to " ,(extwiki^-name xt) " now!"))
|
||||
(p (@ (class "niwa__feedback"))
|
||||
,@(add-between
|
||||
|
@ -172,7 +175,7 @@
|
|||
(define styles
|
||||
(list
|
||||
(format "~a/wikia.php?controller=ThemeApi&method=themeVariables&variant=~a" origin (user-cookies^-theme user-cookies))
|
||||
(format "~a/load.php?lang=en&modules=site.styles%7Cskin.fandomdesktop.styles%7Cext.fandom.PortableInfoboxFandomDesktop.css%7Cext.fandom.GlobalComponents.CommunityHeaderBackground.css%7Cext.fandom.photoGallery.gallery.css%7Cext.gadget.site-styles%2Csound-styles&only=styles&skin=fandomdesktop" origin)))
|
||||
(format "~a/load.php?lang=en&modules=site.styles%7Cskin.fandomdesktop.styles%7Cext.fandom.PortableInfoboxFandomDesktop.css%7Cext.fandom.GlobalComponents.CommunityHeaderBackground.css%7Cext.gadget.site-styles%2Csound-styles&only=styles&skin=fandomdesktop" origin)))
|
||||
(if (config-true? 'strict_proxy)
|
||||
(map u-proxy-url styles)
|
||||
styles)]
|
||||
|
|
32
src/data.rkt
32
src/data.rkt
|
@ -7,8 +7,8 @@
|
|||
(prefix-in easy: net/http-easy)
|
||||
db
|
||||
memo
|
||||
"fandom-request.rkt"
|
||||
"static-data.rkt"
|
||||
"whole-utils.rkt"
|
||||
"../lib/url-utils.rkt"
|
||||
"../lib/xexpr-utils.rkt"
|
||||
"../archiver/archiver-database.rkt"
|
||||
|
@ -54,21 +54,21 @@
|
|||
(vector-ref row 3)))
|
||||
siteinfo-default)]
|
||||
[else
|
||||
(define res
|
||||
(fandom-get-api
|
||||
wikiname
|
||||
'(("action" . "query")
|
||||
("meta" . "siteinfo")
|
||||
("siprop" . "general|rightsinfo")
|
||||
("format" . "json")
|
||||
("formatversion" . "2"))))
|
||||
(cond [(= (easy:response-status-code res) 200)
|
||||
(define data (easy:response-json res))
|
||||
(siteinfo^ (jp "/query/general/sitename" data)
|
||||
(second (regexp-match #rx"/wiki/(.*)" (jp "/query/general/base" data)))
|
||||
(license^ (jp "/query/rightsinfo/text" data)
|
||||
(jp "/query/rightsinfo/url" data)))]
|
||||
[else siteinfo-default])]))
|
||||
(define dest-url
|
||||
(format "https://~a.fandom.com/api.php?~a"
|
||||
wikiname
|
||||
(params->query '(("action" . "query")
|
||||
("meta" . "siteinfo")
|
||||
("siprop" . "general|rightsinfo")
|
||||
("format" . "json")
|
||||
("formatversion" . "2")))))
|
||||
(log-outgoing dest-url)
|
||||
(define res (easy:get dest-url))
|
||||
(define data (easy:response-json res))
|
||||
(siteinfo^ (jp "/query/general/sitename" data)
|
||||
(second (regexp-match #rx"/wiki/(.*)" (jp "/query/general/base" data)))
|
||||
(license^ (jp "/query/rightsinfo/text" data)
|
||||
(jp "/query/rightsinfo/url" data)))]))
|
||||
|
||||
(define/memoize (head-data-getter wikiname) #:hash hash
|
||||
;; data will be stored here, can be referenced by the memoized closure
|
||||
|
|
|
@ -33,43 +33,26 @@
|
|||
; don't forget that I'm returning *code* - return a call to the function
|
||||
(datum->syntax stx `(make-dispatcher-tree ,ds)))
|
||||
|
||||
; guard that the page returned a response, otherwise print more detailed debugging information
|
||||
(define-syntax-rule (page ds name)
|
||||
(λ (req)
|
||||
(define dispatcher (hash-ref ds (quote name)))
|
||||
(define page-response (dispatcher req))
|
||||
(if (response? page-response)
|
||||
page-response
|
||||
(response/output
|
||||
#:code 500
|
||||
#:mime-type #"text/plain"
|
||||
(λ (out)
|
||||
(for ([port (list (current-error-port) out)])
|
||||
(parameterize ([current-output-port port])
|
||||
(printf "error in ~a:~n expected page to return a response~n actually returned: ~v~n"
|
||||
(quote name)
|
||||
page-response))))))))
|
||||
|
||||
(define (make-dispatcher-tree ds)
|
||||
(define subdomain-dispatcher (hash-ref ds 'subdomain-dispatcher))
|
||||
(define tree
|
||||
(sequencer:make
|
||||
subdomain-dispatcher
|
||||
(pathprocedure:make "/" (page ds page-home))
|
||||
(pathprocedure:make "/proxy" (page ds page-proxy))
|
||||
(pathprocedure:make "/search" (page ds page-global-search))
|
||||
(pathprocedure:make "/set-user-settings" (page ds page-set-user-settings))
|
||||
(pathprocedure:make "/buddyfight/wiki/It_Doesn't_Work!!" (page ds page-it-works))
|
||||
(filter:make (pregexp (format "^/~a/wiki/Category:.+$" px-wikiname)) (lift:make (page ds page-category)))
|
||||
(filter:make (pregexp (format "^/~a/wiki/File:.+$" px-wikiname)) (lift:make (page ds page-file)))
|
||||
(pathprocedure:make "/" (hash-ref ds 'page-home))
|
||||
(pathprocedure:make "/proxy" (hash-ref ds 'page-proxy))
|
||||
(pathprocedure:make "/search" (hash-ref ds 'page-global-search))
|
||||
(pathprocedure:make "/set-user-settings" (hash-ref ds 'page-set-user-settings))
|
||||
(pathprocedure:make "/buddyfight/wiki/It_Doesn't_Work!!" (hash-ref ds 'page-it-works))
|
||||
(filter:make (pregexp (format "^/~a/wiki/Category:.+$" px-wikiname)) (lift:make (hash-ref ds 'page-category)))
|
||||
(filter:make (pregexp (format "^/~a/wiki/File:.+$" px-wikiname)) (lift:make (hash-ref ds 'page-file)))
|
||||
(if (config-true? 'feature_offline::enabled)
|
||||
(filter:make (pregexp (format "^/~a/wiki/.+$" px-wikiname)) (lift:make (page ds page-wiki-offline)))
|
||||
(filter:make (pregexp (format "^/~a/wiki/.+$" px-wikiname)) (lift:make (hash-ref ds 'page-wiki-offline)))
|
||||
(λ (_conn _req) (next-dispatcher)))
|
||||
(filter:make (pregexp (format "^/~a/wiki/.+$" px-wikiname)) (lift:make (page ds page-wiki)))
|
||||
(filter:make (pregexp (format "^/~a/search$" px-wikiname)) (lift:make (page ds page-search)))
|
||||
(filter:make (pregexp (format "^/~a(/(wiki(/)?)?)?$" px-wikiname)) (lift:make (page ds redirect-wiki-home)))
|
||||
(filter:make (pregexp (format "^/~a/wiki/.+$" px-wikiname)) (lift:make (hash-ref ds 'page-wiki)))
|
||||
(filter:make (pregexp (format "^/~a/search$" px-wikiname)) (lift:make (hash-ref ds 'page-search)))
|
||||
(filter:make (pregexp (format "^/~a(/(wiki(/)?)?)?$" px-wikiname)) (lift:make (hash-ref ds 'redirect-wiki-home)))
|
||||
(if (config-true? 'feature_offline::enabled)
|
||||
(filter:make (pregexp (format "^/archive/~a/(styles|images)/.+$" px-wikiname)) (lift:make (page ds page-static-archive)))
|
||||
(filter:make (pregexp (format "^/archive/~a/(styles|images)/.+$" px-wikiname)) (lift:make (hash-ref ds 'page-static-archive)))
|
||||
(λ (_conn _req) (next-dispatcher)))
|
||||
(hash-ref ds 'static-dispatcher)
|
||||
(lift:make (hash-ref ds 'page-not-found))))
|
||||
|
|
|
@ -71,13 +71,6 @@
|
|||
(λ (props)
|
||||
'(p "The wiki was founded by Citricsquid on July 16th, 2009 as a way to document information from Minecraft. Since November 15th, 2010, it has been hosted by Curse Media. On December 12th, 2018, it moved to Fandom as it purchased Curse Media. Since September 24, 2023, it forked from Fandom and has been hosted by Weird Gloop.")))
|
||||
|
||||
'Tardis
|
||||
(extwiki-group^
|
||||
"Tardis"
|
||||
'(("Forking announcement" . "https://tardis.wiki/wiki/Tardis:Forking_announcement")
|
||||
("Discussion on Reddit" . "https://old.reddit.com/r/doctorwho/comments/1azxmrl/tardis_wiki_has_regenerated/"))
|
||||
(λ (props) '()))
|
||||
|
||||
'empty
|
||||
(extwiki-group^
|
||||
"Misc"
|
||||
|
@ -426,15 +419,6 @@
|
|||
(λ (props)
|
||||
`()))
|
||||
|
||||
(extwiki^
|
||||
'("tardis") 'default
|
||||
'Tardis
|
||||
"Tardis Data Core"
|
||||
"https://tardis.wiki/wiki/Doctor_Who_Wiki"
|
||||
"https://tardis.wiki/images/Tardis_images/e/e6/Site-logo.png"
|
||||
(λ (props)
|
||||
`()))
|
||||
|
||||
;; fandom wikinames * empty * empty * Name * Home Page
|
||||
(extwiki^ '("aether") 'empty 'empty "Aether Wiki" "https://aether.wiki.gg/wiki/Aether_Wiki" #f #f)
|
||||
(extwiki^ '("before-darkness-falls") 'empty 'empty "Before Darkness Falls Wiki" "https://beforedarknessfalls.wiki.gg/wiki/Before_Darkness_Falls_Wiki" #f #f)
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
#lang typed/racket/base
|
||||
(require "config.rkt"
|
||||
"../lib/url-utils.rkt")
|
||||
(define-type Headers (HashTable Symbol (U Bytes String)))
|
||||
(require/typed net/http-easy
|
||||
[#:opaque Timeout-Config timeout-config?]
|
||||
[#:opaque Response response?]
|
||||
[#:opaque Session session?]
|
||||
[current-session (Parameter Session)]
|
||||
[make-timeout-config ([#:lease Positive-Real] [#:connect Positive-Real] -> Timeout-Config)]
|
||||
[get ((U Bytes String)
|
||||
[#:close? Boolean]
|
||||
[#:headers Headers]
|
||||
[#:timeouts Timeout-Config]
|
||||
[#:max-attempts Exact-Positive-Integer]
|
||||
[#:max-redirects Exact-Nonnegative-Integer]
|
||||
[#:user-agent (U Bytes String)]
|
||||
-> Response)])
|
||||
|
||||
(provide
|
||||
fandom-get
|
||||
fandom-get-api
|
||||
timeouts)
|
||||
|
||||
(define timeouts (make-timeout-config #:lease 5 #:connect 5))
|
||||
|
||||
(: no-headers Headers)
|
||||
(define no-headers '#hasheq())
|
||||
|
||||
(: fandom-get (String String [#:headers (Option Headers)] -> Response))
|
||||
(define (fandom-get wikiname path #:headers [headers #f])
|
||||
(define dest-url (string-append "https://www.fandom.com" path))
|
||||
(define host (string-append wikiname ".fandom.com"))
|
||||
(log-outgoing wikiname path)
|
||||
(get dest-url
|
||||
#:timeouts timeouts
|
||||
#:headers (hash-set (or headers no-headers) 'Host host)))
|
||||
|
||||
(: fandom-get-api (String (Listof (Pair String String)) [#:headers (Option Headers)] -> Response))
|
||||
(define (fandom-get-api wikiname params #:headers [headers #f])
|
||||
(fandom-get wikiname
|
||||
(string-append "/api.php?" (params->query params))
|
||||
#:headers headers))
|
||||
|
||||
(: log-outgoing (String String -> Void))
|
||||
(define (log-outgoing wikiname path)
|
||||
(when (config-true? 'log_outgoing)
|
||||
(printf "out: ~a ~a~n" wikiname path)))
|
|
@ -15,11 +15,11 @@
|
|||
"application-globals.rkt"
|
||||
"config.rkt"
|
||||
"data.rkt"
|
||||
"fandom-request.rkt"
|
||||
"page-wiki.rkt"
|
||||
"../lib/syntax.rkt"
|
||||
"../lib/thread-utils.rkt"
|
||||
"../lib/url-utils.rkt"
|
||||
"whole-utils.rkt"
|
||||
"../lib/xexpr-utils.rkt")
|
||||
|
||||
(provide
|
||||
|
@ -73,24 +73,30 @@
|
|||
(define-values (members-data page-data siteinfo)
|
||||
(thread-values
|
||||
(λ ()
|
||||
(easy:response-json
|
||||
(fandom-get-api
|
||||
wikiname
|
||||
`(("action" . "query")
|
||||
("list" . "categorymembers")
|
||||
("cmtitle" . ,prefixed-category)
|
||||
("cmlimit" . "max")
|
||||
("formatversion" . "2")
|
||||
("format" . "json")))))
|
||||
(define dest-url
|
||||
(format "~a/api.php?~a"
|
||||
origin
|
||||
(params->query `(("action" . "query")
|
||||
("list" . "categorymembers")
|
||||
("cmtitle" . ,prefixed-category)
|
||||
("cmlimit" . "max")
|
||||
("formatversion" . "2")
|
||||
("format" . "json")))))
|
||||
(log-outgoing dest-url)
|
||||
(define dest-res (easy:get dest-url #:timeouts timeouts))
|
||||
(easy:response-json dest-res))
|
||||
(λ ()
|
||||
(easy:response-json
|
||||
(fandom-get-api
|
||||
wikiname
|
||||
`(("action" . "parse")
|
||||
("page" . ,prefixed-category)
|
||||
("prop" . "text|headhtml|langlinks")
|
||||
("formatversion" . "2")
|
||||
("format" . "json")))))
|
||||
(define dest-url
|
||||
(format "~a/api.php?~a"
|
||||
origin
|
||||
(params->query `(("action" . "parse")
|
||||
("page" . ,prefixed-category)
|
||||
("prop" . "text|headhtml|langlinks")
|
||||
("formatversion" . "2")
|
||||
("format" . "json")))))
|
||||
(log-outgoing dest-url)
|
||||
(define dest-res (easy:get dest-url #:timeouts timeouts))
|
||||
(easy:response-json dest-res))
|
||||
(λ ()
|
||||
(siteinfo-fetch wikiname))))
|
||||
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
"application-globals.rkt"
|
||||
"config.rkt"
|
||||
"data.rkt"
|
||||
"fandom-request.rkt"
|
||||
"page-wiki.rkt"
|
||||
"../lib/syntax.rkt"
|
||||
"../lib/thread-utils.rkt"
|
||||
"../lib/url-utils.rkt"
|
||||
"whole-utils.rkt"
|
||||
"../lib/xexpr-utils.rkt")
|
||||
|
||||
(provide page-file)
|
||||
|
@ -40,7 +40,8 @@
|
|||
(imageDescription . #f))))
|
||||
|
||||
(define (url-content-type url)
|
||||
(define dest-res (easy:head url))
|
||||
(log-outgoing url)
|
||||
(define dest-res (easy:head url #:timeouts timeouts))
|
||||
(easy:response-headers-ref dest-res 'content-type))
|
||||
|
||||
(define (get-media-html url content-type)
|
||||
|
@ -105,18 +106,20 @@
|
|||
(response-handler
|
||||
(define wikiname (path/param-path (first (url-path (request-uri req)))))
|
||||
(define prefixed-title (path/param-path (caddr (url-path (request-uri req)))))
|
||||
(define source-url (format "https://~a.fandom.com/wiki/~a" wikiname prefixed-title))
|
||||
(define origin (format "https://~a.fandom.com" wikiname))
|
||||
(define source-url (format "~a/wiki/~a" origin prefixed-title))
|
||||
|
||||
(define-values (media-detail siteinfo)
|
||||
(thread-values
|
||||
(λ ()
|
||||
(define dest-res
|
||||
(fandom-get
|
||||
wikiname
|
||||
(format "/wikia.php?~a"
|
||||
(params->query `(("format" . "json") ("controller" . "Lightbox")
|
||||
("method" . "getMediaDetail")
|
||||
("fileTitle" . ,prefixed-title))))))
|
||||
(define dest-url
|
||||
(format "~a/wikia.php?~a"
|
||||
origin
|
||||
(params->query `(("format" . "json") ("controller" . "Lightbox")
|
||||
("method" . "getMediaDetail")
|
||||
("fileTitle" . ,prefixed-title)))))
|
||||
(log-outgoing dest-url)
|
||||
(define dest-res (easy:get dest-url #:timeouts timeouts))
|
||||
(easy:response-json dest-res))
|
||||
(λ ()
|
||||
(siteinfo-fetch wikiname))))
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
(require racket/dict
|
||||
racket/list
|
||||
racket/string
|
||||
(prefix-in easy: net/http-easy)
|
||||
; html libs
|
||||
html-writing
|
||||
; web server libs
|
||||
|
@ -17,14 +18,15 @@
|
|||
"../lib/syntax.rkt"
|
||||
"../lib/thread-utils.rkt"
|
||||
"../lib/url-utils.rkt"
|
||||
"whole-utils.rkt"
|
||||
"../lib/xexpr-utils.rkt")
|
||||
|
||||
(provide
|
||||
page-search)
|
||||
|
||||
(define search-providers
|
||||
(hash "fandom" search-fandom
|
||||
"solr" search-solr))
|
||||
(hash "fandom" generate-results-content-fandom
|
||||
"solr" generate-results-content-solr))
|
||||
|
||||
;; this takes the info we gathered from fandom and makes the big fat x-expression page
|
||||
(define (generate-results-page req source-url wikiname query results-content #:siteinfo [siteinfo #f])
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
"application-globals.rkt"
|
||||
"config.rkt"
|
||||
"data.rkt"
|
||||
"fandom-request.rkt"
|
||||
"../lib/pure-utils.rkt"
|
||||
"../lib/syntax.rkt"
|
||||
"../lib/thread-utils.rkt"
|
||||
"../lib/tree-updater.rkt"
|
||||
"../lib/url-utils.rkt"
|
||||
"whole-utils.rkt"
|
||||
"../lib/xexpr-utils.rkt")
|
||||
|
||||
(provide
|
||||
|
@ -38,20 +38,25 @@
|
|||
(define (page-wiki req)
|
||||
(define wikiname (path/param-path (first (url-path (request-uri req)))))
|
||||
(define user-cookies (user-cookies-getter req))
|
||||
(define origin (format "https://~a.fandom.com" wikiname))
|
||||
(define path (string-join (map path/param-path (cddr (url-path (request-uri req)))) "/"))
|
||||
(define source-url (format "https://~a.fandom.com/wiki/~a" wikiname path))
|
||||
|
||||
(define-values (dest-res siteinfo)
|
||||
(thread-values
|
||||
(λ ()
|
||||
(fandom-get-api
|
||||
wikiname
|
||||
`(("action" . "parse")
|
||||
("page" . ,path)
|
||||
("prop" . "text|headhtml|langlinks")
|
||||
("formatversion" . "2")
|
||||
("format" . "json"))
|
||||
#:headers `#hasheq((cookie . ,(format "theme=~a" (user-cookies^-theme user-cookies))))))
|
||||
(define dest-url
|
||||
(format "~a/api.php?~a"
|
||||
origin
|
||||
(params->query `(("action" . "parse")
|
||||
("page" . ,path)
|
||||
("prop" . "text|headhtml|langlinks")
|
||||
("formatversion" . "2")
|
||||
("format" . "json")))))
|
||||
(log-outgoing dest-url)
|
||||
(easy:get dest-url
|
||||
#:timeouts timeouts
|
||||
#:headers `#hasheq((cookie . ,(format "theme=~a" (user-cookies^-theme user-cookies))))))
|
||||
(λ ()
|
||||
(siteinfo-fetch wikiname))))
|
||||
|
||||
|
@ -98,13 +103,4 @@
|
|||
#:code 200
|
||||
#:headers headers
|
||||
(λ (out)
|
||||
(write-html body out))))))]
|
||||
[(eq? 404 (easy:response-status-code dest-res))
|
||||
(next-dispatcher)]
|
||||
[else
|
||||
(response-handler
|
||||
(error 'page-wiki "Tried to load page ~a/~v~nSadly, the page didn't load because Fandom returned status code ~a with response:~n~a"
|
||||
wikiname
|
||||
path
|
||||
(easy:response-status-code dest-res)
|
||||
(easy:response-body dest-res)))]))
|
||||
(write-html body out))))))]))
|
||||
|
|
|
@ -3,34 +3,38 @@
|
|||
(prefix-in easy: net/http-easy)
|
||||
"application-globals.rkt"
|
||||
"config.rkt"
|
||||
"fandom-request.rkt"
|
||||
"../lib/url-utils.rkt"
|
||||
"whole-utils.rkt"
|
||||
"../lib/xexpr-utils.rkt")
|
||||
|
||||
(provide
|
||||
search-fandom)
|
||||
generate-results-content-fandom)
|
||||
|
||||
(module+ test
|
||||
(require rackunit
|
||||
"test-utils.rkt")
|
||||
(define search-results-data
|
||||
'(#hasheq((ns . 0) (pageid . 219) (size . 1482) (snippet . "") (timestamp . "2022-08-21T08:54:23Z") (title . "Gacha Capsule") (wordcount . 214)) #hasheq((ns . 0) (pageid . 201) (size . 1198) (snippet . "") (timestamp . "2022-07-11T17:52:47Z") (title . "Badges") (wordcount . 181)))))
|
||||
(define search-json-data
|
||||
'#hasheq((batchcomplete . #t) (query . #hasheq((search . (#hasheq((ns . 0) (pageid . 219) (size . 1482) (snippet . "") (timestamp . "2022-08-21T08:54:23Z") (title . "Gacha Capsule") (wordcount . 214)) #hasheq((ns . 0) (pageid . 201) (size . 1198) (snippet . "") (timestamp . "2022-07-11T17:52:47Z") (title . "Badges") (wordcount . 181)))))))))
|
||||
|
||||
(define (search-fandom wikiname query params)
|
||||
(define res
|
||||
(fandom-get-api
|
||||
wikiname
|
||||
`(("action" . "query")
|
||||
("list" . "search")
|
||||
("srsearch" . ,query)
|
||||
("formatversion" . "2")
|
||||
("format" . "json"))))
|
||||
(define (generate-results-content-fandom wikiname query params)
|
||||
;; constructing the URL where I want to get fandom data from...
|
||||
(define origin (format "https://~a.fandom.com" wikiname))
|
||||
;; the dest-URL will look something like https://minecraft.fandom.com/api.php?action=query&list=search&srsearch=Spawner&formatversion=2&format=json
|
||||
(define dest-url
|
||||
(format "~a/api.php?~a"
|
||||
origin
|
||||
(params->query `(("action" . "query")
|
||||
("list" . "search")
|
||||
("srsearch" . ,query)
|
||||
("formatversion" . "2")
|
||||
("format" . "json")))))
|
||||
;; HTTP request to dest-url for search results
|
||||
(log-outgoing dest-url)
|
||||
(define res (easy:get dest-url #:timeouts timeouts))
|
||||
(define json (easy:response-json res))
|
||||
(define search-results (jp "/query/search" json))
|
||||
(generate-results-content-fandom wikiname query search-results))
|
||||
|
||||
;;; generate content for display in the wiki page layout
|
||||
(define (generate-results-content-fandom wikiname query search-results)
|
||||
;; generate content for display in the wiki page layout
|
||||
`(div (@ (class "mw-parser-output"))
|
||||
;; header before the search results showing how many we found
|
||||
(p ,(format "~a results found for " (length search-results))
|
||||
|
@ -56,4 +60,4 @@
|
|||
(module+ test
|
||||
(parameterize ([(config-parameter 'feature_offline::only) "false"])
|
||||
(check-not-false ((query-selector (attribute-selector 'href "/test/wiki/Gacha_Capsule")
|
||||
(generate-results-content-fandom "test" "Gacha" search-results-data))))))
|
||||
(generate-results-content-fandom test-req "" "test" "Gacha" search-json-data))))))
|
||||
|
|
|
@ -5,14 +5,15 @@
|
|||
"application-globals.rkt"
|
||||
"../lib/html-parsing/main.rkt"
|
||||
"../lib/url-utils.rkt"
|
||||
"whole-utils.rkt"
|
||||
"../lib/xexpr-utils.rkt")
|
||||
|
||||
(provide
|
||||
search-solr)
|
||||
generate-results-content-solr)
|
||||
|
||||
(struct result^ (hl-title hl-body kb words page-path) #:transparent)
|
||||
|
||||
(define (search-solr wikiname query params)
|
||||
(define (generate-results-content-solr wikiname query params)
|
||||
;; grab things from params that would modify the search
|
||||
(define op (if (equal? (dict-ref params 'op #f) "or") '("or" . "OR") '("and" . "AND")))
|
||||
(define sort (if (equal? (dict-ref params 'sort #f) "len") '("len" . "len desc") '("relevance" . "score desc")))
|
||||
|
@ -35,7 +36,8 @@
|
|||
("hl.tag.post" . "</mark>")
|
||||
("sort" . ,(cdr sort))))))
|
||||
;; HTTP request to dest-url for search results
|
||||
(define res (easy:get dest-url #:timeouts (easy:make-timeout-config #:lease 5 #:connect 5)))
|
||||
(log-outgoing dest-url)
|
||||
(define res (easy:get dest-url #:timeouts timeouts))
|
||||
(define json (easy:response-json res))
|
||||
|
||||
;; build result objects
|
||||
|
|
11
src/whole-utils.rkt
Normal file
11
src/whole-utils.rkt
Normal file
|
@ -0,0 +1,11 @@
|
|||
#lang typed/racket/base
|
||||
(require "config.rkt")
|
||||
|
||||
(provide
|
||||
; prints "out: <url>"
|
||||
log-outgoing)
|
||||
|
||||
(: log-outgoing (String -> Void))
|
||||
(define (log-outgoing url-string)
|
||||
(when (config-true? 'log_outgoing)
|
||||
(printf "out: ~a~n" url-string)))
|
|
@ -1,40 +1,74 @@
|
|||
"use strict";
|
||||
|
||||
const tabFromHash = location.hash.length > 1 ? location.hash.substring(1) : null
|
||||
let tabToFind = location.hash.length > 1 ? location.hash.substring(1) : null;
|
||||
for (let tabber of document.body.querySelectorAll(".wds-tabber")) {
|
||||
let [tabs, contents] = getTabs(tabber);
|
||||
|
||||
for (const tabber of document.body.querySelectorAll(".wds-tabber")) {
|
||||
for (const [tab, content] of getTabberTabs(tabber)) {
|
||||
// set up click listener on every tab
|
||||
tab.addEventListener("click", e => {
|
||||
setCurrentTab(tabber, tab, content)
|
||||
e.preventDefault()
|
||||
})
|
||||
for (let i in tabs) {
|
||||
let tab = tabs[i];
|
||||
let content = contents[i];
|
||||
|
||||
// re-open a specific tab on page load based on the URL hash
|
||||
if (tab.dataset.hash === tabFromHash) {
|
||||
setCurrentTab(tabber, tab, content)
|
||||
tab.scrollIntoView()
|
||||
}
|
||||
}
|
||||
tab.addEventListener("click", function(e) {
|
||||
setCurrentTab(tabber, tab, content);
|
||||
e.preventDefault();
|
||||
});
|
||||
if (tab.dataset.hash === tabToFind) {
|
||||
setCurrentTab(tabber, tab, content);
|
||||
}
|
||||
}
|
||||
}
|
||||
document.body.classList.remove("bw-tabs-nojs");
|
||||
|
||||
|
||||
|
||||
function getTabs(tabber) {
|
||||
let tabs = [];
|
||||
let contents = [];
|
||||
|
||||
for (let i of tabber.querySelector(".wds-tabs__wrapper").querySelectorAll(".wds-tabs__tab")) {
|
||||
tabs.push(i);
|
||||
}
|
||||
for (let i of tabber.children) {
|
||||
if (!i.matches(".wds-tab__content")) {
|
||||
continue;
|
||||
}
|
||||
contents.push(i);
|
||||
}
|
||||
|
||||
return [tabs, contents];
|
||||
}
|
||||
|
||||
function getTabberTabs(tabber) {
|
||||
// need to scope the selector to handle nested tabs. see /unturned/wiki/Crate for an example
|
||||
const tabs = [...tabber.querySelectorAll(":scope > .wds-tabs__wrapper .wds-tabs__tab")]
|
||||
const contents = [...tabber.querySelectorAll(":scope > .wds-tab__content")]
|
||||
return tabs.map((_, index) => [tabs[index], contents[index]]) // transpose arrays into [[tab, content], ...]
|
||||
function getCurrentTab(tabber) {
|
||||
let tab = null;
|
||||
let content = null;
|
||||
|
||||
tab = tabber.querySelector(".wds-tabs__wrapper").querySelector(".wds-tabs__tab.wds-is-current");
|
||||
for (let i of tabber.children) {
|
||||
if (!i.matches(".wds-tab__content.wds-is-current")) {
|
||||
continue;
|
||||
}
|
||||
content = i;
|
||||
break;
|
||||
}
|
||||
|
||||
return [tab, content];
|
||||
}
|
||||
|
||||
function setCurrentTab(tabber, tab, content) {
|
||||
// clear currently selected tab
|
||||
getTabberTabs(tabber).flat().forEach(e => e.classList.remove("wds-is-current"))
|
||||
let [currentTab, currentContent] = getCurrentTab(tabber);
|
||||
if (currentTab) {
|
||||
currentTab.classList.remove("wds-is-current");
|
||||
}
|
||||
if (currentContent) {
|
||||
currentContent.classList.remove("wds-is-current");
|
||||
}
|
||||
|
||||
// select new tab
|
||||
tab.classList.add("wds-is-current")
|
||||
content.classList.add("wds-is-current")
|
||||
if (tab.dataset.hash) {
|
||||
history.replaceState(null, "", `#${tab.dataset.hash}`)
|
||||
}
|
||||
tab.classList.add("wds-is-current");
|
||||
content.classList.add("wds-is-current");
|
||||
if (tab.dataset.hash) {
|
||||
let fragment = "#" + tab.dataset.hash;
|
||||
if (location.hash !== fragment) {
|
||||
history.pushState(null, "", fragment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.body.classList.remove("bw-tabs-nojs")
|
||||
|
|
Loading…
Reference in a new issue