Full Code of torta/dark-dmzj for AI

master e5022717bf40 cached
10 files
22.2 KB
9.0k tokens
8 symbols
1 requests
Download .txt
Repository: torta/dark-dmzj
Branch: master
Commit: e5022717bf40
Files: 10
Total size: 22.2 KB

Directory structure:
gitextract_vpoukq8z/

├── .gitattributes
├── .github/
│   └── workflows/
│       └── release.yml
├── .gitignore
├── .goreleaser.yml
├── README.md
├── dark_dmzj.go
├── go.mod
├── hotupdate.go
└── public/
    ├── dmzj.css
    └── index.html

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
/public/*.html linguist-detectable=false


================================================
FILE: .github/workflows/release.yml
================================================
name: goreleaser

on:
  push:

jobs:
  goreleaser:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v1
      - name: Set up Go
        uses: actions/setup-go@v1
        with:
          go-version: "1.13.x"
      - name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v1
        with:
          version: latest
          args: release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .gitignore
================================================
*.exe
/go.sum
/dark_dmzj
/public/data.json
/test


================================================
FILE: .goreleaser.yml
================================================
builds:
  - env:
      - CGO_ENABLED=0
    goos:
      - linux
      - darwin
      - windows
    goarch:
      - 386
      - amd64
      - arm
      - arm64
checksum:
  name_template: "{{ .ProjectName }}_checksums.txt"
archives:
  - name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
    format_overrides:
      - goos: windows
        format: zip
    files:
      - README.md
      - public/**/*


================================================
FILE: README.md
================================================
# dark-dmzj

