├── docker └── .gitkeep ├── document └── .gitkeep ├── packed └── packed.go ├── .gitattributes ├── public ├── favicon.ico ├── assets │ ├── library.png │ ├── bg-default.jpg │ └── js │ │ └── pako.min.js ├── static │ ├── img │ │ └── loading.cbe6a5b.gif │ ├── js │ │ └── manifest.5e6c6e707be36332be94.js │ └── css │ │ └── index.8f174259337d201a961b56ae2f227b1b.css └── index.html ├── go.mod ├── app ├── service │ ├── middleware │ │ ├── cors.go │ │ ├── auth.go │ │ └── white.go │ ├── Book.go │ ├── Article.go │ ├── BooKService.go │ ├── Sources.go │ ├── SearchBook.go │ └── Catalog.go ├── model │ ├── book.go │ └── source.go └── api │ └── book │ └── book.go ├── .gitignore ├── main.go ├── boot └── boot.go ├── router └── router.go ├── library ├── version │ └── version.go ├── response │ └── response.go └── utils │ └── stringex.go ├── Dockerfile ├── config ├── config.toml └── source │ ├── biqiuge.json │ ├── ttkan.json │ └── com17k.json ├── LICENSE ├── curl.sh └── README.md /docker/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /document/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packed/packed.go: -------------------------------------------------------------------------------- 1 | package packed 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * linguist-language=GO 2 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xinjiayu/NovelServer/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/assets/library.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xinjiayu/NovelServer/HEAD/public/assets/library.png -------------------------------------------------------------------------------- /public/assets/bg-default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xinjiayu/NovelServer/HEAD/public/assets/bg-default.jpg -------------------------------------------------------------------------------- /public/static/img/loading.cbe6a5b.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xinjiayu/NovelServer/HEAD/public/static/img/loading.cbe6a5b.gif -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module NovelServer 2 | 3 | require ( 4 | github.com/PuerkitoBio/goquery v1.6.0 5 | github.com/gogf/gf v1.14.3 6 | ) 7 | 8 | go 1.15 9 | -------------------------------------------------------------------------------- /app/service/middleware/cors.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import "github.com/gogf/gf/net/ghttp" 4 | 5 | // 允许接口跨域请求 6 | func CORS(r *ghttp.Request) { 7 | r.Response.CORSDefault() 8 | r.Middleware.Next() 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .buildpath 2 | .hgignore.swp 3 | .project 4 | .orig 5 | .swp 6 | .idea/ 7 | .settings/ 8 | .vscode/ 9 | vender/ 10 | log/ 11 | composer.lock 12 | gitpush.sh 13 | pkg/ 14 | bin/ 15 | cbuild 16 | */.DS_Store 17 | main 18 | .vscode 19 | go.sum -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "NovelServer/boot" 5 | "NovelServer/library/version" 6 | _ "NovelServer/router" 7 | "github.com/gogf/gf/frame/g" 8 | ) 9 | 10 | var ( 11 | BuildVersion = "0.0" 12 | BuildTime = "" 13 | CommitID = "" 14 | ) 15 | 16 | func main() { 17 | version.ShowLogo(BuildVersion, BuildTime, CommitID) 18 | g.Server().Run() 19 | } 20 | -------------------------------------------------------------------------------- /boot/boot.go: -------------------------------------------------------------------------------- 1 | package boot 2 | 3 | import ( 4 | _ "NovelServer/packed" 5 | "github.com/gogf/gf/frame/g" 6 | "github.com/gogf/gf/os/glog" 7 | "github.com/gogf/gf/os/gtime" 8 | ) 9 | 10 | func init() { 11 | err := gtime.SetTimeZone("Asia/Shanghai") //设置系统时区 12 | if err != nil { 13 | glog.Error(err) 14 | } 15 | logPath := g.Config().GetString("logger.path") 16 | err = glog.SetPath(logPath) 17 | if err != nil { 18 | glog.Error(err) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/service/middleware/auth.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/gogf/gf/frame/g" 5 | "github.com/gogf/gf/net/ghttp" 6 | "github.com/gogf/gf/os/glog" 7 | "net/http" 8 | ) 9 | 10 | func Auth(r *ghttp.Request) { 11 | 12 | secretKey := g.Config().GetString("system.SecretKey") 13 | if secretKey != "" { 14 | if secretKey == r.Header.Get("secret-key") { 15 | r.Middleware.Next() 16 | } else { 17 | glog.Info("SecretKey 不一致") 18 | r.Response.WriteStatus(http.StatusForbidden) 19 | } 20 | } else { 21 | r.Middleware.Next() 22 | 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/service/middleware/white.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "NovelServer/library/utils" 5 | "github.com/gogf/gf/frame/g" 6 | "github.com/gogf/gf/net/ghttp" 7 | "github.com/gogf/gf/os/glog" 8 | "net/http" 9 | ) 10 | 11 | func White(r *ghttp.Request) { 12 | accessOk := true 13 | //获取客户端IP 14 | cip := r.GetRemoteIp() 15 | ipArr := g.Config().GetArray("system.whitelist") 16 | if len(ipArr) > 0 { 17 | accessOk = utils.IsContains(cip, ipArr) 18 | } 19 | 20 | if accessOk { 21 | r.Middleware.Next() 22 | } else { 23 | glog.Info(cip, "此IP无权访问服务") 24 | r.Response.WriteStatus(http.StatusForbidden) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /router/router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "NovelServer/app/api/book" 5 | "NovelServer/app/service/middleware" 6 | "github.com/gogf/gf/frame/g" 7 | "github.com/gogf/gf/net/ghttp" 8 | ) 9 | 10 | func init() { 11 | s := g.Server() 12 | s.Group("/v1", func(group *ghttp.RouterGroup) { 13 | 14 | group.Middleware(middleware.CORS, middleware.White, middleware.Auth) 15 | 16 | group.GET("/source", book.Source) 17 | group.GET("/searchbook", book.SearchBook) 18 | group.GET("/catalog", book.Catalog) 19 | group.GET("/article", book.Article) 20 | 21 | group.GET("/booksources", book.BookSources) 22 | 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /library/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | import "fmt" 4 | 5 | func ShowLogo(buildVersion, buildTime, commitID string) { 6 | //版本号 7 | fmt.Println(" _______. ___ _______ ______ ______ \n / | / \\ / _____| / __ \\ / __ \\ \n | (----` / ^ \\ | | __ | | | | | | | | \n \\ \\ / /_\\ \\ | | |_ | | | | | | | | | \n.----) | / _____ \\ | |__| | | `--' | | `--' | \n|_______/ /__/ \\__\\ \\______| \\______/ \\______/ \n ") 8 | fmt.Println("Version :", buildVersion) 9 | fmt.Println("BuildTime :", buildTime) 10 | fmt.Println("CommitID :", commitID) 11 | fmt.Println("") 12 | 13 | } 14 | -------------------------------------------------------------------------------- /public/static/js/manifest.5e6c6e707be36332be94.js: -------------------------------------------------------------------------------- 1 | !function(r){function n(e){if(o[e])return o[e].exports;var t=o[e]={i:e,l:!1,exports:{}};return r[e].call(t.exports,t,t.exports,n),t.l=!0,t.exports}var e=window.webpackJsonp;window.webpackJsonp=function(o,u,c){for(var f,i,p,a=0,l=[];a1:错误码)) 10 | Message string `json:"message"` // 提示信息 11 | Data interface{} `json:"data"` // 返回数据(业务接口定义具体数据结构) 12 | } 13 | 14 | // 标准返回结果数据结构封装。 15 | func Json(r *ghttp.Request, code int, message string, data ...interface{}) { 16 | responseData := interface{}(nil) 17 | if len(data) > 0 { 18 | responseData = data[0] 19 | } 20 | r.Response.WriteJson(JsonResponse{ 21 | Code: code, 22 | Message: message, 23 | Data: responseData, 24 | }) 25 | } 26 | 27 | // 返回JSON数据并退出当前HTTP执行函数。 28 | func JsonExit(r *ghttp.Request, err int, msg string, data ...interface{}) { 29 | Json(r, err, msg, data...) 30 | r.Exit() 31 | } 32 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM loads/alpine:3.8 2 | 3 | LABEL maintainer="john@goframe.org" 4 | 5 | ############################################################################### 6 | # INSTALLATION 7 | ############################################################################### 8 | 9 | # 设置固定的项目路径 10 | ENV WORKDIR /var/www/NovelServer 11 | 12 | # 添加应用可执行文件,并设置执行权限 13 | ADD ./bin/linux_amd64/main $WORKDIR/main 14 | RUN chmod +x $WORKDIR/main 15 | 16 | # 添加I18N多语言文件、静态文件、配置文件、模板文件 17 | ADD i18n $WORKDIR/i18n 18 | ADD public $WORKDIR/public 19 | ADD config $WORKDIR/config 20 | ADD template $WORKDIR/template 21 | 22 | ############################################################################### 23 | # START 24 | ############################################################################### 25 | WORKDIR $WORKDIR 26 | CMD ./main 27 | -------------------------------------------------------------------------------- /config/config.toml: -------------------------------------------------------------------------------- 1 | # HTTP Server 2 | [server] 3 | Address = ":8199" 4 | ServerRoot = "public" 5 | ServerAgent = "NovelServer" 6 | DumpRouterMap = false #是否打印路由信息 7 | 8 | IndexFiles = ["index.html","index.htm"] # 自动首页静态文件检索。默认为["index.html", "index.htm"] 9 | 10 | [logger] 11 | path = "./log" 12 | level = "ALL" 13 | stdout = false 14 | RotateExpire = "1d" 15 | RotateBackupLimit = 1 16 | RotateBackupExpire = "7d" 17 | 18 | [system] 19 | #小说源配置文件存放目录 20 | sourceConfigPath = "./config/source" 21 | #小说源配置文件的名称,如果为空就是全部,空:[] ,赋值例值["xxxx.json","xxxx.json"] 22 | sourceFiles = ["com17k.json","biqiuge.json","ttkan.json"] 23 | 24 | #可访问IP白名单,如果为空就是允许全部,空:[] ,赋值例值["xxx.xxx.xxx.xxx","xxx.xxx.xxx.xxx"] 25 | whitelist = [] 26 | #数据缓存时间,单位为分钟。缓存时间参数 = 0表示不过期, 值< 0表示立即过期, 值> 0表示超时过期。 27 | DataCacheTime = 1 28 | 29 | #api访问密钥,为空不启用密钥检查功能 30 | SecretKey = "" -------------------------------------------------------------------------------- /app/service/Book.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "NovelServer/app/model" 5 | "github.com/gogf/gf/os/gcache" 6 | ) 7 | 8 | //cacheBookInfo 在缓存中保持一份完整的小说图书信息 9 | func (bs *BookService) cacheBookInfo(bKey string, book *model.Book) { 10 | 11 | cacheData, _ := gcache.Get(bKey) 12 | if cacheData == nil { 13 | gcache.Set(bKey, book, 0) 14 | bs.BookList[bKey] = book 15 | 16 | } else { 17 | bookInfo := (cacheData).(*model.Book) 18 | if book.Img != "" { 19 | bookInfo.Img = book.Img 20 | } 21 | if book.LastUrl != "" { 22 | bookInfo.LastUrl = book.LastUrl 23 | } 24 | if book.LastTitle != "" { 25 | bookInfo.LastTitle = book.LastTitle 26 | } 27 | if book.Description != "" { 28 | bookInfo.Description = book.Description 29 | } 30 | gcache.Update(bKey, bookInfo) 31 | bs.BookList[bKey] = bookInfo 32 | 33 | } 34 | 35 | } 36 | 37 | func (bs *BookService) BookInfo(bKey string) *model.Book { 38 | return bs.BookList[bKey] 39 | } 40 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 沙果看书 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 xinjy@qq.com https://github.com/xinjiayu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/model/book.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | //Book 图书模型 4 | type Book struct { 5 | BookId string `xorm:"VARCHAR(100)"` //书的标识ID:书名|作者 进行base64进行编码 6 | BookName string `xorm:"VARCHAR(100)"` //书的名称 7 | SourcesCode string `xorm:"VARCHAR(255)"` //源标识码 多个采用逗号分隔 8 | Author string `xorm:"VARCHAR(50)"` //作者 9 | ClassCode string `xorm:"VARCHAR(50)"` //分类 10 | Url string `xorm:"VARCHAR(255)"` //书的可用来源 11 | Status string `xorm:"CHAR(1)"` //书的状态0,不可用;1,连接;2,完结 12 | Tag string `xorm:"VARCHAR(255)"` //书的标签 13 | Description string `xorm:"VARCHAR(255)"` //书的介绍 14 | Img string `xorm:"VARCHAR(255)"` //书的封面 15 | UpdateTime int `xorm:"INT(11)"` //更新时间 16 | LastTitle string `xorm:"VARCHAR(255)"` //最后一章的标题 17 | LastUrl string `xorm:"VARCHAR(255)"` //最后一章的地址 18 | 19 | } 20 | 21 | //Catalog 书的目录 22 | type BookCatalog struct { 23 | SourcesCode string `xorm:"VARCHAR(50)"` //小说源标识码 24 | Url string `xorm:"VARCHAR(200)"` //章节url 25 | Chapter int `xorm:"INT(11)"` //章节编号 26 | Title string `xorm:"VARCHAR(255)"` //文章标题 27 | } 28 | 29 | //Article struct 30 | type BookArticle struct { 31 | Url string `xorm:"VARCHAR(200)"` //文章标题 32 | Chapter int64 `xorm:"BIGINT(20)"` //文章的ID 33 | Title string `xorm:"VARCHAR(255)"` //文章标题 34 | Doc string `xorm:"TEXT"` //文章内容 35 | } 36 | -------------------------------------------------------------------------------- /app/service/Article.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "NovelServer/app/model" 5 | "NovelServer/library/utils" 6 | "encoding/base64" 7 | "github.com/PuerkitoBio/goquery" 8 | "github.com/gogf/gf/os/glog" 9 | ) 10 | 11 | func (bs *BookService) BookArticle(sourceCode, bookArticleURL string) model.BookArticle { 12 | 13 | //传统的URL是经过编码的需要解码 14 | tmpURL, _ := base64.URLEncoding.DecodeString(bookArticleURL) 15 | bookArticleURL = string(tmpURL) 16 | 17 | config := new(model.SourceConfig) 18 | config = bs.SourceConfigInfo[sourceCode] 19 | glog.Info(bookArticleURL) 20 | doc := getHtmlDoc(bookArticleURL) 21 | 22 | var article model.BookArticle 23 | 24 | doc.Find(config.Article.DataRange).Each(func(i int, s *goquery.Selection) { 25 | if config.Catalog.Title.Type == "text" { 26 | article.Title = s.Find(config.Article.Title.Rule).Text() 27 | } else { 28 | article.Title, _ = s.Find(config.Article.Title.Rule).Attr(config.Article.Title.Type) 29 | } 30 | 31 | if config.Catalog.Title.Type == "text" { 32 | article.Doc = s.Find(config.Article.Doc.Rule).Text() 33 | } else { 34 | article.Doc, _ = s.Find(config.Article.Doc.Rule).Attr(config.Article.Doc.Type) 35 | } 36 | 37 | //进行正则过滤处理 38 | article.Title = utils.NormFormat(article.Title, config.Article.Title.Filter) 39 | article.Doc = utils.NormFormat(article.Doc, config.Article.Doc.Filter) 40 | }) 41 | 42 | return article 43 | } 44 | -------------------------------------------------------------------------------- /app/api/book/book.go: -------------------------------------------------------------------------------- 1 | package book 2 | 3 | import ( 4 | "NovelServer/app/service" 5 | "NovelServer/library/response" 6 | "github.com/gogf/gf/net/ghttp" 7 | ) 8 | 9 | func Source(r *ghttp.Request) { 10 | bs := service.NewSetupData() 11 | response.JsonExit(r, 0, "当前支持的源列表", bs.SourceList) 12 | 13 | } 14 | 15 | func SearchBook(r *ghttp.Request) { 16 | 17 | bookName := r.GetString("bookName") 18 | sourceCode := r.GetString("sourceCode") 19 | 20 | bs := service.NewSetupData() 21 | data := bs.SearchBook(sourceCode, bookName) 22 | response.JsonExit(r, 0, "小说搜索结果", data) 23 | 24 | } 25 | 26 | func Catalog(r *ghttp.Request) { 27 | bookUrl := r.GetString("bookUrl") 28 | sourceCode := r.GetString("sourceCode") 29 | 30 | bs := service.NewSetupData() 31 | data := bs.BookCatalog(sourceCode, bookUrl) 32 | response.JsonExit(r, 0, "小说章节", data) 33 | } 34 | 35 | func Article(r *ghttp.Request) { 36 | bookArticleUrl := r.GetString("bookArticleUrl") 37 | sourceCode := r.GetString("sourceCode") 38 | 39 | bs := service.NewSetupData() 40 | data := bs.BookArticle(sourceCode, bookArticleUrl) 41 | response.JsonExit(r, 0, "小说文章内容", data) 42 | } 43 | 44 | func BookSources(r *ghttp.Request) { 45 | bookName := r.GetString("bookName") 46 | author := r.GetString("author") 47 | 48 | bs := service.NewSetupData() 49 | data := bs.SearchBookByMultiSource(bookName, author) 50 | response.JsonExit(r, 0, "小说搜索结果", data) 51 | } 52 | -------------------------------------------------------------------------------- /library/utils/stringex.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bytes" 5 | "github.com/gogf/gf/os/glog" 6 | "github.com/gogf/gf/text/gregex" 7 | "reflect" 8 | "regexp" 9 | "text/template" 10 | ) 11 | 12 | //通过正则表达式进行数据过滤,过虑掉指定的内容 13 | func NormFormat(str, filter string) string { 14 | if filter != "" { 15 | tmpTxt, err := gregex.ReplaceString(filter, "", str) 16 | if err != nil { 17 | glog.Error(err) 18 | } 19 | return tmpTxt 20 | } 21 | return str 22 | } 23 | 24 | //FindAndReplace 查找并替换 25 | func FindAndReplace(docString, findString, replaceString string) string { 26 | reg := regexp.MustCompile(findString) 27 | return reg.ReplaceAllString(docString, replaceString) 28 | } 29 | 30 | // IsContains 查找值val是否在数组array中存在 31 | func IsContains(val interface{}, array interface{}) bool { 32 | if array == nil { 33 | return false 34 | } 35 | switch reflect.TypeOf(array).Kind() { 36 | case reflect.Slice, reflect.Array: 37 | s := reflect.ValueOf(array) 38 | for i := 0; i < s.Len(); i++ { 39 | if reflect.DeepEqual(val, s.Index(i).Interface()) == true { 40 | return true 41 | } 42 | } 43 | } 44 | return false 45 | } 46 | 47 | //通过文本模板进行变量替换 48 | func StringLiteralTemplate(str string, param interface{}) string { 49 | t, err := template.New("test").Parse(str) 50 | if err != nil { 51 | glog.Fatal("Parse string literal template error:", err) 52 | } 53 | buf := new(bytes.Buffer) //读写方法的可变大小的字节缓冲 54 | err = t.Execute(buf, param) 55 | if err != nil { 56 | glog.Fatal("Execute string literal template error:", err) 57 | return "" 58 | } 59 | return buf.String() 60 | } 61 | -------------------------------------------------------------------------------- /app/service/BooKService.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "NovelServer/app/model" 5 | "github.com/PuerkitoBio/goquery" 6 | "github.com/gogf/gf/os/glog" 7 | "net/http" 8 | ) 9 | 10 | type BookService struct { 11 | formURL string 12 | SourceConfigInfo map[string]*model.SourceConfig 13 | SourceList []*model.Source 14 | BookList map[string]*model.Book 15 | } 16 | 17 | func NewSetupData() *BookService { 18 | 19 | bookService := new(BookService) 20 | 21 | bookService.SourceConfigInfo, bookService.SourceList = initSourceData() 22 | bookService.BookList = make(map[string]*model.Book) 23 | 24 | return bookService 25 | } 26 | 27 | //getHtmlDoc 获取远程html内容 28 | func getHtmlDoc(url string) *goquery.Document { 29 | request, err := http.NewRequest("GET", url, nil) 30 | if err != nil { 31 | glog.Error(err) 32 | return nil 33 | } 34 | 35 | request.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8") 36 | request.Header.Add("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3") 37 | request.Header.Add("Connection", "keep-alive") 38 | request.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36") 39 | 40 | client := http.Client{} 41 | response, err := client.Do(request) 42 | if err != nil { 43 | glog.Error(err) 44 | return nil 45 | } 46 | defer response.Body.Close() 47 | 48 | doc, err := goquery.NewDocumentFromReader(response.Body) 49 | if err != nil { 50 | glog.Error(err) 51 | } 52 | 53 | return doc 54 | } 55 | -------------------------------------------------------------------------------- /config/source/biqiuge.json: -------------------------------------------------------------------------------- 1 | { 2 | "SourcesCode": "biqiuge", 3 | "SourcesName": "笔趣阁", 4 | "Weburl": "", 5 | "Searchurl": "http://www.biquge.info/modules/article/search.php?searchkey=", 6 | "Charset": "GBK", 7 | "Search": { 8 | "Range": "table[class='grid'] tbody tr", 9 | "Repair": { 10 | "Field": "BookUrl", 11 | "Position": "l", 12 | "value": "http://www.biquge.info" 13 | }, 14 | "Replace": { 15 | "Field": "", 16 | "Old": "", 17 | "New": "" 18 | }, 19 | "BookName": { 20 | "Type": "text", 21 | "Rule": "td[class='odd'] a", 22 | "Filter": "" 23 | }, 24 | "BookUrl": { 25 | "Type": "href", 26 | "Rule": "td[class='odd'] a", 27 | "Filter": "" 28 | }, 29 | "BookImg": { 30 | "Type": "", 31 | "Rule": "", 32 | "Filter": "" 33 | }, 34 | "BookAuthor": { 35 | "Type": "text", 36 | "Rule": "td[class='odd']:nth-child(3)", 37 | "Filter": "" 38 | }, 39 | "BookDescription": { 40 | "Type": "text", 41 | "Rule": "", 42 | "Filter": "" 43 | } 44 | }, 45 | "Catalog": { 46 | "Range": "div[class='box_con'] div dl dd", 47 | "Repair": { 48 | "Field": "Url", 49 | "Position": "r", 50 | "value": "FormURL" 51 | }, 52 | "Title": { 53 | "Type": "text", 54 | "Rule": "a", 55 | "Filter": "" 56 | }, 57 | "Url": { 58 | "Type": "href", 59 | "Rule": "a", 60 | "Filter": "" 61 | } 62 | }, 63 | "Article": { 64 | "Range": "div[class='box_con']", 65 | "Title": { 66 | "Type": "text", 67 | "Rule": "div[class='bookname'] h1", 68 | "Filter": "" 69 | }, 70 | "Doc": { 71 | "Type": "text", 72 | "Rule": "div[id='content']", 73 | "Filter": "" 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /config/source/ttkan.json: -------------------------------------------------------------------------------- 1 | { 2 | "SourcesCode": "ttkan", 3 | "SourcesName": "天天看小说", 4 | "Weburl": "https://www.ttkan.co", 5 | "Charset": "UTF8", 6 | "Search": { 7 | "SearchUrl": "https://www.ttkan.co/novel/search?q=", 8 | "Range": "div[class='frame_body'] div div", 9 | "Replace": { 10 | "Field": "BookUrl", 11 | "Old": "novel/chapters/", 12 | "New": "api/nq/amp_novel_chapters?language=cn&limit=100000&novel_id=" 13 | }, 14 | "BookName": { 15 | "Type": "text", 16 | "Rule": "ul li a h3", 17 | "Filter": "" 18 | }, 19 | "BookUrl": { 20 | "Type": "href", 21 | "Rule": "ul li a", 22 | "Filter": "" 23 | }, 24 | "BookImg": { 25 | "Type": "src", 26 | "Rule": "a amp-img", 27 | "Filter": "" 28 | }, 29 | "BookAuthor": { 30 | "Type": "text", 31 | "Rule": "ul li:nth-child(2)", 32 | "Filter": "[作者:]" 33 | }, 34 | "BookDescription": { 35 | "Type": "text", 36 | "Rule": "ul li:nth-child(3)", 37 | "Filter": "\\s" 38 | } 39 | }, 40 | "Catalog": { 41 | "DataType": "json", 42 | "CatalogUrl": "https://www.bg3.co/novel/pagea/sancunrenjian-ergen_{{ .CatalogUrlParam }}.html", 43 | "CatalogUrlParam": "chapter_id", 44 | "Range": "body", 45 | "NextFiltered": "pre", 46 | "Find": "{", 47 | "Title": { 48 | "Type": "text", 49 | "Rule": "chapter_name", 50 | "Filter": "\\t|\\n" 51 | }, 52 | "Url": { 53 | "Type": "", 54 | "Rule": "", 55 | "Filter": "" 56 | } 57 | }, 58 | "Article": { 59 | "Range": "div[class='frame_body']", 60 | "Title": { 61 | "Type": "text", 62 | "Rule": "div h1", 63 | "Filter": "" 64 | }, 65 | "Doc": { 66 | "Type": "text", 67 | "Rule": "div[class='content']", 68 | "Filter": "\\s" 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /config/source/com17k.json: -------------------------------------------------------------------------------- 1 | { 2 | "SourcesCode": "com17k", 3 | "SourcesName": "17k小说网", 4 | "Weburl": "https://www.17k.com", 5 | "Searchurl": "http://search.17k.com/search.xhtml?c.st=0&c.q=", 6 | "Charset": "UTF8", 7 | "Search": { 8 | "Range": "div[class='search-list'] div[class='textlist']", 9 | "Replace": { 10 | "Field": "BookUrl", 11 | "Old": "book", 12 | "New": "list" 13 | }, 14 | "BookName": { 15 | "Type": "alt", 16 | "Rule": "div[class='textleft'] a img", 17 | "Filter": "" 18 | }, 19 | "BookUrl": { 20 | "Type": "href", 21 | "Rule": "div[class='textleft'] a", 22 | "Filter": "//www.17k.com" 23 | }, 24 | "BookImg": { 25 | "Type": "src", 26 | "Rule": "div[class='textleft'] a img", 27 | "Filter": "" 28 | }, 29 | "BookAuthor": { 30 | "Type": "text", 31 | "Rule": "div[class='textmiddle'] dl dd ul li span[class='ls']", 32 | "Filter": "[作者:]|[\\s]" 33 | }, 34 | "BookDescription": { 35 | "Type": "text", 36 | "Rule": "div[class='textmiddle'] dl dd ul li p", 37 | "Filter": "\\s" 38 | } 39 | }, 40 | "Catalog": { 41 | "Range": "div[class='Main List'] dl", 42 | "NextFiltered": "dl", 43 | "Find": "dd a", 44 | "Title": { 45 | "Type": "text", 46 | "Rule": "span[class='ellipsis ']", 47 | "Filter": "\\t|\\n" 48 | }, 49 | "Url": { 50 | "Type": "href", 51 | "Rule": "", 52 | "Filter": "" 53 | } 54 | }, 55 | "Article": { 56 | "Range": "div[class='readAreaBox content']", 57 | "Title": { 58 | "Type": "text", 59 | "Rule": "h1", 60 | "Filter": "" 61 | }, 62 | "Doc": { 63 | "Type": "text", 64 | "Rule": "div[class='p']", 65 | "Filter": "\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t" 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /app/service/Sources.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "NovelServer/app/model" 5 | "github.com/gogf/gf/encoding/gjson" 6 | "github.com/gogf/gf/frame/g" 7 | "github.com/gogf/gf/os/gfile" 8 | "github.com/gogf/gf/os/glog" 9 | "github.com/gogf/gf/util/gconv" 10 | ) 11 | 12 | //initSourceData 初始化小说源配置文件 13 | func initSourceData() (sourceConfigInfo map[string]*model.SourceConfig, sourceList []*model.Source) { 14 | //定义源配置信息文件列表 15 | var sourceFileList []string 16 | sourceConfigInfo = make(map[string]*model.SourceConfig) 17 | 18 | sourcePath := g.Cfg().GetString("system.sourceConfigPath") 19 | sourceFiles := g.Config().GetArray("system.sourceFiles") 20 | sourceFileList = gconv.Strings(sourceFiles) 21 | 22 | //如果配置文件未配置,将使用目录内全部文件 23 | if len(sourceFiles) == 0 { 24 | //获取到源文件列表 25 | sourceConfFileList, _ := getDataSource(sourcePath) 26 | sourceFileList = gconv.Strings(sourceConfFileList) 27 | } 28 | 29 | for i := 0; i < len(sourceFileList); i++ { 30 | configJson := getSourceConfig(sourcePath, sourceFileList[i]) 31 | 32 | configInfo := new(model.SourceConfig) 33 | search := model.Search{} 34 | configInfo.Search = search 35 | 36 | if err := configJson.ToStruct(configInfo); err != nil { 37 | panic(err) 38 | } 39 | 40 | source := new(model.Source) 41 | source.SourcesCode = configInfo.SourcesCode 42 | source.SourcesName = configInfo.SourcesName 43 | sourceList = append(sourceList, source) 44 | 45 | sourceConfigInfo[configInfo.SourcesCode] = configInfo 46 | 47 | } 48 | 49 | return sourceConfigInfo, sourceList 50 | } 51 | 52 | // getDataSource 获取小说源的文件列表 53 | func getDataSource(sourcePath string) ([]string, error) { 54 | files, err := gfile.DirNames(sourcePath) 55 | if err != nil { 56 | return nil, err 57 | } 58 | return files, nil 59 | } 60 | 61 | // getSourceConfig 获取小说源的配置文件 62 | func getSourceConfig(sourcePath, configName string) *gjson.Json { 63 | sourceFile := sourcePath + "/" + configName 64 | sc, err := gjson.Load(sourceFile) 65 | if err != nil { 66 | glog.Error("加载配置文件出错!", err) 67 | return nil 68 | } 69 | return sc 70 | } 71 | -------------------------------------------------------------------------------- /app/model/source.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Source struct { 4 | SourcesCode string `xorm:"VARCHAR(100)"` //源的编码 5 | SourcesName string `xorm:"VARCHAR(100)"` //源的名称 6 | } 7 | 8 | //SourceConfig 小说源配置 9 | type SourceConfig struct { 10 | SourcesCode string `json:"SourcesCode"` 11 | SourcesName string `json:"SourcesName"` 12 | Weburl string `json:"Weburl"` 13 | Charset string `json:"Charset"` 14 | Search `json:"Search"` 15 | Catalog `json:"Catalog"` 16 | Article `json:"Article"` 17 | } 18 | 19 | //Search 小说搜索配置 20 | type Search struct { 21 | SearchUrl string `json:"SearchUrl"` 22 | DataRange string `json:"Range"` 23 | Replace `json:"Replace"` 24 | Repair `json:"Repair"` 25 | BookName Attribute `json:"BookName"` 26 | BookUrl Attribute `json:"BookUrl"` 27 | BookImg Attribute `json:"BookImg"` 28 | BookAuthor Attribute `json:"BookAuthor"` 29 | BookDescription Attribute `json:"BookDescription"` 30 | } 31 | 32 | //Catalog 小说目录配置 33 | type Catalog struct { 34 | DataType string `json:"DataType"` 35 | CatalogUrl string `json:"CatalogUrl"` 36 | CatalogUrlParam string `json:"CatalogUrlParam"` 37 | DataRange string `json:"Range"` 38 | Repair `json:"Repair"` 39 | NextFiltered string `json:"NextFiltered"` 40 | Find string `json:"Find"` 41 | Title Attribute `json:"Title"` 42 | Url Attribute `json:"Url"` 43 | } 44 | 45 | //Article 小说章节内容配置 46 | type Article struct { 47 | DataRange string `json:"Range"` 48 | Title Attribute `json:"Title"` 49 | Doc Attribute `json:"Doc"` 50 | } 51 | 52 | //Attribute 解析规则 53 | type Attribute struct { 54 | Type string `json:"Type"` 55 | Rule string `json:"rule"` 56 | Filter string `json:"filter"` 57 | } 58 | 59 | //Replace 指定字段替换配置 60 | type Replace struct { 61 | Field string `json:"Field"` 62 | Old string `json:"Old"` 63 | New string `json:"New"` 64 | } 65 | 66 | //Repair 指定字段左或是右进行补充内容 67 | type Repair struct { 68 | Field string `json:"Field"` 69 | Position string `json:"Position"` 70 | Value string `json:"Value"` 71 | } 72 | -------------------------------------------------------------------------------- /curl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | WORKSPACE=$(cd $(dirname $0)/; pwd) 4 | cd $WORKSPACE 5 | 6 | mkdir -p var 7 | 8 | app=NovelServer 9 | pidfile=var/app.pid 10 | logfile=var/app.log 11 | 12 | function check_pid() { 13 | if [ -f $pidfile ];then 14 | pid=`cat $pidfile` 15 | if [ -n $pid ]; then 16 | running=`ps -p $pid|grep -v "PID TTY" |wc -l` 17 | return $running 18 | fi 19 | fi 20 | return 0 21 | } 22 | 23 | 24 | function start(){ 25 | check_pid 26 | running=$? 27 | if [ $running -gt 0 ]; then 28 | echo -n "$app now is running already,pid=" 29 | cat $pidfile 30 | return 31 | fi 32 | 33 | nohup ./$app {option} &> $logfile & 34 | sleep 1 35 | running=`ps -p $! | grep -v "PID TTY" | wc -l` 36 | if [ $running -gt 0 ];then 37 | echo $! > $pidfile 38 | echo "$app started..., pid=$!" 39 | else 40 | echo "$app failed to start" 41 | return 1 42 | fi 43 | 44 | } 45 | 46 | function stop() { 47 | check_pid 48 | running=$? 49 | if [ $running -gt 0 ];then 50 | pid=`cat $pidfile` 51 | kill $pid 52 | rm -f $pidfile 53 | echo "$app stoped" 54 | else 55 | echo "$app already stoped" 56 | fi 57 | } 58 | 59 | function restart() { 60 | stop 61 | sleep 1 62 | start 63 | } 64 | 65 | function status() { 66 | check_pid 67 | running=$? 68 | if [ $running -gt 0 ];then 69 | echo "started" 70 | else 71 | echo "stoped" 72 | fi 73 | } 74 | 75 | function tailf() { 76 | tail -f var/* 77 | } 78 | 79 | function help() { 80 | echo "$0 pid|start|stop|restart|status|tail" 81 | } 82 | 83 | function pid() { 84 | cat $pidfile 85 | } 86 | 87 | if [ "$1" == "" ]; then 88 | help 89 | elif [ "$1" == "stop" ];then 90 | stop 91 | elif [ "$1" == "start" ];then 92 | start 93 | elif [ "$1" == "restart" ];then 94 | restart 95 | elif [ "$1" == "status" ];then 96 | status 97 | elif [ "$1" == "tail" ];then 98 | tailf 99 | elif [ "$1" == "pid" ];then 100 | pid 101 | else 102 | help 103 | fi 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 网页版小说解析服务 2 | 3 | ## 服务程序说明 4 | 5 | #### NovelServer 6 | 7 | 将网页版的小说解析成json格式API输出的模式。 8 | 可以通过配置文件进行小说网站源的配置。 9 | 10 | 11 | [NovelServer API文档说明](https://docs.apipost.cn/view/1e517785a3282a91#3196964) 12 | 13 | ## 声明 14 | 此服务源码仅供学习使用,不可用于商业用途,否则后果自负 15 | 16 | ## 技术栈 17 | 18 | 基础框架:[GoFrame](https://github.com/gogf/gf) 【 [中文文档](https://goframe.org/index) 】 19 | 20 | 网页解析库:[goquery](https://github.com/PuerkitoBio/goquery) 21 | 22 | ## 源码运行 23 | 24 | 在项目目录下通源码直接行 25 | 26 | `go run main.go` 27 | 28 | 通过编译脚本,进行编译二进制文件运行。编译后的文件在bin目录下,把自动将需要的相关文件复制到该目录下。 29 | 30 | `./build.sh` 31 | 32 | 分别有三个参数可选支持不同的操作系统,linux|windows|mac 33 | 34 | **关于curl.sh 运行脚本** 35 | 36 | 在mac或是linux下通过该脚本可以后台运行服务。通过参数进行启动、重启、停止及显示后台实时信息的操作。 37 | 38 | ``` 39 | 应用的启动命令说明: 40 | 41 | ./curl.sh pid|start|stop|restart|status|tail 42 | 43 | ``` 44 | 45 | > start:启动应用 46 | > stop:停止应用 47 | > restart:重新启动应用 48 | > status:查看应用状态 49 | > tail:查看应用运行的动态输出日志信息 50 | 51 | 52 | 53 | ## 部署说明 54 | 55 | ### 一、独立部署 56 | 57 | 服务器推荐使用*nix服务器系列(包括:Linux, MacOS, *BSD),以下使用Linux系统为例,介绍如何部署。 58 | 59 | 将应用服务目录复制到目标位置,里面已经写好了执行的脚本,通过脚本来执行。 60 | 61 | ``` 62 | curl.sh脚本参数: 63 | 64 | start|stop|restart|status|tail 65 | 66 | ``` 67 | ### 二、代理部署 68 | 69 | 推荐使用Nginx作为反向代理的前端接入层,有两种配置方式实现动静态请求的拆分。 70 | 71 | ``` 72 | server { 73 | listen 80; 74 | server_name www.abc.com; 75 | 76 | access_log /var/log/gf-app-access.log; 77 | error_log /var/log/gf-app-error.log; 78 | 79 | location ~ .*\.(gif|jpg|jpeg|png|js|css|eot|ttf|woff|svg|otf)$ { 80 | access_log off; 81 | expires 1d; 82 | root /var/www/gf-app/public; 83 | try_files $uri @backend; 84 | } 85 | 86 | location / { 87 | try_files $uri @backend; 88 | } 89 | 90 | location @backend { 91 | proxy_pass http://127.0.0.1:8199; 92 | proxy_redirect off; 93 | proxy_set_header Host $host; 94 | proxy_set_header X-Real-IP $remote_addr; 95 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 96 | } 97 | } 98 | 99 | ``` 100 | 101 | 其中,8199为NovelServer应用Web服务监听端口。这个端口在config.toml文件的server下Address参数中配置。 102 | 103 | ### 三、supervisor 104 | 105 | `supervisor`是用`Python`开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台`daemon`,并监控进程状态,异常退出时能自动重启。官方网站:http://supervisord.org/ 常见配置如下: 106 | 107 | ```undefined 108 | [program:NovelServer] 109 | user=root 110 | command=/var/www/NovelServer 111 | stdout_logfile=/var/log/NovelServer-stdout.log 112 | stderr_logfile=/var/log/NovelServer-stderr.log 113 | autostart=true 114 | autorestart=true 115 | ``` 116 | 117 | 使用步骤如下: 118 | 119 | 1. 使用`sudo service supervisor start`启动`supervisor`服务; 120 | 2. 创建应用配置文件`/etc/supervisor/conf.d/NovelServer.conf`, 内容如上; 121 | 3. 使用`sudo supervisorctl`进入`supervisor`管理终端; 122 | 4. 使用`reload`重新读取配置文件并重启当前`supoervisor`管理的所有进程; 123 | 5. 也可以使用`update`重新加载配置(默认不重启),随后使用`start AssessServer启动指定的应用程序; 124 | 6. 随后可以使用`status`指令查看当前`supervisor`管理的进程状态; 125 | 126 | ## 应用配置文件 127 | 128 | 在config中进行日志、数据库、服务端口及白名单等设置。配置实时生效。 129 | 130 | ` 131 | 132 | ## 采集模板配置文件说明 133 | 134 | 135 | **Rule字段的定义和用法** 136 | 137 | 通过 css selector的定位进行数据提取。可以下载chrome的扩展程序[SelectorGadget](https://chrome.google.com/webstore/detail/selectorgadget/mhjhnkcfbdhnjickkkdbjoemdmbfginb/related?hl=zh-CN) 进行辅助选取。 138 | 139 | **字段说明:** 140 | 141 | **`Range`:** 内容截取范围 142 | 143 | **`Type`:** 选择的类型,text,src,href,alt 144 | 145 | **`Rule`:** 选择的起点,如:"div[class='bookname'] h1" 146 | 147 | > :nth-child(n) 选择器匹配属于其父元素的第 N 个子元素,不论元素的类型。 148 | > 149 | > n 可以是数字、关键词或公式。 150 | > 151 | 152 | **`Filter`:** 过滤器,采用正规选择。 153 | 154 | > **例:** 155 | > 156 | > 1、删除空行 157 | > 158 | > ``` 159 | > \s 160 | > ``` 161 | > 162 | > 2、删除多余的汉字与空格及空行 163 | > 如: 164 | > ``` 165 | > 作者:\n \n 异乡说书人\n \n 166 | > ``` 167 | > 正则: 168 | > 169 | > ``` 170 | > [作者:]|[\s] 171 | > ``` 172 | 173 | 174 | **`Replace`** 替换配置,指定字段,进行替换 175 | 176 | Field,字段名称;Old,原来的内容;New,新的内容。 177 | ``` 178 | "Replace": { 179 | "Field": "BookUrl", 180 | "Old": "novel/chapters/", 181 | "New": "api/nq/novel_id=" 182 | }, 183 | 184 | ``` 185 | -------------------------------------------------------------------------------- /app/service/SearchBook.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "NovelServer/app/model" 5 | "NovelServer/library/utils" 6 | "encoding/base64" 7 | "github.com/PuerkitoBio/goquery" 8 | "github.com/gogf/gf/os/glog" 9 | "net/url" 10 | ) 11 | 12 | //SearchBook 搜索小说 13 | func (bs *BookService) SearchBook(sourceCode, bookName string) []*model.Book { 14 | 15 | config := new(model.SourceConfig) 16 | config = bs.SourceConfigInfo[sourceCode] 17 | 18 | bookName = url.QueryEscape(bookName) 19 | webUrl := config.SearchUrl + bookName 20 | 21 | doc := getHtmlDoc(webUrl) 22 | glog.Info("SourceCode:", config.SourcesCode, webUrl) 23 | 24 | var bookList []*model.Book 25 | doc.Find(config.Search.DataRange).Each(func(i int, s *goquery.Selection) { 26 | 27 | var book = new(model.Book) 28 | 29 | //d,_:=s.Html() 30 | //glog.Info(d) 31 | 32 | if config.Search.BookName.Type == "text" { 33 | book.BookName = s.Find(config.Search.BookName.Rule).Text() 34 | } else { 35 | book.BookName, _ = s.Find(config.Search.BookName.Rule).Attr(config.Search.BookName.Type) 36 | } 37 | 38 | if config.Search.BookUrl.Type == "text" { 39 | book.Url = s.Find(config.Search.BookUrl.Rule).Text() 40 | } else { 41 | book.Url, _ = s.Find(config.Search.BookUrl.Rule).Attr(config.Search.BookUrl.Type) 42 | } 43 | 44 | if config.Search.BookImg.Type == "text" { 45 | book.Img = s.Find(config.Search.BookImg.Rule).Text() 46 | } else { 47 | book.Img, _ = s.Find(config.Search.BookImg.Rule).Attr(config.Search.BookImg.Type) 48 | } 49 | 50 | if config.Search.BookAuthor.Type == "text" { 51 | book.Author = s.Find(config.Search.BookAuthor.Rule).Text() 52 | } else { 53 | book.Author, _ = s.Find(config.Search.BookAuthor.Rule).Attr(config.Search.BookAuthor.Type) 54 | } 55 | 56 | if config.Search.BookDescription.Type == "text" { 57 | book.Description = s.Find(config.Search.BookDescription.Rule).Text() 58 | } else { 59 | book.Description, _ = s.Find(config.Search.BookDescription.Rule).Attr(config.Search.BookDescription.Type) 60 | } 61 | 62 | //进行正则过滤处理 63 | book.BookName = utils.NormFormat(book.BookName, config.Search.BookName.Filter) 64 | book.Url = utils.NormFormat(book.Url, config.Search.BookUrl.Filter) 65 | book.Img = utils.NormFormat(book.Img, config.Search.BookImg.Filter) 66 | book.Author = utils.NormFormat(book.Author, config.Search.BookAuthor.Filter) 67 | book.Description = utils.NormFormat(book.Description, config.Search.BookDescription.Filter) 68 | 69 | if config.Search.Replace.Field != "" { 70 | switch config.Search.Replace.Field { 71 | case "BookUrl": 72 | book.Url = utils.FindAndReplace(book.Url, config.Search.Replace.Old, config.Search.Replace.New) 73 | } 74 | 75 | } 76 | 77 | if config.Weburl != "" { 78 | book.Url = config.Weburl + book.Url 79 | } 80 | 81 | if config.Search.Repair.Field != "" { 82 | switch config.Search.Repair.Field { 83 | case "BookUrl": 84 | if book.Url != "" { 85 | if config.Search.Repair.Position == "r" { 86 | book.Url = book.Url + config.Search.Repair.Value 87 | } 88 | if config.Search.Repair.Position == "l" { 89 | book.Url = config.Search.Repair.Value + book.Url 90 | } 91 | } 92 | 93 | } 94 | } 95 | 96 | book.Url = base64.URLEncoding.EncodeToString([]byte(book.Url)) 97 | 98 | //获取图书唯一标识码,base64编码 99 | book.SourcesCode = config.SourcesCode 100 | bookId := book.BookName + "|" + book.Author 101 | book.BookId = base64.URLEncoding.EncodeToString([]byte(bookId)) 102 | 103 | if book.BookName != "" && book.Url != "" { 104 | bs.cacheBookInfo(book.Url, book) 105 | bookInfo := bs.BookInfo(book.Url) //从缓存中取修正后的小说信息 106 | bookList = append(bookList, bookInfo) 107 | } 108 | 109 | }) 110 | 111 | return bookList 112 | } 113 | 114 | //SearchBookByMultiSource 按名子搜索多个源 115 | func (bs *BookService) SearchBookByMultiSource(bookName, author string) map[string]*model.Book { 116 | bookId := bookName + "|" + author 117 | bookId = base64.URLEncoding.EncodeToString([]byte(bookId)) 118 | 119 | var bookList = make(map[string]*model.Book) 120 | 121 | for _, config := range bs.SourceList { 122 | glog.Info(config.SourcesCode) 123 | 124 | dataList := bs.SearchBook(config.SourcesCode, bookName) 125 | for _, book := range dataList { 126 | if book.BookId == bookId { 127 | bookList[config.SourcesCode] = bs.BookList[book.Url] 128 | } 129 | } 130 | 131 | } 132 | 133 | return bookList 134 | } 135 | -------------------------------------------------------------------------------- /app/service/Catalog.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "NovelServer/app/model" 5 | "NovelServer/library/utils" 6 | "encoding/base64" 7 | "github.com/PuerkitoBio/goquery" 8 | "github.com/gogf/gf/encoding/gjson" 9 | "github.com/gogf/gf/frame/g" 10 | "github.com/gogf/gf/os/glog" 11 | "github.com/gogf/gf/util/gconv" 12 | ) 13 | 14 | func (bs *BookService) BookCatalog(sourceCode, bookURL string) []model.BookCatalog { 15 | 16 | //章节序号 17 | ci := 0 18 | 19 | //传统的URL是经过编码的需要解码 20 | tmpURL, _ := base64.URLEncoding.DecodeString(bookURL) 21 | bookURL = string(tmpURL) 22 | var catalogListData []model.BookCatalog 23 | 24 | config := new(model.SourceConfig) 25 | config = bs.SourceConfigInfo[sourceCode] 26 | glog.Info(bookURL) 27 | 28 | //解析JSON数据 29 | glog.Info("处理数据类型:", config.Catalog.DataType) 30 | if config.Catalog.DataType == "json" { 31 | 32 | jsonData := getRemoteJsonData(bookURL) 33 | catalogList := jsonData.GetArray("items") 34 | var bookCatalog model.BookCatalog 35 | for _, data := range catalogList { 36 | catalog := gconv.Map(data) 37 | bookCatalog.SourcesCode = config.SourcesCode 38 | //通过文字模板的处理,进行参数替换配置 39 | paramDataMap := make(map[string]interface{}) 40 | paramDataMap["CatalogUrlParam"] = catalog[config.Catalog.CatalogUrlParam] 41 | bookCatalog.Url = utils.StringLiteralTemplate(config.Catalog.CatalogUrl, paramDataMap) 42 | bookCatalog.Chapter = gconv.Int(catalog["chapter_id"]) 43 | bookCatalog.Title = gconv.String(catalog[config.Catalog.Title.Rule]) 44 | 45 | bookCatalog.Url = base64.URLEncoding.EncodeToString([]byte(bookCatalog.Url)) 46 | 47 | //进行正则过滤处理 48 | bookCatalog.Title = utils.NormFormat(bookCatalog.Title, config.Catalog.Title.Filter) 49 | bookCatalog.Url = utils.NormFormat(bookCatalog.Url, config.Catalog.Url.Filter) 50 | 51 | if bookCatalog.Title != "" { 52 | ci++ 53 | bookCatalog.Chapter = ci 54 | catalogListData = append(catalogListData, bookCatalog) 55 | } 56 | 57 | } 58 | go bs.updataCache(bookURL, bookCatalog) 59 | 60 | return catalogListData 61 | } 62 | 63 | //解析HTML页面数据 64 | doc := getHtmlDoc(bookURL) 65 | bs.formURL = bookURL 66 | 67 | var bookCatalog model.BookCatalog 68 | if config.Catalog.NextFiltered != "" { 69 | 70 | doc.Find(config.Catalog.DataRange).NextFiltered(config.Catalog.NextFiltered).Find(config.Catalog.Find).Each(func(i int, s *goquery.Selection) { 71 | bookCatalog = bs.analysis(config, s) 72 | if bookCatalog.Title != "" { 73 | ci++ 74 | bookCatalog.Chapter = ci 75 | catalogListData = append(catalogListData, bookCatalog) 76 | 77 | } 78 | }) 79 | 80 | } else { 81 | doc.Find(config.Catalog.DataRange).Each(func(i int, s *goquery.Selection) { 82 | 83 | bookCatalog = bs.analysis(config, s) 84 | if bookCatalog.Title != "" { 85 | ci++ 86 | bookCatalog.Chapter = ci 87 | catalogListData = append(catalogListData, bookCatalog) 88 | 89 | } 90 | }) 91 | 92 | } 93 | go bs.updataCache(bookURL, bookCatalog) 94 | 95 | return catalogListData 96 | } 97 | 98 | func (bs *BookService) analysis(config *model.SourceConfig, s *goquery.Selection) (bookCatalog model.BookCatalog) { 99 | bookCatalog.SourcesCode = config.SourcesCode 100 | if config.Catalog.Title.Type == "text" { 101 | bookCatalog.Title = s.Find(config.Catalog.Title.Rule).Text() 102 | } else { 103 | bookCatalog.Title, _ = s.Find(config.Catalog.Title.Rule).Attr(config.Catalog.Title.Type) 104 | } 105 | 106 | if config.Catalog.Url.Type == "text" { 107 | bookCatalog.Url = s.Find(config.Catalog.Url.Rule).Text() 108 | } else { 109 | if config.Catalog.Url.Rule == "" { 110 | bookCatalog.Url, _ = s.Attr(config.Catalog.Url.Type) 111 | 112 | } else { 113 | bookCatalog.Url, _ = s.Find(config.Catalog.Url.Rule).Attr(config.Catalog.Url.Type) 114 | 115 | } 116 | } 117 | 118 | if config.Catalog.Repair.Field != "" { 119 | switch config.Catalog.Repair.Field { 120 | case "Url": 121 | 122 | if config.Catalog.Repair.Value == "FormURL" { 123 | bookCatalog.Url = bs.formURL + bookCatalog.Url 124 | 125 | } else { 126 | bookCatalog.Url = config.Catalog.Repair.Value + bookCatalog.Url 127 | 128 | } 129 | } 130 | } 131 | 132 | if config.Weburl != "" { 133 | bookCatalog.Url = config.Weburl + bookCatalog.Url 134 | } 135 | 136 | bookCatalog.Url = base64.URLEncoding.EncodeToString([]byte(bookCatalog.Url)) 137 | 138 | //进行正则过滤处理 139 | bookCatalog.Title = utils.NormFormat(bookCatalog.Title, config.Catalog.Title.Filter) 140 | bookCatalog.Url = utils.NormFormat(bookCatalog.Url, config.Catalog.Url.Filter) 141 | 142 | return 143 | } 144 | func getRemoteJsonData(webUrl string) *gjson.Json { 145 | c := g.Client() 146 | c.SetHeader("Span-Id", "0.0.1") 147 | c.SetHeader("Trace-Id", "NBC56410N97LJ016FQA") 148 | if r, e := c.Get(webUrl); e != nil { 149 | glog.Error(e) 150 | return nil 151 | } else { 152 | defer r.Close() 153 | jsonData := gjson.New(r.ReadAllString()) 154 | return jsonData 155 | } 156 | } 157 | 158 | func (bs *BookService) updataCache(bookURL string, bookCatalog model.BookCatalog) { 159 | book := new(model.Book) 160 | book.SourcesCode = bookCatalog.SourcesCode 161 | book.Url = base64.URLEncoding.EncodeToString([]byte(bookURL)) 162 | book.LastTitle = bookCatalog.Title 163 | book.LastUrl = bookCatalog.Url 164 | glog.Info("补充的数据:", book) 165 | bs.cacheBookInfo(book.Url, book) 166 | } 167 | -------------------------------------------------------------------------------- /public/static/css/index.8f174259337d201a961b56ae2f227b1b.css: -------------------------------------------------------------------------------- 1 | a,abbr,acronym,address,applet,article,aside,audio,b,big,blockquote,body,canvas,caption,center,cite,code,dd,del,details,dfn,div,dl,dt,em,embed,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,html,i,iframe,img,input,ins,kbd,label,legend,li,mark,menu,nav,object,ol,output,p,pre,q,ruby,s,samp,section,small,span,strike,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video{margin:0;padding:0;border:0;font-size:100%;font-weight:400;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,menu,nav,section{display:block}body{line-height:1}blockquote,q{quotes:none}blockquote:after,blockquote:before,q:after,q:before{content:none}table{border-collapse:collapse;border-spacing:0}a{color:#7e8c8d;-webkit-backface-visibility:hidden;text-decoration:none}li{list-style:none}body{-webkit-text-size-adjust:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}::-webkit-scrollbar{width:4px}::-webkit-scrollbar:horizontal{height:10px}::-webkit-scrollbar-track{border-radius:5px}::-webkit-scrollbar-thumb{border-radius:5px;background:hsla(0,0%,39%,.5)}body{-webkit-overflow-scrolling:touch;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.flex{display:-ms-flexbox;display:flex;-ms-flex-flow:row nowrap;flex-flow:row nowrap}.auto{-ms-flex:auto;flex:auto}.float-right{float:right}.tab-wrapper{height:calc(100vh - 14vw)}.tab-wrapper,.wrapper{position:fixed;top:0;left:0;width:100%;background:#f3f4f6}.wrapper{height:100vh}.scroll{height:100%;overflow:hidden}.bscroll-vertical-scrollbar{width:5px!important}.bscroll-indicator{background:rgba(0,0,0,.4)!important}.slide-enter-active,.slide-leave-active{transition:transform .3s ease}.slide-enter,.slide-leave-to{transform:translate3d(0,100%,0)}.night{background:#000}.night .color,.night .color .item p,.night .color li{color:hsla(0,0%,100%,.5)!important}.night .bg,.night .tab-wrapper{background:#1a1a1a!important}.night .search_box input{background-color:#1a1a1a!important}.night .border li{border-bottom-color:#000!important}.night .border:after{border-color:#000!important}.night .list li{background:#333!important;box-shadow:none!important}.night .list li img{filter:brightness(.5)}.night .list .btn{color:hsla(0,0%,100%,.5)!important;background:#705a31!important}@font-face{font-family:icomoon;src:url(data:application/vnd.ms-fontobject;base64,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);src:url(data:application/vnd.ms-fontobject;base64,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#iefix) format("embedded-opentype"),url(data:application/x-font-ttf;base64,AAEAAAALAIAAAwAwT1MvMg8SBzwAAAC8AAAAYGNtYXDTE5FnAAABHAAAAIRnYXNwAAAAEAAAAaAAAAAIZ2x5ZvRDnA4AAAGoAAAIrGhlYWQQCJJZAAAKVAAAADZoaGVhCAoEUAAACowAAAAkaG10eDGAAXcAAAqwAAAAPGxvY2ELCA2uAAAK7AAAACBtYXhwABsAnQAACwwAAAAgbmFtZZlKCfsAAAssAAABhnBvc3QAAwAAAAAMtAAAACAAAwPLAZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAAADqRwPA/8AAQAPAAEAAAAABAAAAAAAAAAAAAAAgAAAAAAADAAAAAwAAABwAAQADAAAAHAADAAEAAAAcAAQAaAAAABYAEAADAAYAAQAg6QLpIOmG6ZTpuunU6kf//f//AAAAAAAg6QDpIOmF6ZTpuunU6kb//f//AAH/4xcEFucWgxZ2FlEWOBXHAAMAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAB//8ADwABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAABAIIARgNeAxoAIgAAARQXHgEXFjMyNjcGBw4BBwYjIicuAScmNTQ3PgE3NjcOARUBXR0dZERDTSZIIRQjI1w4Nz1ORUVnHR4QETsqKTIDAwLOW1BPdyIjEhA1LS1BEhIeHWdFRU46NTVaIyMWEyYTAAAAAAIAAAASBAADEgAfAD8AAAEVFAYjIRUUBiMiJi8BLgE1NDY/AT4BMzIWHQEhMhYVERQGDwEOASMiJj0BISImPQE0NjMhNTQ2MzIWHwEeARUEAAsH/O0KCAQHA7YCAwMCtwMHAwcLAxMHCwMCtwMHAwcL/O0HCwsHAxMKCAQHA7YCAwESbQgLbQgLAwO3AgcDBAcDtgMDCwhtCwgBNwMHA7cCAwsHbgsHbgcLbggKAwK3AgcEAAEAYwAaAp0DnQAVAAAJAhYUDwEGIicBJjQ3ATYyHwEWFAcCnf7RAS8LC18KHgv+WAsLAagLHgpfCwsDC/7Q/tELHgpfCwsBqAoeCwGoCwtfCh4LAAUAAABABEgDQAAPABMAIwAnADgAABMjIgYVERQWOwEyNjURNCYHIzUzJSMiBhURFBY7ATI2NRE0JgcjNTM3Bw4BFwEeAT8BPgEnAS4BB+DADRMTDcANExMtgIABYMANExMNwA0TEy2AgP2rDAgFASAGGgusDAgG/uAGGQwDQBMN/UANExMNAsANE8BAgBMN/UANExMNAsANE8BAT1cGGQz9xQwJBlcGGQwCOwwIBQAABgAA/8AEAAPAAAMABwApADcARQBTAAATIRUhJSEVIQEjESERIREhESMiBhURFBYzITI2NREzERQWMyEyNjURNCYBIyImNTQ2OwEyFhUUBhMjIiY1NDY7ATIWFRQGASMiJjU0NjsBMhYVFAZAAYD+gAIAAYD+gAF4OP8A/wD/ADgeKioeATAeKoAqHgEwHioq/Yb4DxUVD/gPFRW1QA0TEw1ADRMTAW/4DxUVD/gPFRUDwEBAQP8AAQD/AAEA/wAqHv3QHioqHgF4/ogeKioeAjAeKv2AEw0NExMNDRMBwBMNDRMTDQ0T/kATDQ0TEw0NEwAAAAIAAP/YA+gDwAAoAEQAACUnLgEHPgE1NCcuAScmIyIHDgEHBhUUFx4BFxYzMjY3BhYfAR4BNzYmASInLgEnJjU0Nz4BNzYzMhceARcWFRQHDgEHBgPg8hMnECsxHh5pRkVQUEVGaR4eHh5pRkVQR4AyARARzhtLGxoE/YI1Ly5GFBQUFEYuLzU1Ly5GFBQUFEYuL1nOERABMoBHUEVGaR4eHh5pRkVQUEVGaR4eMSsQJxPyHgQaG0sBAhQURi4vNTUvLkYUFBQURi4vNTUvLkYUFAAAAgAS/8AD7gPAAEIAXgAAASYnJjY3NjcnDgEjIicuAScmNSMUBgcGBw4BJyYnBx4BFxYXFgYHBgcXPgEzMhceARcWFTM0Njc2Nz4BFxYXNy4BJwUiJy4BJyY1NDc+ATc2MzIXHgEXFhUUBw4BBwYDphQFBBMYFyNlFTIbKCMkNQ8PyQ0NFR8fSCcmI2UWJQ0UBAUUFxcjZRUyGigkIzUPEMkNDRQfH0kmJiRkFSUN/lorJiU5EBAQEDklJisrJiU5EBAQEDklJgFeIyYmSR8fFK8NDg8QNSQjKRkyFyMXFxMEBRSuDSQXIyYmSCAfFK4MDg8QNSMkKBkxFyMXFxMEBRSvDCQXbRAQOSUmKysmJTkQEBAQOSUmKysmJTkQEAAABgAA/8AEAAPAAAMABwALAA8AEwAXAAATIREhJSEVIQUhESElIRUhBSERISUhFSEAAQD/AAGAAoD9gP6AAQD/AAGAAoD9gP6AAQD/AAGAAoD9gAPA/wDAgMD/AMCAwP8AwIAAAAoAAP/ABAADwAANABsAKQA3AEYAVABjAHIAjgCaAAAlMhYdARQGIyImPQE0NhMiJj0BNDYzMhYdARQGATIWFRQGKwEiJjU0NjMFFAYrASImNTQ2OwEyFgUXFhQHBiIvASY0NzYyFwEnJjQ3NjIfARYUBwYiJQYiJyY0PwE2MhcWFA8BATYyFxYUDwEGIicmND8BASIHDgEHBhUUFx4BFxYzMjc+ATc2NTQnLgEnJgMiJjU0NjMyFhUUBgIAGyUlGxslJRsbJSUbGyUlAaUbJSUbQBslJRv9QCUbQBslJRtAGyUCfS0TExM1Ei4SEhM1E/2GLRMTEzUSLhISEzUCZxM1ExISLhI1ExMTLf2GEzUTEhIuEjUTExMtAT01Ly5GFBQUFEYuLzU1Ly5GFBQUFEYuLzVCXl5CQl5egCUbQBslJRtAGyUCgCUbQBslJRtAGyX/ACUbGyUlGxslQBslJRsbJSX9LhI1ExMTLRM1ExISAcQuEjUTExMtEzUTEhISEhM1Ey0TExM1Ei7+PBISEzUTLRMTEzUSLgHiFBRGLi81NS8uRhQUFBRGLi81NS8uRhQU/mBeQkJeXkJCXgAAAAALAEAAAAOgAwAABgAKAA4AEgAWABoAHgAiACYAKgAuAAABETMRMycHATMVIzczFSM3MxUjBTMVIzczFSM3MxUjJzMVIyUzFSMRFSM1JSERIQLAQKDAwP4gYGCAYGCAQED/AEBAYGBggGBg4EBAAQBAQMABAP7AAUABwP6AAYDAwAFAQEBAQGCAYEBAQEDgYEBg/uDAwED+wAAAAAALAEAAAAOgAwAABgAKAA4AEgAWABoAHgAiACYAKgAuAAABESMRIxc3ARUjNSUhESEFMxUjNzMVIzczFSMFMxUjNzMVIzczFSMnMxUjJTMVIwMAQKDAwP2gwAEA/sABQP7AYGCAYGCAQED/AEBAYGBggGBg4EBAAQBAQAEAAYD+gMDAAcDAwED+wIBAQEBAYIBgQEBAQOBgQGAAAAABAAAAAAAAtV4QwV8PPPUACwQAAAAAANZRJu4AAAAA1lEm7gAA/8AESAPAAAAACAACAAAAAAAAAAEAAAPA/8AAAASAAAAAAARIAAEAAAAAAAAAAAAAAAAAAAAPBAAAAAAAAAAAAAAAAgAAAAQAAIIEAAAAAwAAYwSAAAAEAAAABAAAAAQAABIEAAAABAAAAAQAAEAEAABAAAAAAAAKABQAHgBYALIA3AE0Aa4CGAKoAtoDugQIBFYAAQAAAA8AmwALAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAA4ArgABAAAAAAABAAcAAAABAAAAAAACAAcAYAABAAAAAAADAAcANgABAAAAAAAEAAcAdQABAAAAAAAFAAsAFQABAAAAAAAGAAcASwABAAAAAAAKABoAigADAAEECQABAA4ABwADAAEECQACAA4AZwADAAEECQADAA4APQADAAEECQAEAA4AfAADAAEECQAFABYAIAADAAEECQAGAA4AUgADAAEECQAKADQApGljb21vb24AaQBjAG8AbQBvAG8AblZlcnNpb24gMS4wAFYAZQByAHMAaQBvAG4AIAAxAC4AMGljb21vb24AaQBjAG8AbQBvAG8Abmljb21vb24AaQBjAG8AbQBvAG8AblJlZ3VsYXIAUgBlAGcAdQBsAGEAcmljb21vb24AaQBjAG8AbQBvAG8AbkZvbnQgZ2VuZXJhdGVkIGJ5IEljb01vb24uAEYAbwBuAHQAIABnAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAEkAYwBvAE0AbwBvAG4ALgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=) format("truetype"),url(data:application/font-woff;base64,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) format("woff"),url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiID4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8bWV0YWRhdGE+R2VuZXJhdGVkIGJ5IEljb01vb248L21ldGFkYXRhPgo8ZGVmcz4KPGZvbnQgaWQ9Imljb21vb24iIGhvcml6LWFkdi14PSIxMDI0Ij4KPGZvbnQtZmFjZSB1bml0cy1wZXItZW09IjEwMjQiIGFzY2VudD0iOTYwIiBkZXNjZW50PSItNjQiIC8+CjxtaXNzaW5nLWdseXBoIGhvcml6LWFkdi14PSIxMDI0IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4MjA7IiBob3Jpei1hZHYteD0iNTEyIiBkPSIiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlOTAwOyIgZ2x5cGgtbmFtZT0ibmlnaHQiIGQ9Ik0zNDguNjQgNzE3LjYzMmMwLTI0MS42IDE2NS43MjgtNDM3LjQ0IDM3MC4xNDQtNDM3LjQ0IDUwLjgxNiAwIDk5LjIzMiAxMi4xNiAxNDMuMzI4IDM0LjAxNi01NC4yNC0xNDIuNzItMTkxLjg3Mi0yNDQuMzUyLTM1My42MzItMjQ0LjM1Mi0yMDkuMDU2IDAtMzc4LjU2IDE2OS41MDQtMzc4LjU2IDM3OC41NiAwIDE1NC4yNCA5Mi40MTYgMjg2LjY4OCAyMjQuNzM2IDM0NS42OTYtMy43MTItMjQuODk2LTYuMDE2LTUwLjMzNi02LjAxNi03Ni40OHoiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlOTAxOyIgZ2x5cGgtbmFtZT0iZXhjaGFuZ2UiIGQ9Ik0xMDI0IDI3NC4yODZ2LTEwOS43MTRjMC05LjcxNC04LjU3MS0xOC4yODYtMTguMjg2LTE4LjI4NmgtNzg2LjI4NnYtMTA5LjcxNGMwLTkuNzE0LTgtMTguMjg2LTE4LjI4Ni0xOC4yODYtNS4xNDMgMC05LjcxNCAyLjI4Ni0xMy43MTQgNS43MTRsLTE4Mi4yODYgMTgyLjg1N2MtMy40MjkgMy40MjktNS4xNDMgOC01LjE0MyAxMi41NzEgMCA1LjE0MyAxLjcxNCA5LjcxNCA1LjE0MyAxMy4xNDNsMTgyLjg1NyAxODIuODU3YzMuNDI5IDMuNDI5IDguNTcxIDUuMTQzIDEzLjE0MyA1LjE0MyA5LjcxNCAwIDE4LjI4Ni04IDE4LjI4Ni0xOC4yODZ2LTEwOS43MTRoNzg2LjI4NmM5LjcxNCAwIDE4LjI4Ni04IDE4LjI4Ni0xOC4yODZ6TTEwMjQgNTg1LjE0M2MwLTQuNTcxLTEuNzE0LTkuNzE0LTUuMTQzLTEzLjE0M2wtMTgyLjg1Ny0xODIuODU3Yy0zLjQyOS0zLjQyOS04LjU3MS01LjE0My0xMy4xNDMtNS4xNDMtOS43MTQgMC0xOC4yODYgOC41NzEtMTguMjg2IDE4LjI4NnYxMDkuNzE0aC03ODYuMjg2Yy05LjcxNCAwLTE4LjI4NiA4LjU3MS0xOC4yODYgMTguMjg2djEwOS43MTRjMCA5LjcxNCA4LjU3MSAxOC4yODYgMTguMjg2IDE4LjI4Nmg3ODYuMjg2djEwOS43MTRjMCAxMC4yODYgOCAxOC4yODYgMTguMjg2IDE4LjI4NiA1LjE0MyAwIDkuNzE0LTIuMjg2IDEzLjcxNC01LjcxNGwxODIuMjg2LTE4Mi4yODZjMy40MjktMy40MjkgNS4xNDMtOC41NzEgNS4xNDMtMTMuMTQzeiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGU5MDI7IiBnbHlwaC1uYW1lPSJiYWNrIiBob3Jpei1hZHYteD0iNzY4IiBkPSJNNjY5LjE0MyA3NzguODU3bC0zMDMuNDI5LTMwMy40MjkgMzAzLjQyOS0zMDMuNDI5YzE0LjI4Ni0xNC4yODYgMTQuMjg2LTM3LjE0MyAwLTUxLjQyOWwtOTQuODU3LTk0Ljg1N2MtMTQuMjg2LTE0LjI4Ni0zNy4xNDMtMTQuMjg2LTUxLjQyOSAwbC00MjQgNDI0Yy0xNC4yODYgMTQuMjg2LTE0LjI4NiAzNy4xNDMgMCA1MS40MjlsNDI0IDQyNGMxNC4yODYgMTQuMjg2IDM3LjE0MyAxNC4yODYgNTEuNDI5IDBsOTQuODU3LTk0Ljg1N2MxNC4yODYtMTQuMjg2IDE0LjI4Ni0zNy4xNDMgMC01MS40Mjl6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTkyMDsiIGdseXBoLW5hbWU9ImJvb2tzIiBob3Jpei1hZHYteD0iMTE1MiIgZD0iTTIyNCA4MzJoLTE5MmMtMTcuNiAwLTMyLTE0LjQtMzItMzJ2LTcwNGMwLTE3LjYgMTQuNC0zMiAzMi0zMmgxOTJjMTcuNiAwIDMyIDE0LjQgMzIgMzJ2NzA0YzAgMTcuNi0xNC40IDMyLTMyIDMyek0xOTIgNjQwaC0xMjh2NjRoMTI4di02NHpNNTQ0IDgzMmgtMTkyYy0xNy42IDAtMzItMTQuNC0zMi0zMnYtNzA0YzAtMTcuNiAxNC40LTMyIDMyLTMyaDE5MmMxNy42IDAgMzIgMTQuNCAzMiAzMnY3MDRjMCAxNy42LTE0LjQgMzItMzIgMzJ6TTUxMiA2NDBoLTEyOHY2NGgxMjh2LTY0ek03NjUuMDg4IDc4Mi41MmwtMTcxLjQ2NC04Ni4zOTRjLTE1LjcxNi03LjkxOC0yMi4wOTYtMjcuMjU4LTE0LjE3OC00Mi45NzZsMjg3Ljk3OC01NzEuNTQ4YzcuOTE4LTE1LjcxOCAyNy4yNTgtMjIuMDk4IDQyLjk3Ni0xNC4xNzhsMTcxLjQ2NCA4Ni4zOTJjMTUuNzE2IDcuOTIgMjIuMDk2IDI3LjI2IDE0LjE3OCA0Mi45NzRsLTI4Ny45NzggNTcxLjU1Yy03LjkyIDE1LjcxOC0yNy4yNiAyMi4xLTQyLjk3NiAxNC4xOHoiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlOTg1OyIgZ2x5cGgtbmFtZT0iYmlub2N1bGFycyIgZD0iTTY0IDk2MGgzODR2LTY0aC0zODR6TTU3NiA5NjBoMzg0di02NGgtMzg0ek05NTIgNjQwaC01NnYyNTZoLTI1NnYtMjU2aC0yNTZ2MjU2aC0yNTZ2LTI1NmgtNTZjLTM5LjYgMC03Mi0zMi40LTcyLTcydi01NjBjMC0zOS42IDMyLjQtNzIgNzItNzJoMzA0YzM5LjYgMCA3MiAzMi40IDcyIDcydjM3NmgxMjh2LTM3NmMwLTM5LjYgMzIuNC03MiA3Mi03MmgzMDRjMzkuNiAwIDcyIDMyLjQgNzIgNzJ2NTYwYzAgMzkuNi0zMi40IDcyLTcyIDcyek0zNDggMGgtMjQ4Yy0xOS44IDAtMzYgMTQuNC0zNiAzMnMxNi4yIDMyIDM2IDMyaDI0OGMxOS44IDAgMzYtMTQuNCAzNi0zMnMtMTYuMi0zMi0zNi0zMnpNNTQ0IDQ0OGgtNjRjLTE3LjYgMC0zMiAxNC40LTMyIDMyczE0LjQgMzIgMzIgMzJoNjRjMTcuNiAwIDMyLTE0LjQgMzItMzJzLTE0LjQtMzItMzItMzJ6TTkyNCAwaC0yNDhjLTE5LjggMC0zNiAxNC40LTM2IDMyczE2LjIgMzIgMzYgMzJoMjQ4YzE5LjggMCAzNi0xNC40IDM2LTMycy0xNi4yLTMyLTM2LTMyeiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGU5ODY7IiBnbHlwaC1uYW1lPSJzZWFyY2giIGQ9Ik05OTIuMjYyIDg4LjYwNGwtMjQyLjU1MiAyMDYuMjk0Yy0yNS4wNzQgMjIuNTY2LTUxLjg5IDMyLjkyNi03My41NTIgMzEuOTI2IDU3LjI1NiA2Ny4wNjggOTEuODQyIDE1NC4wNzggOTEuODQyIDI0OS4xNzYgMCAyMTIuMDc4LTE3MS45MjIgMzg0LTM4NCAzODQtMjEyLjA3NiAwLTM4NC0xNzEuOTIyLTM4NC0zODRzMTcxLjkyMi0zODQgMzg0LTM4NGM5NS4wOTggMCAxODIuMTA4IDM0LjU4NiAyNDkuMTc2IDkxLjg0NC0xLTIxLjY2MiA5LjM2LTQ4LjQ3OCAzMS45MjYtNzMuNTUybDIwNi4yOTQtMjQyLjU1MmMzNS4zMjItMzkuMjQ2IDkzLjAyMi00Mi41NTQgMTI4LjIyLTcuMzU2czMxLjg5MiA5Mi44OTgtNy4zNTQgMTI4LjIyek0zODQgMzIwYy0xNDEuMzg0IDAtMjU2IDExNC42MTYtMjU2IDI1NnMxMTQuNjE2IDI1NiAyNTYgMjU2IDI1Ni0xMTQuNjE2IDI1Ni0yNTYtMTE0LjYxNC0yNTYtMjU2LTI1NnoiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlOTk0OyIgZ2x5cGgtbmFtZT0ic2V0dGluZyIgZD0iTTkzMy43OSAzNDkuNzVjLTUzLjcyNiA5My4wNTQtMjEuNDE2IDIxMi4zMDQgNzIuMTUyIDI2Ni40ODhsLTEwMC42MjYgMTc0LjI5MmMtMjguNzUtMTYuODU0LTYyLjE3Ni0yNi41MTgtOTcuODQ2LTI2LjUxOC0xMDcuNTM2IDAtMTk0LjcwOCA4Ny43NDYtMTk0LjcwOCAxOTUuOTloLTIwMS4yNThjMC4yNjYtMzMuNDEtOC4wNzQtNjcuMjgyLTI1Ljk1OC05OC4yNTItNTMuNzI0LTkzLjA1Ni0xNzMuMTU2LTEyNC43MDItMjY2Ljg2Mi03MC43NThsLTEwMC42MjQtMTc0LjI5MmMyOC45Ny0xNi40NzIgNTQuMDUwLTQwLjU4OCA3MS44ODYtNzEuNDc4IDUzLjYzOC05Mi45MDggMjEuNTEyLTIxMS45Mi03MS43MDgtMjY2LjIyNGwxMDAuNjI2LTE3NC4yOTJjMjguNjUgMTYuNjk2IDYxLjkxNiAyNi4yNTQgOTcuNCAyNi4yNTQgMTA3LjE5NiAwIDE5NC4xNDQtODcuMTkyIDE5NC43LTE5NC45NThoMjAxLjI1NGMtMC4wODYgMzMuMDc0IDguMjcyIDY2LjU3IDI1Ljk2NiA5Ny4yMTggNTMuNjM2IDkyLjkwNiAxNzIuNzc2IDEyNC41OTQgMjY2LjQxNCA3MS4wMTJsMTAwLjYyNiAxNzQuMjljLTI4Ljc4IDE2LjQ2Ni01My42OTIgNDAuNDk4LTcxLjQzNCA3MS4yMjh6TTUxMiAyNDAuNjY4Yy0xMTQuNTA4IDAtMjA3LjMzNiA5Mi44MjQtMjA3LjMzNiAyMDcuMzM0IDAgMTE0LjUwOCA5Mi44MjYgMjA3LjMzNCAyMDcuMzM2IDIwNy4zMzQgMTE0LjUwOCAwIDIwNy4zMzItOTIuODI2IDIwNy4zMzItMjA3LjMzNC0wLjAwMi0xMTQuNTEtOTIuODI0LTIwNy4zMzQtMjA3LjMzMi0yMDcuMzM0eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGU5YmE7IiBnbHlwaC1uYW1lPSJsaXN0IiBkPSJNMCA5NjBoMjU2di0yNTZoLTI1NnpNMzg0IDg5Nmg2NDB2LTEyOGgtNjQwek0wIDU3NmgyNTZ2LTI1NmgtMjU2ek0zODQgNTEyaDY0MHYtMTI4aC02NDB6TTAgMTkyaDI1NnYtMjU2aC0yNTZ6TTM4NCAxMjhoNjQwdi0xMjhoLTY0MHoiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlOWQ0OyIgZ2x5cGgtbmFtZT0ic3VuIiBkPSJNNTEyIDEyOGMzNS4zNDYgMCA2NC0yOC42NTQgNjQtNjR2LTY0YzAtMzUuMzQ2LTI4LjY1NC02NC02NC02NHMtNjQgMjguNjU0LTY0IDY0djY0YzAgMzUuMzQ2IDI4LjY1NCA2NCA2NCA2NHpNNTEyIDc2OGMtMzUuMzQ2IDAtNjQgMjguNjU0LTY0IDY0djY0YzAgMzUuMzQ2IDI4LjY1NCA2NCA2NCA2NHM2NC0yOC42NTQgNjQtNjR2LTY0YzAtMzUuMzQ2LTI4LjY1NC02NC02NC02NHpNOTYwIDUxMmMzNS4zNDYgMCA2NC0yOC42NTQgNjQtNjRzLTI4LjY1NC02NC02NC02NGgtNjRjLTM1LjM0OCAwLTY0IDI4LjY1NC02NCA2NHMyOC42NTIgNjQgNjQgNjRoNjR6TTE5MiA0NDhjMC0zNS4zNDYtMjguNjU0LTY0LTY0LTY0aC02NGMtMzUuMzQ2IDAtNjQgMjguNjU0LTY0IDY0czI4LjY1NCA2NCA2NCA2NGg2NGMzNS4zNDYgMCA2NC0yOC42NTQgNjQtNjR6TTgyOC43ODQgMjIxLjcyNmw0NS4yNTYtNDUuMjU4YzI0Ljk5Mi0yNC45OSAyNC45OTItNjUuNTE2IDAtOTAuNTA4LTI0Ljk5NC0yNC45OTItNjUuNTE4LTI0Ljk5Mi05MC41MSAwbC00NS4yNTYgNDUuMjU2Yy0yNC45OTIgMjQuOTktMjQuOTkyIDY1LjUxNiAwIDkwLjUxIDI0Ljk5NCAyNC45OTIgNjUuNTE4IDI0Ljk5MiA5MC41MSAwek0xOTUuMjE2IDY3NC4yNzRsLTQ1LjI1NiA0NS4yNTZjLTI0Ljk5NCAyNC45OTQtMjQuOTk0IDY1LjUxNiAwIDkwLjUxczY1LjUxNiAyNC45OTQgOTAuNTEgMGw0NS4yNTYtNDUuMjU2YzI0Ljk5NC0yNC45OTQgMjQuOTk0LTY1LjUxNiAwLTkwLjUxcy02NS41MTYtMjQuOTk0LTkwLjUxIDB6TTgyOC43ODQgNjc0LjI3NGMtMjQuOTkyLTI0Ljk5Mi02NS41MTYtMjQuOTkyLTkwLjUxIDAtMjQuOTkyIDI0Ljk5NC0yNC45OTIgNjUuNTE2IDAgOTAuNTFsNDUuMjU2IDQ1LjI1NGMyNC45OTIgMjQuOTk0IDY1LjUxNiAyNC45OTQgOTAuNTEgMCAyNC45OTItMjQuOTk0IDI0Ljk5Mi02NS41MTYgMC05MC41MWwtNDUuMjU2LTQ1LjI1NHpNMTk1LjIxNiAyMjEuNzI2YzI0Ljk5MiAyNC45OTIgNjUuNTE4IDI0Ljk5MiA5MC41MDggMCAyNC45OTQtMjQuOTk0IDI0Ljk5NC02NS41MiAwLTkwLjUxbC00NS4yNTQtNDUuMjU2Yy0yNC45OTQtMjQuOTkyLTY1LjUxNi0yNC45OTItOTAuNTEgMHMtMjQuOTk0IDY1LjUxOCAwIDkwLjUwOGw0NS4yNTYgNDUuMjU4ek01MTIgNzA0Yy0xNDEuMzg0IDAtMjU2LTExNC42MTYtMjU2LTI1NiAwLTE0MS4zODIgMTE0LjYxNi0yNTYgMjU2LTI1NiAxNDEuMzgyIDAgMjU2IDExNC42MTggMjU2IDI1NiAwIDE0MS4zODQtMTE0LjYxNiAyNTYtMjU2IDI1NnpNNTEyIDI4OGMtODguMzY2IDAtMTYwIDcxLjYzNC0xNjAgMTYwczcxLjYzNCAxNjAgMTYwIDE2MCAxNjAtNzEuNjM0IDE2MC0xNjAtNzEuNjM0LTE2MC0xNjAtMTYweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGVhNDY7IiBnbHlwaC1uYW1lPSJzb3J0VXAiIGQ9Ik03MDQgNDQ4di0zODRoNjR2Mzg0aDE2MGwtMTkyIDE5Mi0xOTItMTkyek02NCA3NjhoOTZ2LTY0aC05NnY2NHpNMTkyIDc2OGg5NnYtNjRoLTk2djY0ek0zMjAgNzY4aDY0di05NmgtNjR2OTZ6TTY0IDU0NGg2NHYtOTZoLTY0djk2ek0xNjAgNTEyaDk2di02NGgtOTZ2NjR6TTI4OCA1MTJoOTZ2LTY0aC05NnY2NHpNNjQgNjcyaDY0di05NmgtNjR2OTZ6TTMyMCA2NDBoNjR2LTk2aC02NHY5NnpNMzIwIDI1NnYtMTkyaC0xOTJ2MTkyaDE5MnpNMzg0IDMyMGgtMzIwdi0zMjBoMzIwdjMyMHoiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlYTQ3OyIgZ2x5cGgtbmFtZT0ic29ydERvd24iIGQ9Ik03NjggMjU2djM4NGgtNjR2LTM4NGgtMTYwbDE5Mi0xOTIgMTkyIDE5MnpNMzIwIDcwNHYtMTkyaC0xOTJ2MTkyaDE5MnpNMzg0IDc2OGgtMzIwdi0zMjBoMzIwdjMyMHpNNjQgMzIwaDk2di02NGgtOTZ2NjR6TTE5MiAzMjBoOTZ2LTY0aC05NnY2NHpNMzIwIDMyMGg2NHYtOTZoLTY0djk2ek02NCA5Nmg2NHYtOTZoLTY0djk2ek0xNjAgNjRoOTZ2LTY0aC05NnY2NHpNMjg4IDY0aDk2di02NGgtOTZ2NjR6TTY0IDIyNGg2NHYtOTZoLTY0djk2ek0zMjAgMTkyaDY0di05NmgtNjR2OTZ6IiAvPgo8L2ZvbnQ+PC9kZWZzPjwvc3ZnPg==#icomoon) format("svg");font-weight:400;font-style:normal}[class*=" icon-"],[class^=icon-]{font-family:icomoon!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-back:before{content:"\E902"}.icon-exchange:before{content:"\E901"}.icon-night:before{content:"\E900"}.icon-books:before{content:"\E920"}.icon-binoculars:before{content:"\E985"}.icon-search:before{content:"\E986"}.icon-setting:before{content:"\E994"}.icon-list:before{content:"\E9BA"}.icon-sun:before{content:"\E9D4"}.icon-sortUp:before{content:"\EA46"}.icon-sortDown:before{content:"\EA47"} -------------------------------------------------------------------------------- /public/assets/js/pako.min.js: -------------------------------------------------------------------------------- 1 | /* pako 1.0.3 nodeca/pako */ 2 | !function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.pako=t()}}(function(){return function t(e,a,i){function n(s,o){if(!a[s]){if(!e[s]){var l="function"==typeof require&&require;if(!o&&l)return l(s,!0);if(r)return r(s,!0);var h=new Error("Cannot find module '"+s+"'");throw h.code="MODULE_NOT_FOUND",h}var d=a[s]={exports:{}};e[s][0].call(d.exports,function(t){var a=e[s][1][t];return n(a?a:t)},d,d.exports,t,e,a,i)}return a[s].exports}for(var r="function"==typeof require&&require,s=0;s0?e.windowBits=-e.windowBits:e.gzip&&e.windowBits>0&&e.windowBits<16&&(e.windowBits+=16),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new f,this.strm.avail_out=0;var a=o.deflateInit2(this.strm,e.level,e.method,e.windowBits,e.memLevel,e.strategy);if(a!==b)throw new Error(d[a]);if(e.header&&o.deflateSetHeader(this.strm,e.header),e.dictionary){var n;if(n="string"==typeof e.dictionary?h.string2buf(e.dictionary):"[object ArrayBuffer]"===_.call(e.dictionary)?new Uint8Array(e.dictionary):e.dictionary,a=o.deflateSetDictionary(this.strm,n),a!==b)throw new Error(d[a]);this._dict_set=!0}}function n(t,e){var a=new i(e);if(a.push(t,!0),a.err)throw a.msg;return a.result}function r(t,e){return e=e||{},e.raw=!0,n(t,e)}function s(t,e){return e=e||{},e.gzip=!0,n(t,e)}var o=t("./zlib/deflate"),l=t("./utils/common"),h=t("./utils/strings"),d=t("./zlib/messages"),f=t("./zlib/zstream"),_=Object.prototype.toString,u=0,c=4,b=0,g=1,m=2,w=-1,p=0,v=8;i.prototype.push=function(t,e){var a,i,n=this.strm,r=this.options.chunkSize;if(this.ended)return!1;i=e===~~e?e:e===!0?c:u,"string"==typeof t?n.input=h.string2buf(t):"[object ArrayBuffer]"===_.call(t)?n.input=new Uint8Array(t):n.input=t,n.next_in=0,n.avail_in=n.input.length;do{if(0===n.avail_out&&(n.output=new l.Buf8(r),n.next_out=0,n.avail_out=r),a=o.deflate(n,i),a!==g&&a!==b)return this.onEnd(a),this.ended=!0,!1;0!==n.avail_out&&(0!==n.avail_in||i!==c&&i!==m)||("string"===this.options.to?this.onData(h.buf2binstring(l.shrinkBuf(n.output,n.next_out))):this.onData(l.shrinkBuf(n.output,n.next_out)))}while((n.avail_in>0||0===n.avail_out)&&a!==g);return i===c?(a=o.deflateEnd(this.strm),this.onEnd(a),this.ended=!0,a===b):i!==m||(this.onEnd(b),n.avail_out=0,!0)},i.prototype.onData=function(t){this.chunks.push(t)},i.prototype.onEnd=function(t){t===b&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=l.flattenChunks(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg},a.Deflate=i,a.deflate=n,a.deflateRaw=r,a.gzip=s},{"./utils/common":3,"./utils/strings":4,"./zlib/deflate":8,"./zlib/messages":13,"./zlib/zstream":15}],2:[function(t,e,a){"use strict";function i(t){if(!(this instanceof i))return new i(t);this.options=o.assign({chunkSize:16384,windowBits:0,to:""},t||{});var e=this.options;e.raw&&e.windowBits>=0&&e.windowBits<16&&(e.windowBits=-e.windowBits,0===e.windowBits&&(e.windowBits=-15)),!(e.windowBits>=0&&e.windowBits<16)||t&&t.windowBits||(e.windowBits+=32),e.windowBits>15&&e.windowBits<48&&0===(15&e.windowBits)&&(e.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new f,this.strm.avail_out=0;var a=s.inflateInit2(this.strm,e.windowBits);if(a!==h.Z_OK)throw new Error(d[a]);this.header=new _,s.inflateGetHeader(this.strm,this.header)}function n(t,e){var a=new i(e);if(a.push(t,!0),a.err)throw a.msg;return a.result}function r(t,e){return e=e||{},e.raw=!0,n(t,e)}var s=t("./zlib/inflate"),o=t("./utils/common"),l=t("./utils/strings"),h=t("./zlib/constants"),d=t("./zlib/messages"),f=t("./zlib/zstream"),_=t("./zlib/gzheader"),u=Object.prototype.toString;i.prototype.push=function(t,e){var a,i,n,r,d,f,_=this.strm,c=this.options.chunkSize,b=this.options.dictionary,g=!1;if(this.ended)return!1;i=e===~~e?e:e===!0?h.Z_FINISH:h.Z_NO_FLUSH,"string"==typeof t?_.input=l.binstring2buf(t):"[object ArrayBuffer]"===u.call(t)?_.input=new Uint8Array(t):_.input=t,_.next_in=0,_.avail_in=_.input.length;do{if(0===_.avail_out&&(_.output=new o.Buf8(c),_.next_out=0,_.avail_out=c),a=s.inflate(_,h.Z_NO_FLUSH),a===h.Z_NEED_DICT&&b&&(f="string"==typeof b?l.string2buf(b):"[object ArrayBuffer]"===u.call(b)?new Uint8Array(b):b,a=s.inflateSetDictionary(this.strm,f)),a===h.Z_BUF_ERROR&&g===!0&&(a=h.Z_OK,g=!1),a!==h.Z_STREAM_END&&a!==h.Z_OK)return this.onEnd(a),this.ended=!0,!1;_.next_out&&(0!==_.avail_out&&a!==h.Z_STREAM_END&&(0!==_.avail_in||i!==h.Z_FINISH&&i!==h.Z_SYNC_FLUSH)||("string"===this.options.to?(n=l.utf8border(_.output,_.next_out),r=_.next_out-n,d=l.buf2string(_.output,n),_.next_out=r,_.avail_out=c-r,r&&o.arraySet(_.output,_.output,n,r,0),this.onData(d)):this.onData(o.shrinkBuf(_.output,_.next_out)))),0===_.avail_in&&0===_.avail_out&&(g=!0)}while((_.avail_in>0||0===_.avail_out)&&a!==h.Z_STREAM_END);return a===h.Z_STREAM_END&&(i=h.Z_FINISH),i===h.Z_FINISH?(a=s.inflateEnd(this.strm),this.onEnd(a),this.ended=!0,a===h.Z_OK):i!==h.Z_SYNC_FLUSH||(this.onEnd(h.Z_OK),_.avail_out=0,!0)},i.prototype.onData=function(t){this.chunks.push(t)},i.prototype.onEnd=function(t){t===h.Z_OK&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=o.flattenChunks(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg},a.Inflate=i,a.inflate=n,a.inflateRaw=r,a.ungzip=n},{"./utils/common":3,"./utils/strings":4,"./zlib/constants":6,"./zlib/gzheader":9,"./zlib/inflate":11,"./zlib/messages":13,"./zlib/zstream":15}],3:[function(t,e,a){"use strict";var i="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;a.assign=function(t){for(var e=Array.prototype.slice.call(arguments,1);e.length;){var a=e.shift();if(a){if("object"!=typeof a)throw new TypeError(a+"must be non-object");for(var i in a)a.hasOwnProperty(i)&&(t[i]=a[i])}}return t},a.shrinkBuf=function(t,e){return t.length===e?t:t.subarray?t.subarray(0,e):(t.length=e,t)};var n={arraySet:function(t,e,a,i,n){if(e.subarray&&t.subarray)return void t.set(e.subarray(a,a+i),n);for(var r=0;r=252?6:l>=248?5:l>=240?4:l>=224?3:l>=192?2:1;o[254]=o[254]=1,a.string2buf=function(t){var e,a,i,r,s,o=t.length,l=0;for(r=0;r>>6,e[s++]=128|63&a):a<65536?(e[s++]=224|a>>>12,e[s++]=128|a>>>6&63,e[s++]=128|63&a):(e[s++]=240|a>>>18,e[s++]=128|a>>>12&63,e[s++]=128|a>>>6&63,e[s++]=128|63&a);return e},a.buf2binstring=function(t){return i(t,t.length)},a.binstring2buf=function(t){for(var e=new n.Buf8(t.length),a=0,i=e.length;a4)h[n++]=65533,a+=s-1;else{for(r&=2===s?31:3===s?15:7;s>1&&a1?h[n++]=65533:r<65536?h[n++]=r:(r-=65536,h[n++]=55296|r>>10&1023,h[n++]=56320|1023&r)}return i(h,n)},a.utf8border=function(t,e){var a;for(e=e||t.length,e>t.length&&(e=t.length),a=e-1;a>=0&&128===(192&t[a]);)a--;return a<0?e:0===a?e:a+o[t[a]]>e?a:e}},{"./common":3}],5:[function(t,e,a){"use strict";function i(t,e,a,i){for(var n=65535&t|0,r=t>>>16&65535|0,s=0;0!==a;){s=a>2e3?2e3:a,a-=s;do n=n+e[i++]|0,r=r+n|0;while(--s);n%=65521,r%=65521}return n|r<<16|0}e.exports=i},{}],6:[function(t,e,a){"use strict";e.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],7:[function(t,e,a){"use strict";function i(){for(var t,e=[],a=0;a<256;a++){t=a;for(var i=0;i<8;i++)t=1&t?3988292384^t>>>1:t>>>1;e[a]=t}return e}function n(t,e,a,i){var n=r,s=i+a;t^=-1;for(var o=i;o>>8^n[255&(t^e[o])];return t^-1}var r=i();e.exports=n},{}],8:[function(t,e,a){"use strict";function i(t,e){return t.msg=D[e],e}function n(t){return(t<<1)-(t>4?9:0)}function r(t){for(var e=t.length;--e>=0;)t[e]=0}function s(t){var e=t.state,a=e.pending;a>t.avail_out&&(a=t.avail_out),0!==a&&(R.arraySet(t.output,e.pending_buf,e.pending_out,a,t.next_out),t.next_out+=a,e.pending_out+=a,t.total_out+=a,t.avail_out-=a,e.pending-=a,0===e.pending&&(e.pending_out=0))}function o(t,e){C._tr_flush_block(t,t.block_start>=0?t.block_start:-1,t.strstart-t.block_start,e),t.block_start=t.strstart,s(t.strm)}function l(t,e){t.pending_buf[t.pending++]=e}function h(t,e){t.pending_buf[t.pending++]=e>>>8&255,t.pending_buf[t.pending++]=255&e}function d(t,e,a,i){var n=t.avail_in;return n>i&&(n=i),0===n?0:(t.avail_in-=n,R.arraySet(e,t.input,t.next_in,n,a),1===t.state.wrap?t.adler=N(t.adler,e,n,a):2===t.state.wrap&&(t.adler=O(t.adler,e,n,a)),t.next_in+=n,t.total_in+=n,n)}function f(t,e){var a,i,n=t.max_chain_length,r=t.strstart,s=t.prev_length,o=t.nice_match,l=t.strstart>t.w_size-ft?t.strstart-(t.w_size-ft):0,h=t.window,d=t.w_mask,f=t.prev,_=t.strstart+dt,u=h[r+s-1],c=h[r+s];t.prev_length>=t.good_match&&(n>>=2),o>t.lookahead&&(o=t.lookahead);do if(a=e,h[a+s]===c&&h[a+s-1]===u&&h[a]===h[r]&&h[++a]===h[r+1]){r+=2,a++;do;while(h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&r<_);if(i=dt-(_-r),r=_-dt,i>s){if(t.match_start=e,s=i,i>=o)break;u=h[r+s-1],c=h[r+s]}}while((e=f[e&d])>l&&0!==--n);return s<=t.lookahead?s:t.lookahead}function _(t){var e,a,i,n,r,s=t.w_size;do{if(n=t.window_size-t.lookahead-t.strstart,t.strstart>=s+(s-ft)){R.arraySet(t.window,t.window,s,s,0),t.match_start-=s,t.strstart-=s,t.block_start-=s,a=t.hash_size,e=a;do i=t.head[--e],t.head[e]=i>=s?i-s:0;while(--a);a=s,e=a;do i=t.prev[--e],t.prev[e]=i>=s?i-s:0;while(--a);n+=s}if(0===t.strm.avail_in)break;if(a=d(t.strm,t.window,t.strstart+t.lookahead,n),t.lookahead+=a,t.lookahead+t.insert>=ht)for(r=t.strstart-t.insert,t.ins_h=t.window[r],t.ins_h=(t.ins_h<t.pending_buf_size-5&&(a=t.pending_buf_size-5);;){if(t.lookahead<=1){if(_(t),0===t.lookahead&&e===I)return vt;if(0===t.lookahead)break}t.strstart+=t.lookahead,t.lookahead=0;var i=t.block_start+a;if((0===t.strstart||t.strstart>=i)&&(t.lookahead=t.strstart-i,t.strstart=i,o(t,!1),0===t.strm.avail_out))return vt;if(t.strstart-t.block_start>=t.w_size-ft&&(o(t,!1),0===t.strm.avail_out))return vt}return t.insert=0,e===F?(o(t,!0),0===t.strm.avail_out?yt:xt):t.strstart>t.block_start&&(o(t,!1),0===t.strm.avail_out)?vt:vt}function c(t,e){for(var a,i;;){if(t.lookahead=ht&&(t.ins_h=(t.ins_h<=ht)if(i=C._tr_tally(t,t.strstart-t.match_start,t.match_length-ht),t.lookahead-=t.match_length,t.match_length<=t.max_lazy_match&&t.lookahead>=ht){t.match_length--;do t.strstart++,t.ins_h=(t.ins_h<=ht&&(t.ins_h=(t.ins_h<4096)&&(t.match_length=ht-1)),t.prev_length>=ht&&t.match_length<=t.prev_length){n=t.strstart+t.lookahead-ht,i=C._tr_tally(t,t.strstart-1-t.prev_match,t.prev_length-ht),t.lookahead-=t.prev_length-1,t.prev_length-=2;do++t.strstart<=n&&(t.ins_h=(t.ins_h<=ht&&t.strstart>0&&(n=t.strstart-1,i=s[n],i===s[++n]&&i===s[++n]&&i===s[++n])){r=t.strstart+dt;do;while(i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&nt.lookahead&&(t.match_length=t.lookahead)}if(t.match_length>=ht?(a=C._tr_tally(t,1,t.match_length-ht),t.lookahead-=t.match_length,t.strstart+=t.match_length,t.match_length=0):(a=C._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++),a&&(o(t,!1),0===t.strm.avail_out))return vt}return t.insert=0,e===F?(o(t,!0),0===t.strm.avail_out?yt:xt):t.last_lit&&(o(t,!1),0===t.strm.avail_out)?vt:kt}function m(t,e){for(var a;;){if(0===t.lookahead&&(_(t),0===t.lookahead)){if(e===I)return vt;break}if(t.match_length=0,a=C._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++,a&&(o(t,!1),0===t.strm.avail_out))return vt}return t.insert=0,e===F?(o(t,!0),0===t.strm.avail_out?yt:xt):t.last_lit&&(o(t,!1),0===t.strm.avail_out)?vt:kt}function w(t,e,a,i,n){this.good_length=t,this.max_lazy=e,this.nice_length=a,this.max_chain=i,this.func=n}function p(t){t.window_size=2*t.w_size,r(t.head),t.max_lazy_match=Z[t.level].max_lazy,t.good_match=Z[t.level].good_length,t.nice_match=Z[t.level].nice_length,t.max_chain_length=Z[t.level].max_chain,t.strstart=0,t.block_start=0,t.lookahead=0,t.insert=0,t.match_length=t.prev_length=ht-1,t.match_available=0,t.ins_h=0}function v(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=V,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,this.prev_length=0,this.max_chain_length=0,this.max_lazy_match=0,this.level=0,this.strategy=0,this.good_match=0,this.nice_match=0,this.dyn_ltree=new R.Buf16(2*ot),this.dyn_dtree=new R.Buf16(2*(2*rt+1)),this.bl_tree=new R.Buf16(2*(2*st+1)),r(this.dyn_ltree),r(this.dyn_dtree),r(this.bl_tree),this.l_desc=null,this.d_desc=null,this.bl_desc=null,this.bl_count=new R.Buf16(lt+1),this.heap=new R.Buf16(2*nt+1),r(this.heap),this.heap_len=0,this.heap_max=0,this.depth=new R.Buf16(2*nt+1),r(this.depth),this.l_buf=0,this.lit_bufsize=0,this.last_lit=0,this.d_buf=0,this.opt_len=0,this.static_len=0,this.matches=0,this.insert=0,this.bi_buf=0,this.bi_valid=0}function k(t){var e;return t&&t.state?(t.total_in=t.total_out=0,t.data_type=Q,e=t.state,e.pending=0,e.pending_out=0,e.wrap<0&&(e.wrap=-e.wrap),e.status=e.wrap?ut:wt,t.adler=2===e.wrap?0:1,e.last_flush=I,C._tr_init(e),H):i(t,K)}function y(t){var e=k(t);return e===H&&p(t.state),e}function x(t,e){return t&&t.state?2!==t.state.wrap?K:(t.state.gzhead=e,H):K}function z(t,e,a,n,r,s){if(!t)return K;var o=1;if(e===Y&&(e=6),n<0?(o=0,n=-n):n>15&&(o=2,n-=16),r<1||r>$||a!==V||n<8||n>15||e<0||e>9||s<0||s>W)return i(t,K);8===n&&(n=9);var l=new v;return t.state=l,l.strm=t,l.wrap=o,l.gzhead=null,l.w_bits=n,l.w_size=1<L||e<0)return t?i(t,K):K;if(o=t.state,!t.output||!t.input&&0!==t.avail_in||o.status===pt&&e!==F)return i(t,0===t.avail_out?P:K);if(o.strm=t,a=o.last_flush,o.last_flush=e,o.status===ut)if(2===o.wrap)t.adler=0,l(o,31),l(o,139),l(o,8),o.gzhead?(l(o,(o.gzhead.text?1:0)+(o.gzhead.hcrc?2:0)+(o.gzhead.extra?4:0)+(o.gzhead.name?8:0)+(o.gzhead.comment?16:0)),l(o,255&o.gzhead.time),l(o,o.gzhead.time>>8&255),l(o,o.gzhead.time>>16&255),l(o,o.gzhead.time>>24&255),l(o,9===o.level?2:o.strategy>=G||o.level<2?4:0),l(o,255&o.gzhead.os),o.gzhead.extra&&o.gzhead.extra.length&&(l(o,255&o.gzhead.extra.length),l(o,o.gzhead.extra.length>>8&255)),o.gzhead.hcrc&&(t.adler=O(t.adler,o.pending_buf,o.pending,0)),o.gzindex=0,o.status=ct):(l(o,0),l(o,0),l(o,0),l(o,0),l(o,0),l(o,9===o.level?2:o.strategy>=G||o.level<2?4:0),l(o,zt),o.status=wt);else{var _=V+(o.w_bits-8<<4)<<8,u=-1;u=o.strategy>=G||o.level<2?0:o.level<6?1:6===o.level?2:3,_|=u<<6,0!==o.strstart&&(_|=_t),_+=31-_%31,o.status=wt,h(o,_),0!==o.strstart&&(h(o,t.adler>>>16),h(o,65535&t.adler)),t.adler=1}if(o.status===ct)if(o.gzhead.extra){for(d=o.pending;o.gzindex<(65535&o.gzhead.extra.length)&&(o.pending!==o.pending_buf_size||(o.gzhead.hcrc&&o.pending>d&&(t.adler=O(t.adler,o.pending_buf,o.pending-d,d)),s(t),d=o.pending,o.pending!==o.pending_buf_size));)l(o,255&o.gzhead.extra[o.gzindex]),o.gzindex++;o.gzhead.hcrc&&o.pending>d&&(t.adler=O(t.adler,o.pending_buf,o.pending-d,d)),o.gzindex===o.gzhead.extra.length&&(o.gzindex=0,o.status=bt)}else o.status=bt;if(o.status===bt)if(o.gzhead.name){d=o.pending;do{if(o.pending===o.pending_buf_size&&(o.gzhead.hcrc&&o.pending>d&&(t.adler=O(t.adler,o.pending_buf,o.pending-d,d)),s(t),d=o.pending,o.pending===o.pending_buf_size)){f=1;break}f=o.gzindexd&&(t.adler=O(t.adler,o.pending_buf,o.pending-d,d)),0===f&&(o.gzindex=0,o.status=gt)}else o.status=gt;if(o.status===gt)if(o.gzhead.comment){d=o.pending;do{if(o.pending===o.pending_buf_size&&(o.gzhead.hcrc&&o.pending>d&&(t.adler=O(t.adler,o.pending_buf,o.pending-d,d)),s(t),d=o.pending,o.pending===o.pending_buf_size)){f=1;break}f=o.gzindexd&&(t.adler=O(t.adler,o.pending_buf,o.pending-d,d)),0===f&&(o.status=mt)}else o.status=mt;if(o.status===mt&&(o.gzhead.hcrc?(o.pending+2>o.pending_buf_size&&s(t),o.pending+2<=o.pending_buf_size&&(l(o,255&t.adler),l(o,t.adler>>8&255),t.adler=0,o.status=wt)):o.status=wt),0!==o.pending){if(s(t),0===t.avail_out)return o.last_flush=-1,H}else if(0===t.avail_in&&n(e)<=n(a)&&e!==F)return i(t,P);if(o.status===pt&&0!==t.avail_in)return i(t,P);if(0!==t.avail_in||0!==o.lookahead||e!==I&&o.status!==pt){var c=o.strategy===G?m(o,e):o.strategy===X?g(o,e):Z[o.level].func(o,e);if(c!==yt&&c!==xt||(o.status=pt),c===vt||c===yt)return 0===t.avail_out&&(o.last_flush=-1),H;if(c===kt&&(e===U?C._tr_align(o):e!==L&&(C._tr_stored_block(o,0,0,!1),e===T&&(r(o.head),0===o.lookahead&&(o.strstart=0,o.block_start=0,o.insert=0))),s(t),0===t.avail_out))return o.last_flush=-1,H}return e!==F?H:o.wrap<=0?j:(2===o.wrap?(l(o,255&t.adler),l(o,t.adler>>8&255),l(o,t.adler>>16&255),l(o,t.adler>>24&255),l(o,255&t.total_in),l(o,t.total_in>>8&255),l(o,t.total_in>>16&255),l(o,t.total_in>>24&255)):(h(o,t.adler>>>16),h(o,65535&t.adler)),s(t),o.wrap>0&&(o.wrap=-o.wrap),0!==o.pending?H:j)}function E(t){var e;return t&&t.state?(e=t.state.status,e!==ut&&e!==ct&&e!==bt&&e!==gt&&e!==mt&&e!==wt&&e!==pt?i(t,K):(t.state=null,e===wt?i(t,M):H)):K}function A(t,e){var a,i,n,s,o,l,h,d,f=e.length;if(!t||!t.state)return K;if(a=t.state,s=a.wrap,2===s||1===s&&a.status!==ut||a.lookahead)return K;for(1===s&&(t.adler=N(t.adler,e,f,0)),a.wrap=0,f>=a.w_size&&(0===s&&(r(a.head),a.strstart=0,a.block_start=0,a.insert=0),d=new R.Buf8(a.w_size),R.arraySet(d,e,f-a.w_size,a.w_size,0),e=d,f=a.w_size),o=t.avail_in,l=t.next_in,h=t.input,t.avail_in=f,t.next_in=0,t.input=e,_(a);a.lookahead>=ht;){i=a.strstart,n=a.lookahead-(ht-1);do a.ins_h=(a.ins_h<>>24,b>>>=y,g-=y,y=k>>>16&255,0===y)A[o++]=65535&k;else{if(!(16&y)){if(0===(64&y)){k=m[(65535&k)+(b&(1<>>=y,g-=y),g<15&&(b+=E[r++]<>>24,b>>>=y,g-=y,y=k>>>16&255,!(16&y)){if(0===(64&y)){k=w[(65535&k)+(b&(1<d){t.msg="invalid distance too far back",a.mode=i;break t}if(b>>>=y,g-=y,y=o-l,z>y){if(y=z-y,y>_&&a.sane){t.msg="invalid distance too far back",a.mode=i;break t}if(B=0,S=c,0===u){if(B+=f-y,y2;)A[o++]=S[B++],A[o++]=S[B++],A[o++]=S[B++],x-=3;x&&(A[o++]=S[B++],x>1&&(A[o++]=S[B++]))}else{B=o-z;do A[o++]=A[B++],A[o++]=A[B++],A[o++]=A[B++],x-=3;while(x>2);x&&(A[o++]=A[B++],x>1&&(A[o++]=A[B++]))}break}}break}}while(r>3,r-=x,g-=x<<3,b&=(1<>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24)}function n(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new w.Buf16(320),this.work=new w.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function r(t){var e;return t&&t.state?(e=t.state,t.total_in=t.total_out=e.total=0,t.msg="",e.wrap&&(t.adler=1&e.wrap),e.mode=T,e.last=0,e.havedict=0,e.dmax=32768,e.head=null,e.hold=0,e.bits=0,e.lencode=e.lendyn=new w.Buf32(bt),e.distcode=e.distdyn=new w.Buf32(gt),e.sane=1,e.back=-1,Z):N}function s(t){var e;return t&&t.state?(e=t.state,e.wsize=0,e.whave=0,e.wnext=0,r(t)):N}function o(t,e){var a,i;return t&&t.state?(i=t.state,e<0?(a=0,e=-e):(a=(e>>4)+1,e<48&&(e&=15)),e&&(e<8||e>15)?N:(null!==i.window&&i.wbits!==e&&(i.window=null),i.wrap=a,i.wbits=e,s(t))):N}function l(t,e){var a,i;return t?(i=new n,t.state=i,i.window=null,a=o(t,e),a!==Z&&(t.state=null),a):N}function h(t){return l(t,wt)}function d(t){if(pt){var e;for(g=new w.Buf32(512),m=new w.Buf32(32),e=0;e<144;)t.lens[e++]=8;for(;e<256;)t.lens[e++]=9;for(;e<280;)t.lens[e++]=7;for(;e<288;)t.lens[e++]=8;for(y(z,t.lens,0,288,g,0,t.work,{bits:9}),e=0;e<32;)t.lens[e++]=5;y(B,t.lens,0,32,m,0,t.work,{bits:5}),pt=!1}t.lencode=g,t.lenbits=9,t.distcode=m,t.distbits=5}function f(t,e,a,i){var n,r=t.state;return null===r.window&&(r.wsize=1<=r.wsize?(w.arraySet(r.window,e,a-r.wsize,r.wsize,0),r.wnext=0,r.whave=r.wsize):(n=r.wsize-r.wnext,n>i&&(n=i),w.arraySet(r.window,e,a-i,n,r.wnext),i-=n,i?(w.arraySet(r.window,e,a-i,i,0),r.wnext=i,r.whave=r.wsize):(r.wnext+=n,r.wnext===r.wsize&&(r.wnext=0),r.whave>>8&255,a.check=v(a.check,Et,2,0),_=0,u=0,a.mode=F;break}if(a.flags=0,a.head&&(a.head.done=!1),!(1&a.wrap)||(((255&_)<<8)+(_>>8))%31){t.msg="incorrect header check",a.mode=_t;break}if((15&_)!==U){t.msg="unknown compression method",a.mode=_t;break}if(_>>>=4,u-=4,yt=(15&_)+8,0===a.wbits)a.wbits=yt;else if(yt>a.wbits){t.msg="invalid window size",a.mode=_t;break}a.dmax=1<>8&1),512&a.flags&&(Et[0]=255&_,Et[1]=_>>>8&255,a.check=v(a.check,Et,2,0)),_=0,u=0,a.mode=L;case L:for(;u<32;){if(0===l)break t;l--,_+=n[s++]<>>8&255,Et[2]=_>>>16&255,Et[3]=_>>>24&255,a.check=v(a.check,Et,4,0)),_=0,u=0,a.mode=H;case H:for(;u<16;){if(0===l)break t;l--,_+=n[s++]<>8),512&a.flags&&(Et[0]=255&_,Et[1]=_>>>8&255,a.check=v(a.check,Et,2,0)),_=0,u=0,a.mode=j;case j:if(1024&a.flags){for(;u<16;){if(0===l)break t;l--,_+=n[s++]<>>8&255,a.check=v(a.check,Et,2,0)),_=0,u=0}else a.head&&(a.head.extra=null);a.mode=K;case K:if(1024&a.flags&&(g=a.length,g>l&&(g=l),g&&(a.head&&(yt=a.head.extra_len-a.length,a.head.extra||(a.head.extra=new Array(a.head.extra_len)),w.arraySet(a.head.extra,n,s,g,yt)),512&a.flags&&(a.check=v(a.check,n,g,s)),l-=g,s+=g,a.length-=g),a.length))break t;a.length=0,a.mode=M;case M:if(2048&a.flags){if(0===l)break t;g=0;do yt=n[s+g++],a.head&&yt&&a.length<65536&&(a.head.name+=String.fromCharCode(yt));while(yt&&g>9&1,a.head.done=!0),t.adler=a.check=0,a.mode=X;break;case q:for(;u<32;){if(0===l)break t;l--,_+=n[s++]<>>=7&u,u-=7&u,a.mode=ht;break}for(;u<3;){if(0===l)break t;l--,_+=n[s++]<>>=1,u-=1,3&_){case 0:a.mode=J;break;case 1:if(d(a),a.mode=at,e===A){_>>>=2,u-=2;break t}break;case 2:a.mode=$;break;case 3:t.msg="invalid block type",a.mode=_t}_>>>=2,u-=2;break;case J:for(_>>>=7&u,u-=7&u;u<32;){if(0===l)break t;l--,_+=n[s++]<>>16^65535)){t.msg="invalid stored block lengths",a.mode=_t;break}if(a.length=65535&_,_=0,u=0,a.mode=Q,e===A)break t;case Q:a.mode=V;case V:if(g=a.length){if(g>l&&(g=l),g>h&&(g=h),0===g)break t;w.arraySet(r,n,s,g,o),l-=g,s+=g,h-=g,o+=g,a.length-=g;break}a.mode=X;break;case $:for(;u<14;){if(0===l)break t; 3 | l--,_+=n[s++]<>>=5,u-=5,a.ndist=(31&_)+1,_>>>=5,u-=5,a.ncode=(15&_)+4,_>>>=4,u-=4,a.nlen>286||a.ndist>30){t.msg="too many length or distance symbols",a.mode=_t;break}a.have=0,a.mode=tt;case tt:for(;a.have>>=3,u-=3}for(;a.have<19;)a.lens[At[a.have++]]=0;if(a.lencode=a.lendyn,a.lenbits=7,zt={bits:a.lenbits},xt=y(x,a.lens,0,19,a.lencode,0,a.work,zt),a.lenbits=zt.bits,xt){t.msg="invalid code lengths set",a.mode=_t;break}a.have=0,a.mode=et;case et:for(;a.have>>24,mt=St>>>16&255,wt=65535&St,!(gt<=u);){if(0===l)break t;l--,_+=n[s++]<>>=gt,u-=gt,a.lens[a.have++]=wt;else{if(16===wt){for(Bt=gt+2;u>>=gt,u-=gt,0===a.have){t.msg="invalid bit length repeat",a.mode=_t;break}yt=a.lens[a.have-1],g=3+(3&_),_>>>=2,u-=2}else if(17===wt){for(Bt=gt+3;u>>=gt,u-=gt,yt=0,g=3+(7&_),_>>>=3,u-=3}else{for(Bt=gt+7;u>>=gt,u-=gt,yt=0,g=11+(127&_),_>>>=7,u-=7}if(a.have+g>a.nlen+a.ndist){t.msg="invalid bit length repeat",a.mode=_t;break}for(;g--;)a.lens[a.have++]=yt}}if(a.mode===_t)break;if(0===a.lens[256]){t.msg="invalid code -- missing end-of-block",a.mode=_t;break}if(a.lenbits=9,zt={bits:a.lenbits},xt=y(z,a.lens,0,a.nlen,a.lencode,0,a.work,zt),a.lenbits=zt.bits,xt){t.msg="invalid literal/lengths set",a.mode=_t;break}if(a.distbits=6,a.distcode=a.distdyn,zt={bits:a.distbits},xt=y(B,a.lens,a.nlen,a.ndist,a.distcode,0,a.work,zt),a.distbits=zt.bits,xt){t.msg="invalid distances set",a.mode=_t;break}if(a.mode=at,e===A)break t;case at:a.mode=it;case it:if(l>=6&&h>=258){t.next_out=o,t.avail_out=h,t.next_in=s,t.avail_in=l,a.hold=_,a.bits=u,k(t,b),o=t.next_out,r=t.output,h=t.avail_out,s=t.next_in,n=t.input,l=t.avail_in,_=a.hold,u=a.bits,a.mode===X&&(a.back=-1);break}for(a.back=0;St=a.lencode[_&(1<>>24,mt=St>>>16&255,wt=65535&St,!(gt<=u);){if(0===l)break t;l--,_+=n[s++]<>pt)],gt=St>>>24,mt=St>>>16&255,wt=65535&St,!(pt+gt<=u);){if(0===l)break t;l--,_+=n[s++]<>>=pt,u-=pt,a.back+=pt}if(_>>>=gt,u-=gt,a.back+=gt,a.length=wt,0===mt){a.mode=lt;break}if(32&mt){a.back=-1,a.mode=X;break}if(64&mt){t.msg="invalid literal/length code",a.mode=_t;break}a.extra=15&mt,a.mode=nt;case nt:if(a.extra){for(Bt=a.extra;u>>=a.extra,u-=a.extra,a.back+=a.extra}a.was=a.length,a.mode=rt;case rt:for(;St=a.distcode[_&(1<>>24,mt=St>>>16&255,wt=65535&St,!(gt<=u);){if(0===l)break t;l--,_+=n[s++]<>pt)],gt=St>>>24,mt=St>>>16&255,wt=65535&St,!(pt+gt<=u);){if(0===l)break t;l--,_+=n[s++]<>>=pt,u-=pt,a.back+=pt}if(_>>>=gt,u-=gt,a.back+=gt,64&mt){t.msg="invalid distance code",a.mode=_t;break}a.offset=wt,a.extra=15&mt,a.mode=st;case st:if(a.extra){for(Bt=a.extra;u>>=a.extra,u-=a.extra,a.back+=a.extra}if(a.offset>a.dmax){t.msg="invalid distance too far back",a.mode=_t;break}a.mode=ot;case ot:if(0===h)break t;if(g=b-h,a.offset>g){if(g=a.offset-g,g>a.whave&&a.sane){t.msg="invalid distance too far back",a.mode=_t;break}g>a.wnext?(g-=a.wnext,m=a.wsize-g):m=a.wnext-g,g>a.length&&(g=a.length),bt=a.window}else bt=r,m=o-a.offset,g=a.length;g>h&&(g=h),h-=g,a.length-=g;do r[o++]=bt[m++];while(--g);0===a.length&&(a.mode=it);break;case lt:if(0===h)break t;r[o++]=a.length,h--,a.mode=it;break;case ht:if(a.wrap){for(;u<32;){if(0===l)break t;l--,_|=n[s++]<=1&&0===j[N];N--);if(O>N&&(O=N),0===N)return b[g++]=20971520,b[g++]=20971520,w.bits=1,0;for(C=1;C0&&(t===o||1!==N))return-1;for(K[1]=0,Z=1;Zr||t===h&&T>s)return 1;for(var Y=0;;){Y++,B=Z-I,m[R]z?(S=M[P+m[R]],E=L[H+m[R]]):(S=96,E=0),p=1<>I)+v]=B<<24|S<<16|E|0;while(0!==v);for(p=1<>=1;if(0!==p?(F&=p-1,F+=p):F=0,R++,0===--j[Z]){if(Z===N)break;Z=e[a+m[R]]}if(Z>O&&(F&y)!==k){for(0===I&&(I=O),x+=C,D=Z-I,U=1<r||t===h&&T>s)return 1;k=F&y,b[k]=O<<24|D<<16|x-g|0}}return 0!==F&&(b[x+F]=Z-I<<24|64<<16|0),w.bits=O,0}},{"../utils/common":3}],13:[function(t,e,a){"use strict";e.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],14:[function(t,e,a){"use strict";function i(t){for(var e=t.length;--e>=0;)t[e]=0}function n(t,e,a,i,n){this.static_tree=t,this.extra_bits=e,this.extra_base=a,this.elems=i,this.max_length=n,this.has_stree=t&&t.length}function r(t,e){this.dyn_tree=t,this.max_code=0,this.stat_desc=e}function s(t){return t<256?lt[t]:lt[256+(t>>>7)]}function o(t,e){t.pending_buf[t.pending++]=255&e,t.pending_buf[t.pending++]=e>>>8&255}function l(t,e,a){t.bi_valid>W-a?(t.bi_buf|=e<>W-t.bi_valid,t.bi_valid+=a-W):(t.bi_buf|=e<>>=1,a<<=1;while(--e>0);return a>>>1}function f(t){16===t.bi_valid?(o(t,t.bi_buf),t.bi_buf=0,t.bi_valid=0):t.bi_valid>=8&&(t.pending_buf[t.pending++]=255&t.bi_buf,t.bi_buf>>=8,t.bi_valid-=8)}function _(t,e){var a,i,n,r,s,o,l=e.dyn_tree,h=e.max_code,d=e.stat_desc.static_tree,f=e.stat_desc.has_stree,_=e.stat_desc.extra_bits,u=e.stat_desc.extra_base,c=e.stat_desc.max_length,b=0;for(r=0;r<=X;r++)t.bl_count[r]=0;for(l[2*t.heap[t.heap_max]+1]=0,a=t.heap_max+1;ac&&(r=c,b++),l[2*i+1]=r,i>h||(t.bl_count[r]++,s=0,i>=u&&(s=_[i-u]),o=l[2*i],t.opt_len+=o*(r+s),f&&(t.static_len+=o*(d[2*i+1]+s)));if(0!==b){do{for(r=c-1;0===t.bl_count[r];)r--;t.bl_count[r]--,t.bl_count[r+1]+=2,t.bl_count[c]--,b-=2}while(b>0);for(r=c;0!==r;r--)for(i=t.bl_count[r];0!==i;)n=t.heap[--a],n>h||(l[2*n+1]!==r&&(t.opt_len+=(r-l[2*n+1])*l[2*n],l[2*n+1]=r),i--)}}function u(t,e,a){var i,n,r=new Array(X+1),s=0;for(i=1;i<=X;i++)r[i]=s=s+a[i-1]<<1;for(n=0;n<=e;n++){var o=t[2*n+1];0!==o&&(t[2*n]=d(r[o]++,o))}}function c(){var t,e,a,i,r,s=new Array(X+1);for(a=0,i=0;i>=7;i8?o(t,t.bi_buf):t.bi_valid>0&&(t.pending_buf[t.pending++]=t.bi_buf),t.bi_buf=0,t.bi_valid=0}function m(t,e,a,i){g(t),i&&(o(t,a),o(t,~a)),N.arraySet(t.pending_buf,t.window,e,a,t.pending),t.pending+=a}function w(t,e,a,i){var n=2*e,r=2*a;return t[n]>1;a>=1;a--)p(t,r,a);n=l;do a=t.heap[1],t.heap[1]=t.heap[t.heap_len--],p(t,r,1),i=t.heap[1],t.heap[--t.heap_max]=a,t.heap[--t.heap_max]=i,r[2*n]=r[2*a]+r[2*i],t.depth[n]=(t.depth[a]>=t.depth[i]?t.depth[a]:t.depth[i])+1,r[2*a+1]=r[2*i+1]=n,t.heap[1]=n++,p(t,r,1);while(t.heap_len>=2);t.heap[--t.heap_max]=t.heap[1],_(t,e),u(r,h,t.bl_count)}function y(t,e,a){var i,n,r=-1,s=e[1],o=0,l=7,h=4;for(0===s&&(l=138,h=3),e[2*(a+1)+1]=65535,i=0;i<=a;i++)n=s,s=e[2*(i+1)+1],++o=3&&0===t.bl_tree[2*nt[e]+1];e--);return t.opt_len+=3*(e+1)+5+5+4,e}function B(t,e,a,i){var n;for(l(t,e-257,5),l(t,a-1,5),l(t,i-4,4),n=0;n>>=1)if(1&a&&0!==t.dyn_ltree[2*e])return D;if(0!==t.dyn_ltree[18]||0!==t.dyn_ltree[20]||0!==t.dyn_ltree[26])return I;for(e=32;e0?(t.strm.data_type===U&&(t.strm.data_type=S(t)),k(t,t.l_desc),k(t,t.d_desc),s=z(t),n=t.opt_len+3+7>>>3,r=t.static_len+3+7>>>3,r<=n&&(n=r)):n=r=a+5,a+4<=n&&e!==-1?A(t,e,a,i):t.strategy===O||r===n?(l(t,(F<<1)+(i?1:0),3),v(t,st,ot)):(l(t,(L<<1)+(i?1:0),3),B(t,t.l_desc.max_code+1,t.d_desc.max_code+1,s+1),v(t,t.dyn_ltree,t.dyn_dtree)),b(t),i&&g(t)}function C(t,e,a){return t.pending_buf[t.d_buf+2*t.last_lit]=e>>>8&255,t.pending_buf[t.d_buf+2*t.last_lit+1]=255&e,t.pending_buf[t.l_buf+t.last_lit]=255&a,t.last_lit++,0===e?t.dyn_ltree[2*a]++:(t.matches++,e--,t.dyn_ltree[2*(ht[a]+M+1)]++,t.dyn_dtree[2*s(e)]++),t.last_lit===t.lit_bufsize-1}var N=t("../utils/common"),O=4,D=0,I=1,U=2,T=0,F=1,L=2,H=3,j=258,K=29,M=256,P=M+1+K,Y=30,q=19,G=2*P+1,X=15,W=16,J=7,Q=256,V=16,$=17,tt=18,et=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],at=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],it=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],nt=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],rt=512,st=new Array(2*(P+2));i(st);var ot=new Array(2*Y);i(ot);var lt=new Array(rt);i(lt);var ht=new Array(j-H+1);i(ht);var dt=new Array(K);i(dt);var ft=new Array(Y);i(ft);var _t,ut,ct,bt=!1;a._tr_init=E,a._tr_stored_block=A,a._tr_flush_block=R,a._tr_tally=C,a._tr_align=Z},{"../utils/common":3}],15:[function(t,e,a){"use strict";function i(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}e.exports=i},{}],"/":[function(t,e,a){"use strict";var i=t("./lib/utils/common").assign,n=t("./lib/deflate"),r=t("./lib/inflate"),s=t("./lib/zlib/constants"),o={};i(o,n,r,s),e.exports=o},{"./lib/deflate":1,"./lib/inflate":2,"./lib/utils/common":3,"./lib/zlib/constants":6}]},{},[])("/")}); 4 | --------------------------------------------------------------------------------