├── .gitattributes ├── .github └── workflows │ └── release.yml ├── .gitignore ├── .goreleaser.yml ├── README.md ├── dark_dmzj.go ├── go.mod ├── hotupdate.go └── public ├── dmzj.css └── index.html /.gitattributes: -------------------------------------------------------------------------------- 1 | /public/*.html linguist-detectable=false 2 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: goreleaser 2 | 3 | on: 4 | push: 5 | 6 | jobs: 7 | goreleaser: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v1 12 | - name: Set up Go 13 | uses: actions/setup-go@v1 14 | with: 15 | go-version: "1.13.x" 16 | - name: Run GoReleaser 17 | uses: goreleaser/goreleaser-action@v1 18 | with: 19 | version: latest 20 | args: release 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | /go.sum 3 | /dark_dmzj 4 | /public/data.json 5 | /test 6 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | builds: 2 | - env: 3 | - CGO_ENABLED=0 4 | goos: 5 | - linux 6 | - darwin 7 | - windows 8 | goarch: 9 | - 386 10 | - amd64 11 | - arm 12 | - arm64 13 | checksum: 14 | name_template: "{{ .ProjectName }}_checksums.txt" 15 | archives: 16 | - name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" 17 | format_overrides: 18 | - goos: windows 19 | format: zip 20 | files: 21 | - README.md 22 | - public/**/* 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dark-dmzj 2 | 3 | 方便得浏览动漫之家藏起来的漫画. [dark-dmzj.hloli.net](https://dark-dmzj.hloli.net) 4 | 5 | ## usage 6 | 1. 下载安装动漫之家手机APP. 7 | 2. 手机浏览器打开 [https://dark-dmzj.hloli.net](https://dark-dmzj.hloli.net). 8 | 9 |  10 | 11 |  12 | -------------------------------------------------------------------------------- /dark_dmzj.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/tls" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/labstack/echo" 8 | "github.com/labstack/echo/middleware" 9 | "github.com/tidwall/gjson" 10 | "gopkg.in/cheggaaa/pb.v1" 11 | "io" 12 | "io/ioutil" 13 | "math/rand" 14 | "net/http" 15 | "os" 16 | "path/filepath" 17 | "sort" 18 | "time" 19 | ) 20 | 21 | var client *http.Client 22 | var bar *pb.ProgressBar 23 | var isDownloading bool 24 | 25 | type dmzjBook struct { 26 | ID uint64 `json:"id"` 27 | Title string `json:"title"` 28 | IsLong int64 `json:"islong"` 29 | Authors []string `json:"authors"` 30 | Types []string `json:"types"` 31 | Status []string `json:"status"` 32 | Cover string `json:"cover"` 33 | LastUpdateChapterName string `json:"last_update_chapter_name"` 34 | LastUpdateChapterID uint64 `json:"last_update_chapter_id"` 35 | LastUpdateTime int64 `json:"last_updatetime"` 36 | } 37 | 38 | func init() { 39 | client = &http.Client{ 40 | Transport: &http.Transport{ 41 | MaxIdleConnsPerHost: 256, 42 | MaxIdleConns: 256, 43 | ResponseHeaderTimeout: 10 * time.Second, 44 | TLSHandshakeTimeout: 10 * time.Second, 45 | TLSNextProto: make(map[string]func(authority string, c *tls.Conn) http.RoundTripper), 46 | }, 47 | Timeout: time.Second * 10, 48 | } 49 | 50 | ex, err := os.Executable() 51 | if err != nil { 52 | panic(err) 53 | } 54 | exPath := filepath.Dir(ex) 55 | if _, err := os.Stat(filepath.Join(exPath, "public", "index.html")); !os.IsNotExist(err) { 56 | if err := os.Chdir(exPath); err != nil { 57 | panic(err) 58 | } 59 | } 60 | } 61 | 62 | func apiWithRetry(id int, try int) string { 63 | for i := 0; i < try; i++ { 64 | domains := []string{"v3api.dmzj1.com/comic/comic_"} 65 | res, err := client.Get(fmt.Sprintf("http://%s%d.json", domains[rand.Intn(1)], id)) 66 | resCk, errCk := client.Get(fmt.Sprintf("https://api.m.dmzj.com/info/%d.html", id)) 67 | if err == nil { 68 | defer res.Body.Close() 69 | defer io.Copy(ioutil.Discard, res.Body) 70 | } 71 | if errCk == nil { 72 | defer resCk.Body.Close() 73 | defer io.Copy(ioutil.Discard, resCk.Body) 74 | } 75 | if err == nil && res.StatusCode == 200 { 76 | body, _ := ioutil.ReadAll(res.Body) 77 | if errCk == nil && resCk.StatusCode == 200 { 78 | bodyCk, _ := ioutil.ReadAll(resCk.Body) 79 | if len(bodyCk) > 1024 { 80 | return "" 81 | } 82 | return string(body) 83 | } 84 | } 85 | } 86 | return "" 87 | } 88 | 89 | func getItem(id int, c chan<- string) { 90 | c <- apiWithRetry(id, 5) 91 | bar.Increment() 92 | } 93 | 94 | func arrayMap(vs []string, f func(string) []string) [][]string { 95 | vsm := make([][]string, len(vs)) 96 | for i, v := range vs { 97 | vsm[i] = f(v) 98 | } 99 | return vsm 100 | } 101 | 102 | func downloadBooks() { 103 | if isDownloading { 104 | return 105 | } 106 | isDownloading = true 107 | defer func() { isDownloading = false }() 108 | 109 | MaxRoutines := 50 110 | MaxBooks := 70000 111 | 112 | bar = pb.New(MaxBooks - 1).Prefix("Updating ") 113 | bar.SetWidth(60) 114 | bar.ShowTimeLeft = true 115 | bar.ShowCounters = false 116 | bar.ShowSpeed = true 117 | bar.Start() 118 | defer bar.FinishPrint("Finish!") 119 | 120 | c := make(chan string, MaxBooks) 121 | jobs := make(chan int, MaxBooks) 122 | for i := 0; i < MaxRoutines; i++ { 123 | go func() { 124 | for e := range jobs { 125 | getItem(e, c) 126 | } 127 | }() 128 | } 129 | for i := 1; i < MaxBooks; i++ { 130 | jobs <- i 131 | } 132 | 133 | items := []dmzjBook{} 134 | for p := 1; p < MaxBooks; p++ { 135 | dat := gjson.Parse(<-c) 136 | if dat.Get("id").Exists() { 137 | tags := arrayMap([]string{"authors", "types", "status"}, func(v string) []string { 138 | tag := []string{} 139 | for _, e := range dat.Get(v).Array() { 140 | tag = append(tag, e.Get("tag_name").String()) 141 | } 142 | return tag 143 | }) 144 | items = append(items, dmzjBook{ 145 | ID: dat.Get("id").Uint(), 146 | Title: dat.Get("title").String(), 147 | IsLong: dat.Get("islong").Int(), 148 | Authors: tags[0], 149 | Types: tags[1], 150 | Status: tags[2], 151 | Cover: dat.Get("cover").String(), 152 | LastUpdateChapterName: dat.Get("chapters.0.data.0.chapter_title").String(), 153 | LastUpdateChapterID: dat.Get("chapters.0.data.0.chapter_id").Uint(), 154 | LastUpdateTime: dat.Get("last_updatetime").Int(), 155 | }) 156 | } 157 | } 158 | 159 | sort.Slice(items, func(a, b int) bool { 160 | return items[a].LastUpdateTime > items[b].LastUpdateTime 161 | }) 162 | 163 | jsonDat, _ := json.Marshal(items) 164 | ioutil.WriteFile("public/data.json", jsonDat, 0644) 165 | } 166 | 167 | func main() { 168 | go func() { 169 | time.Sleep(1 * time.Second) 170 | downloadBooks() 171 | }() 172 | 173 | e := echo.New() 174 | e.HideBanner = true 175 | e.Static("/", "public") 176 | e.Use(middleware.GzipWithConfig(middleware.GzipConfig{ 177 | Level: 5, 178 | })) 179 | e.GET("/webpic/*", func(c echo.Context) error { 180 | req, _ := http.NewRequest("GET", fmt.Sprintf("http://images.dmzj.com%s", c.Request().URL.Path), nil) 181 | req.Header.Set("Referer", "https://m.dmzj.com/") 182 | res, err := client.Do(req) 183 | if err != nil { 184 | return c.NoContent(http.StatusBadGateway) 185 | } 186 | defer res.Body.Close() 187 | data, _ := ioutil.ReadAll(res.Body) 188 | return c.Blob(res.StatusCode, res.Header.Get("Content-Type"), data) 189 | }) 190 | e.Logger.Fatal(e.Start(":7777")) 191 | } 192 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/torta/dark-dmzj 2 | 3 | require ( 4 | github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect 5 | github.com/fatih/color v1.7.0 // indirect 6 | github.com/labstack/echo v3.3.10+incompatible 7 | github.com/labstack/gommon v0.2.8 // indirect 8 | github.com/mattn/go-colorable v0.0.9 // indirect 9 | github.com/mattn/go-isatty v0.0.4 // indirect 10 | github.com/mattn/go-runewidth v0.0.4 // indirect 11 | github.com/stretchr/testify v1.3.0 // indirect 12 | github.com/tidwall/gjson v1.1.5 13 | github.com/tidwall/match v1.0.1 // indirect 14 | github.com/valyala/bytebufferpool v1.0.0 // indirect 15 | github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 // indirect 16 | golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613 // indirect 17 | golang.org/x/sys v0.0.0-20190130150945-aca44879d564 // indirect 18 | gopkg.in/cheggaaa/pb.v1 v1.0.27 19 | ) 20 | -------------------------------------------------------------------------------- /hotupdate.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package main 4 | 5 | import ( 6 | "os" 7 | "os/signal" 8 | "syscall" 9 | ) 10 | 11 | func init() { 12 | c := make(chan os.Signal, 1) 13 | signal.Notify(c, syscall.SIGUSR1) 14 | go func() { 15 | for { 16 | <-c 17 | downloadBooks() 18 | } 19 | }() 20 | } 21 | -------------------------------------------------------------------------------- /public/dmzj.css: -------------------------------------------------------------------------------- 1 | body,button,dd,dl,dt,fieldset,h1,h2,h3,h4,h5,h6,hr,input,lengend,li,ol,p,pre,td,textarea,th,ul{margin:0;padding:0}body,html{height:100%}body{background:#f5f5f5;font-family:"PingFang SC","Microsoft YaHei","微软雅黑",SimSun,"宋体",Arial,STHeiti,"华文黑体",Helvetica,Tahoma,Arial sans-serif}body,button,input,select,textarea{font-size:12px}ol,ul{list-style:none}a{text-decoration:none;cursor:pointer;outline:0}a:hover{text-decoration:none}fieldset,img{border:none}button,input,select,textarea{font-size:100%}.header{height:46px;background-size:100% 2px;background-color:#fff}.header .serCh{display:none;width:100%;height:44px;background:#fff;position:absolute;left:0;top:0;z-index:5}.serChinputBox{margin-right:92px;height:10px}.searInput{-webkit-appearance:none;width:100%;float:left;height:30px;border:1px solid #cbcbcb;margin:8px 0 0 10px;border-radius:2px 0 0 2px;border-right:0;background:#f5f5f5;outline:0;font-size:15px;padding:0 5px}.searBtn{width:33px;height:28px;border:1px solid #cbcbcb;float:right;margin:8px 0 0 0;border-radius:0 2px 2px 0;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAiCAMAAADmrkDzAAAAUVBMVEUAAAA1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTWDH6iCAAAAGnRSTlMA84gUz8rp4dzEPgxiWCcbBo1HRuCoSbGmIVJ8jhUAAADTSURBVDjLzZNZDsMgDEQNDVvIvrWZ+x+0UmkgTSz5t/Nlw5PMGJuyah2sUjbomlg1Hlm+ud/vBnB67ofYTdoDZr8AtYVrS9o62N9Ss8Izng/iC2o65Z3CSBeNUF3JDFa6aYUpLuDinYgO2ZFHS4xa+MMHFmK14OtHQ7NAuQiYeGJCSIFFzxM9bAoUBp4YoGRCrnK8dBZeKrgVOiZ2Xf45+fflCSrauCncUpiRyyRnoBQ6tmHo5882dBTMQ9gog+qCUD2mrRxTox5VQnj9I2JIQEx4A1Y8D2zeFlbPAAAAAElFTkSuQmCC) no-repeat center;background-size:17px 17px;background-color:#f5f5f5;border-left:0}.searClose{width:31px;height:28px;border:1px solid #cbcbcb;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATBAMAAACAfiv/AAAAIVBMVEUAAAA1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTXjvRxHAAAACnRSTlMAFNTO2BnFLii7fcpN5AAAAGdJREFUCNctzaENgDAQheGHINgGJqgiqYJgCCMgSQeoYh5mAEM6JeS/O3X5xP+0BHFH0Rb52r2ov+H8BDUpgrMEg4JBYxAeQbg6Sl195ZcrbZorbRuizRBtQ9qGgg2N04/wpNOTw/UBx1EX2JLOhUoAAAAASUVORK5CYII=) no-repeat center;background-size:10px 10px;border-radius:2px;float:right;margin:8px 10px 0 5px;background-color:#f5f5f5}.messagSjr{width:100%;position:absolute;top:46px;z-index:4;background:#fff;z-index:888}.messagSjr .keyTit li{margin:0 10px;padding:0 5px;height:40px;border-bottom:1px solid #cbcbcb;line-height:40px;font-size:14px}.UpdateList{margin-top:7px;background:#fff}.UpdateList .itemBox{height:114px;border-bottom:1px solid #cbcbcb;padding-top:10px;margin-left:10px;position:relative}.UpdateList .itemImg{width:78px;height:103px;float:left;display:block;position:relative}.UpdateList .itemImg img{border-radius:2px}.UpdateList .itemTxt{height:114px;margin-left:88px;padding-right:10px}.UpdateList .itemTxt .title{height:33px;display:block;padding-right:80px;color:#000;line-height:33px;font-size:15px;text-overflow:ellipsis;overflow:hidden}.UpdateList .itemTxt .txtItme{display:block;height:15px;line-height:15px;font-size:12px;color:#000;opacity:.9;margin:7px 0}.UpdateList .itemTxt .txtItme .pd{padding-right:5px}.UpdateList .itemTxt .txtItme .icon{float:left;display:block;width:15px;height:15px;float:left;display:block;margin-right:5px}.UpdateList .itemTxt .txtItme .icon.icon01{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAAAZlBMVEUAAABmvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP/m9P9twP/w+f+ByP9wwf9qvv/////L6f+x3f+/4//2+/+Y0v+V0f+JzP+84v/U7P/X7f/W7f+k1/+i1v/o0ERqAAAADXRSTlMA6pQE+VdMEMWArceByQzOeQAAAQZJREFUKM+Fk+mSgyAQhMULTTIcIqAx2eP9X3J1tUeSWOX3h5IG6bkypqjzRpSlaPK6yN6RrSBGtPJVrSDiQJWIRU4f5AWrFzrgAp3vTs9heE58f3sX379q7LpR/eC7+vcMV1Z1y9IpC3+L/xaH/X1d7x477eyLQzJ6XbXh8IqsJtBD7gnUs21g8HNDu/mGwAPWIoEmw9PLvhq1HtV8CoisJGYa+plhIqbcZRdNsE7bYKLbZQH128O5/4Iu2Fr0xPgIawjMrklBYiwCq7eoAiWEx5YWJBV1QHW2pKIkwaWyCygJCnqAkGiHQyo00yH5SSueNPL5GAB5E4l4k6mGEbwuI3hNR/AP2holij6C64EAAAAASUVORK5CYII=);background-size:100%}.UpdateList .itemTxt .txtItme .icon.icon02{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAAAeFBMVEUAAABmvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP/////w+P/6/f+LzP96xf+y3v/r9/+Rz/9pvv+AyP91w//m9P/a7/+94v+34P/y+v/R6//G5v+W0v/2+//f8f/K6P8CnX0IAAAAEXRSTlMA6QSS+VcQlUyA68Wtx8aBTV5wTfMAAAEBSURBVCjPhdNtc4MgDAfwABZF+7AUta5d1da2+/7fcDMFQll3/l+Id78DckcCIbJQW5FlYqsKCWm0ERhSGv2qK0KOWEUoc/yTXAZd45usvSt8m9zdi/+E7tdc1dd031Pqkeqb6zes58fpSH+3mhYDIAXrdUbKnr5CQpHop7U3z1iA8tp9017bNDawggopbTfNmnAFwulAa3K4gOypI8Y5Os6efO7xJe3dMx1+SXi6+sMrurA+xDpcTr40heypooICUx+sV/wAWSY+sgrJT9L8OmmLPsY9KPshUqG5Hcj7vmNF14558O4Rab7QiguNvDQGHL0rGcudZuER3MwjuIlH8AcPlDETmzg0tgAAAABJRU5ErkJggg==);background-size:100%}.UpdateList .itemTxt .txtItme .icon.icon03{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAAAY1BMVEUAAABmvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9mvP9wwf/p9v/a7/+Y0v/+///N6f+k1/+Mzf/4/P/s9/+54P+d1P+Ax//v+f/n9P/X7v+/4/98xv/qsHowAAAADnRSTlMA6ZT5V0wQgOvErcfGgcWY6r4AAAD0SURBVCjPhZNZFoMgDEXFuYNRBBVn97/KCqFGsae8D3P0SniQJCAl4ZtFEXuHSXBTmjE4lGfplcYGklh8piHcFBJ9wg893bW1VF03y/q6Praw4s1YlmPDK/tDbDyjq75qwaqtevSn/WdIeUnblhx5tmOGmTUlPpv8bL8r8z61cFE7mZCg7WEBK27jMqD5hw6y+WJhYyP184Fbq83Fm8LNIx06cDF+iiw+fE9CCK69I8bk8wiORkzuWgPHGh2MRAfzXUuQ/7lUT0mooOu5oCsV1NMO1EyDVEIoOVAzeVrR08j+MUClRU4wL1IiNIIvPYKv8wh+AJ7oKJ0DK8hKAAAAAElFTkSuQmCC);background-size:100%}.UpdateList .coll{width:50px;height:15px;color:#000;overflow:hidden;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE0AAABOCAMAAABSQ2ssAAAA3lBMVEUAAAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/tAD/////+/D/6K3/wCf/uxf/uA7/tgX//vn/vyP//PX/+/L/6rX/2Hj/vR3/+OX/8dD/67r/02n/zlX/+er/9uH/wzL/wi7/uhH/3In/yUj/5qn/46D/0F3/4Zn/24P/x0D/xTkRj11eAAAAKHRSTlMAUhHv1+zcuLP7+fyPSh0CVcWEP1nz6LyTcWNhKAHTubWmo9+XbifPferQzAAAAptJREFUWMPtmNd22kAQhleo0Yxp7gVsJ86MBAjRe7Od8v4vFAOHE82gEEBzwUW+y9GZj7MsK2Z/FUrsvlC8yX95snOGpesJ+ORCv7S+5eLP1/mv2cJ9TO1DTEvblp6Ef5LULTut7ZKea/EEHEQirp2rcDQDjsDQwlwZG47EzijOmQlHY54x2W0KIpC6I7I7iEhQd5aCiKT+LDajQ2T0zVY8XIEAVw9rWxZEyK5PgAEiGKtToYEQ2tIWByHiy7dGAoRIxMhCBZaaBjHSStkghq2UxUq/3sZ1DDL6PlnWJ+8jUq6P3ytAsZQygTBdq2hjG6AdUm90gGAqlQTCHN/8Gqn48zouFlif095ZpY9tICSVAkoffwKnjf1lJ2eILqvEuK2LHeBU0XGwCpwp9ljlldh810H0YAv8BEI+BB3XhwCFoK3isLbdNm9ZdoIbmw3aXGxV0Nll4+VOi3x3N0Gbg9XqIbYG1qrYDBTyijTB7BCbgzUgD66ZrRbJ9ixqizObh41DdgGoLae2nkawPYraXkRtl6I2XdR2IWqD/7YT2AX9hH+9Lyd86mXfSGVR25Oo7VrUlt+2efv/19eZ7YbbHJzta5uhw2xFbuthu1Pbx1bzf2CP2QrcNkBKt/XhrW3eh9tFypDZXrkNhv1xkwmHq06mcsatBTBbTCWJjeP5g96mvzfwPeAgkknVZE+2GTRWI/MAOLzHJBP+ZhzlTEaIowmEQSYuSymbTIPhummjOYUw6DRoK5Xmk+r+8Ek1TW9tFbeJB9F0AzLQZG+Uordd2Zu4bEogmWAUZdMV0eRHOpXacAsRuRVN80STRsEUtJRRIWSPS2izculxWTvfnWyXDHOfZNs0StvJ9u7UvZwzLFNPblL3x3XqXvxr6v4bzaRYyhqP0ToAAAAASUVORK5CYII=) no-repeat 6px 0;background-size:39px;float:right;padding-top:45px;line-height:18px;font-size:12px;opacity:.9;text-align:center;position:absolute;top:37px;right:12px}.UpdateList .coll:hover{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE4AAABOCAMAAAC5dNAvAAAA2FBMVEUAAAD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/ogD/////+vH/pw//4a3/sSf/pAX//vz/9eL/tDD/+/P/rR//5LX/rBn/+e//9+j/5rr/yWn/wVX/qxf/04b/zXf/ryT//Pf/3J3/vEj/79H/68n/4Kn/0Hz/xF3/uDz/79SHA+hiAAAAJ3RSTlMAUvy46u7Us/L43dliV0pAKB0SApUQj4Nx4cfDu6NVppGFblvepw6iItqwAAACr0lEQVRYw82Y6XKiUBBGm01Egxr3mMRk1m5AUNzX7Mm8/xuNZSo13JbJuPRUef7Rt/pYeIG6/UE6tVLxW/NL9YfRyucsS8c1WcvMZS7t69vGV7dY+gk7UdbqRt5y8J84Vt6oa2X4hIpm67gXuq1V4C9oGTyAjAZpnBt4IMY5bFEw8WDMAjDOdDwC/YzZ8EgUX0HHI9ELiV2w8GisP/txhQJcfdjaKEIbNlQyKEL+/f3QUAhto7NRCBvWlHUUQi+zexW421sUow4ABophAECO1d6euxElGd/3cE3vfqyU77r3HVTJAYCJCr2ItoiWiMuUetxHBRMAHFRY0PPKVyr9RUQPDxQt1Ga/M6ElKjgANVSZ0BtyXmgyoRfkzChglRqUWGVMQ+TMyfNSyj16ZJUSFDHBKvCIQtyC1mDKr5AXrDBBEdzEVWfE+j7XhbRmlNxeF5qJq4AGHfI+0/Fyf6D8f01oJK48Gs730d2RP6Q4UWhAVelCfx+dRz4qC1W4kdRdgyGps6Gl6kK622crUNVdQmZr+QhdBi4kdReyOhNMSV0WsiesQ8CT1mVPWJcVflCkH+Pvoi+Z9CfgUlLXAltSZ8C1pO4GqpK6KjQkdQ1osuWIwt1PARHTNcFlOo/8XXU+jZjOhSLT/aJl399F568W9MR0RSgx3ZRUuoPX8F0XvgZdUpkxXQlqTIezSddjxtmmlbm87uABma4G4Cg6TtifPn4InqZ9tk2sxwEAky1tM41pTTxFDu8x1UHg48TK6Y2Jxj1MY06xOggYynFxnu6L43TbUDkuGuoQ1RnRXvDDbJ2NeJ3Ao73wgoQNNeEBVHo8lh/eK3k8Bh4tgIsiuLKxjHBoJBtpyQZusnGgcFgpH6Vy2ocFvW3hGPr/h+TpEf6N0crkTMtJRvjVTYRfg1R+AyqRRSgxTWieAAAAAElFTkSuQmCC) no-repeat;background-size:39px} -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |{{ item.authors.join('/') }}
91 |92 | 93 | {{ type }} 94 |
95 |96 | 97 | {{ moment(item.last_updatetime * 1000).format('YYYY-MM-DD H:mm') }} 98 |
99 |