方便得浏览动漫之家藏起来的漫画. [dark-dmzj.hloli.net](https://dark-dmzj.hloli.net)

## usage
1. 下载安装动漫之家手机APP.
2. 手机浏览器打开 [https://dark-dmzj.hloli.net](https://dark-dmzj.hloli.net).

![gif](https://i.imgur.com/NQdMDLo.gif)

![cat](https://i.imgur.com/dtG3c3Q.jpg)


================================================
FILE: dark_dmzj.go
================================================
package main

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
	"github.com/tidwall/gjson"
	"gopkg.in/cheggaaa/pb.v1"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"time"
)

var client *http.Client
var bar *pb.ProgressBar
var isDownloading bool

type dmzjBook struct {
	ID                    uint64   `json:"id"`
	Title                 string   `json:"title"`
	IsLong                int64    `json:"islong"`
	Authors               []string `json:"authors"`
	Types                 []string `json:"types"`
	Status                []string `json:"status"`
	Cover                 string   `json:"cover"`
	LastUpdateChapterName string   `json:"last_update_chapter_name"`
	LastUpdateChapterID   uint64   `json:"last_update_chapter_id"`
	LastUpdateTime        int64    `json:"last_updatetime"`
}

func init() {
	client = &http.Client{
		Transport: &http.Transport{
			MaxIdleConnsPerHost:   256,
			MaxIdleConns:          256,
			ResponseHeaderTimeout: 10 * time.Second,
			TLSHandshakeTimeout:   10 * time.Second,
			TLSNextProto:          make(map[string]func(authority string, c *tls.Conn) http.RoundTripper),
		},
		Timeout: time.Second * 10,
	}

	ex, err := os.Executable()
	if err != nil {
		panic(err)
	}
	exPath := filepath.Dir(ex)
	if _, err := os.Stat(filepath.Join(exPath, "public", "index.html")); !os.IsNotExist(err) {
		if err := os.Chdir(exPath); err != nil {
			panic(err)
		}
	}
}

func apiWithRetry(id int, try int) string {
	for i := 0; i < try; i++ {
		domains := []string{"v3api.dmzj1.com/comic/comic_"}
		res, err := client.Get(fmt.Sprintf("http://%s%d.json", domains[rand.Intn(1)], id))
		resCk, errCk := client.Get(fmt.Sprintf("https://api.m.dmzj.com/info/%d.html", id))
		if err == nil {
			defer res.Body.Close()
			defer io.Copy(ioutil.Discard, res.Body)
		}
		if errCk == nil {
			defer resCk.Body.Close()
			defer io.Copy(ioutil.Discard, resCk.Body)
		}
		if err == nil && res.StatusCode == 200 {
			body, _ := ioutil.ReadAll(res.Body)
			if errCk == nil && resCk.StatusCode == 200 {
				bodyCk, _ := ioutil.ReadAll(resCk.Body)
				if len(bodyCk) > 1024 {
					return ""
				}
				return string(body)
			}
		}
	}
	return ""
}

func getItem(id int, c chan<- string) {
	c <- apiWithRetry(id, 5)
	bar.Increment()
}

func arrayMap(vs []string, f func(string) []string) [][]string {
	vsm := make([][]string, len(vs))
	for i, v := range vs {
		vsm[i] = f(v)
	}
	return vsm
}

func downloadBooks() {
	if isDownloading {
		return
	}
	isDownloading = true
	defer func() { isDownloading = false }()

	MaxRoutines := 50
	MaxBooks := 70000

	bar = pb.New(MaxBooks - 1).Prefix("Updating ")
	bar.SetWidth(60)
	bar.ShowTimeLeft = true
	bar.ShowCounters = false
	bar.ShowSpeed = true
	bar.Start()
	defer bar.FinishPrint("Finish!")

	c := make(chan string, MaxBooks)
	jobs := make(chan int, MaxBooks)
	for i := 0; i < MaxRoutines; i++ {
		go func() {
			for e := range jobs {
				getItem(e, c)
			}
		}()
	}
	for i := 1; i < MaxBooks; i++ {
		jobs <- i
	}

	items := []dmzjBook{}
	for p := 1; p < MaxBooks; p++ {
		dat := gjson.Parse(<-c)
		if dat.Get("id").Exists() {
			tags := arrayMap([]string{"authors", "types", "status"}, func(v string) []string {
				tag := []string{}
				for _, e := range dat.Get(v).Array() {
					tag = append(tag, e.Get("tag_name").String())
				}
				return tag
			})
			items = append(items, dmzjBook{
				ID:                    dat.Get("id").Uint(),
				Title:                 dat.Get("title").String(),
				IsLong:                dat.Get("islong").Int(),
				Authors:               tags[0],
				Types:                 tags[1],
				Status:                tags[2],
				Cover:                 dat.Get("cover").String(),
				LastUpdateChapterName: dat.Get("chapters.0.data.0.chapter_title").String(),
				LastUpdateChapterID:   dat.Get("chapters.0.data.0.chapter_id").Uint(),
				LastUpdateTime:        dat.Get("last_updatetime").Int(),
			})
		}
	}

	sort.Slice(items, func(a, b int) bool {
		return items[a].LastUpdateTime > items[b].LastUpdateTime
	})

	jsonDat, _ := json.Marshal(items)
	ioutil.WriteFile("public/data.json", jsonDat, 0644)
}

func main() {
	go func() {
		time.Sleep(1 * time.Second)
		downloadBooks()
	}()

	e := echo.New()
	e.HideBanner = true
	e.Static("/", "public")
	e.Use(middleware.GzipWithConfig(middleware.GzipConfig{
		Level: 5,
	}))
	e.GET("/webpic/*", func(c echo.Context) error {
		req, _ := http.NewRequest("GET", fmt.Sprintf("http://images.dmzj.com%s", c.Request().URL.Path), nil)
		req.Header.Set("Referer", "https://m.dmzj.com/")
		res, err := client.Do(req)
		if err != nil {
			return c.NoContent(http.StatusBadGateway)
		}
		defer res.Body.Close()
		data, _ := ioutil.ReadAll(res.Body)
		return c.Blob(res.StatusCode, res.Header.Get("Content-Type"), data)
	})
	e.Logger.Fatal(e.Start(":7777"))
}


================================================
FILE: go.mod
================================================
module github.com/torta/dark-dmzj

require (
	github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
	github.com/fatih/color v1.7.0 // indirect
	github.com/labstack/echo v3.3.10+incompatible
	github.com/labstack/gommon v0.2.8 // indirect
	github.com/mattn/go-colorable v0.0.9 // indirect
	github.com/mattn/go-isatty v0.0.4 // indirect
	github.com/mattn/go-runewidth v0.0.4 // indirect
	github.com/stretchr/testify v1.3.0 // indirect
	github.com/tidwall/gjson v1.1.5
	github.com/tidwall/match v1.0.1 // indirect
	github.com/valyala/bytebufferpool v1.0.0 // indirect
	github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 // indirect
	golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613 // indirect
	golang.org/x/sys v0.0.0-20190130150945-aca44879d564 // indirect
	gopkg.in/cheggaaa/pb.v1 v1.0.27
)


================================================
FILE: hotupdate.go
================================================
// +build !windows

package main

import (
	"os"
	"os/signal"
	"syscall"
)

func init() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGUSR1)
	go func() {
		for {
			<-c
			downloadBooks()
		}
	}()
}


================================================
FILE: public/dmzj.css
================================================
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}

