├── .gitignore ├── README.md ├── go.mod ├── go.sum ├── main.go └── resource ├── DouTu.alfredworkflow └── preview.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | .idea 3 | tmp/ 4 | .DS_Store 5 | images -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 斗图神器 2 | 3 | ### 下载 4 | 5 | [下载斗图神器2.0](resource/DouTu.alfredworkflow) 6 | 7 | ### 使用 8 | 9 | - 检索关键字: `dt 关键字` 10 | - 检索快捷键:`Comamnd+Shift+D` 11 | 12 | ### 效果图 13 | 14 | ![效果图](resource/preview.gif) 15 | 16 | ### 说明 17 | 18 | - 斗图神器依赖于[斗图啦](https://www.doutula.com)网站 19 | - 2.0采用Golang开发,使用Goroutine提升用户体验 20 | - 添加剪切板交互方式,感谢[Cong YU](https://github.com/imcuttle)贡献方案 -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module DouTu2.0 2 | 3 | go 1.14 4 | 5 | require github.com/PuerkitoBio/goquery v1.8.0 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U= 2 | github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI= 3 | github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= 4 | github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= 5 | golang.org/x/net v0.0.0-20210916014120-12bc252f5db8 h1:/6y1LfuqNuQdHAm0jjtPtgRcxIxjVZgm5OTu8/QhZvk= 6 | golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 7 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 8 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 9 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 10 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 11 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 12 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/xml" 5 | "flag" 6 | "fmt" 7 | "io/ioutil" 8 | "log" 9 | "net/http" 10 | "os" 11 | "strings" 12 | "sync" 13 | "time" 14 | 15 | "github.com/PuerkitoBio/goquery" 16 | ) 17 | 18 | const QueryUrl = "https://www.doutula.com/search?keyword=" 19 | const ImgPath = "images" 20 | 21 | var wg sync.WaitGroup 22 | 23 | type Items struct { 24 | XMLName xml.Name `xml:"items"` 25 | Version string `xml:"version,attr"` 26 | Encoding string `xml:"encoding,attr"` 27 | Item []Item `xml:"item"` 28 | } 29 | 30 | type Item struct { 31 | XMLName xml.Name `xml:"item"` 32 | Uid int64 `xml:"uid,attr"` 33 | Arg string `xml:"arg,attr"` 34 | Valid string `xml:"valid,attr"` 35 | Icon string `xml:"icon"` 36 | Title string `xml:"title"` 37 | Autocomplete string `xml:"autocomplete,attr"` 38 | } 39 | 40 | func GetXML(list []Item) string { 41 | bs := Items{Version: "1.0", Encoding: "UTF-8"} 42 | for _, v := range list { 43 | v.Uid = time.Now().UnixNano() 44 | v.Valid = "yes" 45 | bs.Item = append(bs.Item, v) 46 | } 47 | data, _ := xml.MarshalIndent(&bs, "", " ") 48 | return string(data) 49 | } 50 | 51 | func getContent(query string) { 52 | url := QueryUrl + query 53 | resp, err := http.Get(url) 54 | if err != nil { 55 | log.Fatal("网络请求失败:", err) 56 | } 57 | if resp.StatusCode != 200 { 58 | log.Fatalf("网络请求失败: %d %s", resp.StatusCode, resp.Status) 59 | } 60 | defer resp.Body.Close() 61 | 62 | doc, err := goquery.NewDocumentFromReader(resp.Body) 63 | if err != nil { 64 | log.Fatal(err) 65 | } 66 | list := make([]Item, 0) 67 | doc.Find(".img-responsive").Each(func(i int, s *goquery.Selection) { 68 | url, _ := s.Attr("data-original") 69 | name := s.Next().Text() 70 | icon := getFileName(url) 71 | wg.Add(1) 72 | go saveFile(url) 73 | list = append(list, Item{Arg: icon, Title: name, Icon: icon}) 74 | }) 75 | xmlStr := GetXML(list) 76 | wg.Wait() 77 | fmt.Println(xmlStr) 78 | } 79 | 80 | func exist(filename string) bool { 81 | _, err := os.Stat(filename) 82 | return err == nil || os.IsExist(err) 83 | } 84 | 85 | func getFileName(url string) string { 86 | urlList := strings.Split(url, "/") 87 | return ImgPath + "/" + urlList[len(urlList)-1] 88 | } 89 | 90 | func saveFile(url string) string { 91 | defer wg.Done() 92 | if !exist(ImgPath) { 93 | _ = os.Mkdir(ImgPath, 0777) 94 | } 95 | filename := getFileName(url) 96 | if exist(filename) { 97 | return "" 98 | } 99 | resp, _ := http.Get(url) 100 | defer resp.Body.Close() 101 | pix, _ := ioutil.ReadAll(resp.Body) 102 | 103 | if err := ioutil.WriteFile(filename, pix, 0777); err != nil { 104 | log.Fatal(err) 105 | } 106 | return filename 107 | } 108 | 109 | func main() { 110 | var query string 111 | flag.StringVar(&query, "query", "", "查询内容") 112 | flag.Parse() 113 | getContent(query) 114 | } 115 | -------------------------------------------------------------------------------- /resource/DouTu.alfredworkflow: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KilluaaaCHEN/Dou-figure-alfred-workflow/96081dcb8c1d1a0a12967068de7b1a9796804ab5/resource/DouTu.alfredworkflow -------------------------------------------------------------------------------- /resource/preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KilluaaaCHEN/Dou-figure-alfred-workflow/96081dcb8c1d1a0a12967068de7b1a9796804ab5/resource/preview.gif --------------------------------------------------------------------------------