================================================
FILE: public/index.html
================================================
<!doctype html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
  <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
  <meta name="referrer" content="no-referrer"/>
  <meta name="format-detection" content="telephone=no"/>
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="white">
  <meta name="wap-font-scale" content="no">
  <title>Dark Dmzj</title>
  <link rel="stylesheet" href="dmzj.css" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.2.2/gh-fork-ribbon.min.css" />
  <style type="text/css">
    body, .UpdateList {
      background: rgb(30, 30, 30);
    }
    .UpdateList .itemBox {
      border-bottom: 1px solid rgb(90, 90, 90);
    }
    .UpdateList .itemTxt .title, .UpdateList .itemTxt .txtItme, .UpdateList .coll {
      color: #fff;
    }
    .header {
      background: transparent;
    }
    .header .serCh {
      background: rgb(60, 60, 60);
    }
    .searInput, .searClose, .searBtn {
      border: 1px solid rgb(129, 129, 129);
      background-color: rgb(110, 110, 110);
      color: #fff;
    }
    .github-fork-ribbon.right-bottom:before {
        background-color: #333;
    }
    .messagSjr {
      background: rgb(60, 60, 60);
      color: #fff;
      top: 44px;
      display: none;
    }
    @media (min-width: 1281px) {
      .messagSjr {
        display: block;
      }
      .header {
        height: 146px;
      }
    }
  </style>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/vanilla-lazyload@8.17.0/dist/lazyload.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
  <script src="https://unpkg.com/unfetch/polyfill"></script>
</head>
<body>
  <div id="app">
    <div class="header">
      <div class="serCh" id="serCh" style="display: block;">
        <div id="searchForm" action="">
          <a href="javascript:void(0);" @click="searchClear" class="searClose"></a>
          <a href="javascript:void(0);" @click="searchAction" class="searBtn"></a>
          <div class="serChinputBox"><input @keyup.enter="searchAction" v-model.trim="keyword" type="search" class="searInput" placeholder="漫画名或作者" id="searInput"></div>
        </div>
      </div>
      <div class="messagSjr" style="padding-bottom: 20px;">
        <ul class="keyTit" id="messagelist">
          <li>1. 下载安装动漫之家手机APP.</li>
          <li>2. 手机浏览器打开 https://dark-dmzj.hloli.net</li>
        </ul>
      </div>
    </div>
    <div class="UpdateList">
      <div class="ClientVer" style="color: #fff; font-size: 14px; padding: 10px; text-align: right;">
        <input type="radio" id="cver1" v-model="clientVer" value="1" />
        <label for="cver1">动漫之家</label>
        /
        <input type="radio" id="cver2" v-model="clientVer" value="2" />
        <label for="cver2">动漫之家社区</label>
      </div>
      <div class="itemBox" v-for="item in items" :key="item.id">
        <div class="itemImg">
          <a :href="formatUrl(item)" title=""><img :class="'lazy'" :data-src="item.cover.replace(/https?:\/\/images\.dmzj\.com/, '')" width="100%"/></a>
        </div>
        <div class="itemTxt">
          <a :href="formatUrl(item)" class="title">{{ item.title }}</a>
          <p class="txtItme">{{ item.authors.join('/') }}<span class="icon icon01"></span></p>
          <p class="txtItme">
            <span class="icon icon02"></span>
            <span class="pd" v-for="type in item.types">{{ type }}</span>
          </p>
          <p class="txtItme">
            <span class="icon icon03"></span>
            <span class="date">{{ moment(item.last_updatetime * 1000).format('YYYY-MM-DD H:mm') }}</span>
          </p>
        </div>
        <a :href="formatUrl(item)" class="coll">{{ item.last_update_chapter_name }}</a>
      </div>
    </div>
  </div>
  <script>
    (function () {
      function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
      var lz = new LazyLoad({ elements_selector: ".lazy" });
      var data = [[], []];
      var iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform);
      new Vue({
        el: '#app',
        data: {
          keyword: "",
          items: [],
          clientVer: (window.localStorage && localStorage.getItem("cver")) || 2,
        },
        watch: {
          clientVer: function(val, oldVal) {
            window.localStorage && localStorage.setItem("cver", val);
          }
        },
        methods: {
          formatUrl: function formatUrl(item) {
            return ~~this.clientVer === 2
                ? iOS
                    ? "dmzjsq://dmzj.com/comicReader?comicId=" +
                      item.id +
                      "&chapterId=" +
                      item.last_update_chapter_id
                    : "dmzj1://dmzj1.com/comic?id=" + item.id
                : iOS
                ? "dmzj://objectIntro/comic?objId=" + item.id
                : "dmzj://dmzj.com/comic?id=" + item.id;
          },
          loadMore: function loadMore() {
            var _items;

            (_items = this.items).push.apply(_items, _toConsumableArray(data[0].splice(0, 20)));
            Vue.nextTick(function () {
              return lz.update();
            });
          },
          searchClear: function searchClear() {
            var _this = this;

            this.keyword = '';
            Vue.nextTick(function () {
              return _this.searchAction();
            });
          },
          searchAction: function searchAction() {
            var keyword = this.keyword.toLowerCase();
            if (this.keyword.length === 0) {
              data[0] = data[1].slice(0);
            } else {
              data[0] = data[1].filter(function (e) {
                return e.title.toLowerCase().indexOf(keyword) > -1 || e.authors.join().toLowerCase().indexOf(keyword) > -1;
              });
            }
            this.items = [];
            this.loadMore();
          }
        },
        created: function created() {
          var _this2 = this;

          fetch('data.json').then(function (e) {
            return e.json();
          }).then(function (e) {
            return data = [e, e.slice(0)];
          }).then(function () {
            window.onscroll = function () {
              if (window.innerHeight + (window.pageYOffset || document.documentElement.scrollTop) > _this2.$el.offsetHeight - 100) {
                _this2.loadMore();
              }
            };
          }).then(this.loadMore);
        }
      });
    })();
  </script>
  <a class="github-fork-ribbon right-bottom fixed" href="https://github.com/torta/dark-dmzj" data-ribbon="Fork me on GitHub" title="Fork me on GitHub">Fork me on GitHub</a>
</body>
</html>
Download .txt
gitextract_vpoukq8z/

├── .gitattributes
├── .github/
│   └── workflows/
│       └── release.yml
├── .gitignore
├── .goreleaser.yml
├── README.md
├── dark_dmzj.go
├── go.mod
├── hotupdate.go
└── public/
    ├── dmzj.css
    └── index.html
Download .txt
SYMBOL INDEX (8 symbols across 2 files)

FILE: dark_dmzj.go
  type dmzjBook (line 25) | type dmzjBook struct
  function init (line 38) | func init() {
  function apiWithRetry (line 62) | func apiWithRetry(id int, try int) string {
  function getItem (line 89) | func getItem(id int, c chan<- string) {
  function arrayMap (line 94) | func arrayMap(vs []string, f func(string) []string) [][]string {
  function downloadBooks (line 102) | func downloadBooks() {
  function main (line 167) | func main() {

FILE: hotupdate.go
  function init (line 11) | func init() {
Condensed preview — 10 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (24K chars).
[
  {
    "path": ".gitattributes",
    "chars": 41,
    "preview": "/public/*.html linguist-detectable=false\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 453,
    "preview": "name: goreleaser\n\non:\n  push:\n\njobs:\n  goreleaser:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        "
  },
  {
    "path": ".gitignore",
    "chars": 49,
    "preview": "*.exe\n/go.sum\n/dark_dmzj\n/public/data.json\n/test\n"
  },
  {
    "path": ".goreleaser.yml",
    "chars": 438,
    "preview": "builds:\n  - env:\n      - CGO_ENABLED=0\n    goos:\n      - linux\n      - darwin\n      - windows\n    goarch:\n      - 386\n  "
  },
  {
    "path": "README.md",
    "chars": 262,
    "preview": "# dark-dmzj\n\n方便得浏览动漫之家藏起来的漫画. [dark-dmzj.hloli.net](https://dark-dmzj.hloli.net)\n\n## usage\n1. 下载安装动漫之家手机APP.\n2. 手机浏览器打开 "
  },
  {
    "path": "dark_dmzj.go",
    "chars": 4864,
    "preview": "package main\n\nimport (\n\t\"crypto/tls\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/labstack/echo\"\n\t\"github.com/labstack/echo/midd"
  },
  {
    "path": "go.mod",
    "chars": 818,
    "preview": "module github.com/torta/dark-dmzj\n\nrequire (\n\tgithub.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect\n\tgithub.com/fa"
  },
  {
    "path": "hotupdate.go",
    "chars": 213,
    "preview": "// +build !windows\n\npackage main\n\nimport (\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n)\n\nfunc init() {\n\tc := make(chan os.Signal, 1)\n"
  },
  {
    "path": "public/dmzj.css",
    "chars": 8465,
    "preview": "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,h"
  },
  {
    "path": "public/index.html",
    "chars": 7123,
    "preview": "<!doctype html>\n<html>\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n  <meta name=\"viewp"
  }
]

About this extraction

This page contains the full source code of the torta/dark-dmzj GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 10 files (22.2 KB), approximately 9.0k tokens, and a symbol index with 8 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!