T O D O \color{#EE2C2C}{TODO} TODO
− 优 化 命 令 , 增 加 u r l 缓 存 \color{#6495ED}{-优化命令,增加url缓存} −优化命令,增加url缓存
− 开 放 随 机 s e t u 和 检 索 功 能 \color{#6495ED}{-开放随机setu和检索功能} −开放随机setu和检索功能
package fvckPixiv
type UserProfileImageUrls struct {
Px16x16 string `json:"px_16x16"`
Px170x170 string `json:"px_170x170"`
Px50x50 string `json:"px_50x50"`
}
type PixOAuthHandler struct {
Account string `json:"account"`
Id string `json:"id"`
IsMailAuthorized bool `json:"is_mail_authorized"`
IsPremium bool `json:"is_premium"`
MailAddress string `json:"mail_address"`
Name string `json:"name"`
ProfileImageUrls UserProfileImageUrls `json:"profile_image_urls"`
RequirePolicyAgreement bool `json:"require_policy_agreement"`
XRestrict int `json:"x_restrict"`
}
type PixLoginResponseHandler struct {
AccessToken string `json:"access_token"`
DeviceToken string `json:"device_token"`
ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
Scope string `json:"scope"`
TokenType string `json:"token_type"`
UserOAuth PixOAuthHandler `json:"user"`
}
type PixLoginResponse struct {
Response PixLoginResponseHandler `json:"response"`
}
//-------------------------Illustration Info----------------------------//
type ImageUrls struct {
Large string `json:"large"`
Medium string `json:"medium"`
SquareMedium string `json:"square_medium"`
}
type MetaPages struct {
}
type IllustrationInfo struct {
CreateDate string `json:"create_date"`
Height int `json:"height"`
Id int `json:"id"`
ImageUrl ImageUrls `json:"image_urls"`
}
type Illustration struct {
Illusts []IllustrationInfo `json:"illusts"`
NextUrl string `json:"next_url"`
}
package fvckPixiv
import (
"crypto/md5"
"encoding/hex"
"strings"
"time"
)
var HashSalt string = "28c1fdd170a5204386cb1313c7077b34f83e4aaf4aa829ce78c231e05b0bae2c"
func getXClientHashAndTime() (string, string) {
var result string
var curTime string = getCurFormatTime()
data := []byte(curTime+HashSalt)
encodedData := md5.Sum(data)
for _, b := range encodedData {
temp := make([]byte, 1)
temp[0] = byte(int(b) & 0xff)
hexString := hex.EncodeToString(temp)
if len(hexString) < 2 {
hexString = "0" + hexString
}
result = result+hexString
}
return result, curTime
}
func getCurFormatTime() string {
rawTime := time.Now().Format("2006-01-02 15:04:05")
var curTime string
for index, timeMsg := range strings.Split(rawTime, " ") {
if index == 0 {
curTime = timeMsg
} else if index == 1 {
curTime = curTime + "T" + timeMsg + "+08:00"
}
}
return curTime
}
package fvckPixiv
import (
"crypto/tls"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)
type PixClient struct {
clnt http.Client
pixLoginResponse PixLoginResponse
R18illustration Illustration
}
func NewPixivClient() *PixClient {
proxyUrl, err := url.Parse("http://127.0.0.1:8118/")
if err != nil {
panic(err)}
transport := &http.Transport {
TLSClientConfig: &tls.Config{
InsecureSkipVerify: false},
Dial: func(netw, addr string) (net.Conn, error) {
deadline := time.Now().Add(60 * time.Second)
c, err := net.DialTimeout(netw, addr, time.Second*60)
if err != nil {
panic(err)
}
err = c.SetDeadline(deadline)
return c, err
},
ResponseHeaderTimeout: time.Second*60,
Proxy: http.ProxyURL(proxyUrl),
}
return &PixClient {
clnt: http.Client{
Transport: transport},
pixLoginResponse: PixLoginResponse{
},
}
}
func (client *PixClient) PixLogin() {
info := "password=fanfan2000&client_id=MOBrBDS8blbauoSck0ZfDbtuzpyT&get_secure_url=true&username=1264625484%40qq.com&include_policy=true&client_secret=lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj&device_token=pixiv&grant_type=password"
request, err := http.NewRequest("POST",
"https://oauth.secure.pixiv.net/auth/token",
strings.NewReader(info))
if err != nil {
log.Println(err)
}
clientHash, curTime := getXClientHashAndTime()
request.Header.Set("User-Agent", "PixivAndroidApp/5.0.155 (Android 5.1.1; OPPO R17)")
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
request.Header.Set("App-OS", "Android")
request.Header.Set("App-OS-Version", "5.1.1")
request.Header.Set("App-Version", "5.0.166")
request.Header.Set("X-Client-Hash", clientHash)
request.Header.Set("X-Client-Time", curTime)
request.Header.Set("Connection", "Keep-Alive")
request.Header.Set("Content-Length", strconv.Itoa(len(info)))
for key, value := range request.Header {
fmt.Println(key, value)
}
resp, err := client.clnt.Do(request)
if err != nil {
panic(err)
}
data, err := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if err != nil {
panic(err)
} else {
log.Println(string(data))
}
err = json.Unmarshal(data, &client.pixLoginResponse)
if err != nil {
panic(err)
}
}
func (client *PixClient) PixivGetR18Daily() {
req, err := http.NewRequest("GET",
"https://app-api.pixiv.net/v1/illust/ranking?filter=for_android&mode=day_r18",
strings.NewReader(""))
if err != nil {
panic(err)}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Authorization", "Bearer " + client.pixLoginResponse.Response.AccessToken)
req.Header.Set("User-Agent", "PixivAndroidApp/5.0.155 (Android 5.1.1; OPPO R17)")
req.Header.Set("Accept", "*/*")
req.Header.Set("Cache-Control", "no-cache")
resp, err := client.clnt.Do(req)
if err != nil {
log.Println(err)
}
if resp.StatusCode == 400 {
client.PixLogin()
client.PixivGetR18Daily()
return
}
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)}
defer resp.Body.Close()
err = json.Unmarshal(content, &client.R18illustration)
if err != nil {
log.Println(err)
}
}
func (client *PixClient) HSGet(url string) (*http.Response, error) {
resp, err := client.clnt.Get(url)
if err != nil {
return nil, err}
return resp, nil
}
func (client *PixClient) HSPost(url string, args string) (*http.Response, error) {
var rsp io.Reader
resp, err := client.clnt.Post(url, args, rsp)
if err != nil {
log.Println(err)
}
return resp, nil
}
package downloader
import (
"errors"
"fmt"
"io"
"log"
"net/http"
"os"
"strconv"
)
func IsFileExist(filename string, fileSize int64) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
log.Println(info)
return false
}
if fileSize == info.Size() {
log.Println("文件已存在!", info.Name(), info.Size(), info.ModTime())
return true
}
del := os.Remove(filename)
if del != nil {
log.Println(del)
}
return false
}
func DownloadFile(url string, localPath string,
feedbacks ...func(length, downLen int64)) error {
var (
fsize int64
buf = make([]byte, 128*1024)
written int64
)
tmpFilePath := localPath + ".download"
log.Println(tmpFilePath)
client := new(http.Client)
resp, err := client.Get(url)
if err != nil {
return err
}
fsize, err = strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 32)
if err != nil {
log.Println(err)
}
if IsFileExist(localPath, fsize) {
return err
}
log.Println("fsize", fsize)
file, err := os.Create(tmpFilePath)
if err != nil {
return err
}
defer file.Close()
if resp.Body == nil {
return errors.New("body is null")
}
defer resp.Body.Close()
for {
nr, er := resp.Body.Read(buf)
if nr > 0 {
nw, ew := file.Write(buf[0:nr])
if nw > 0 {
written += int64(nw)
}
if ew != nil {
err = ew
break
}
if nr != nw {
err = io.ErrShortWrite
break
}
}
if er != nil {
if er != io.EOF {
err = er
}
break
}
for _, feedback := range feedbacks {
feedback(fsize, written)
}
}
log.Println(err)
if err == nil {
file.Close()
err = os.Rename(tmpFilePath, localPath)
fmt.Println(err)
}
return err
}
package main
import (
"log"
"net/url"
"regexp"
"strconv"
"strings"
"FuckPixiv/src/fvckPixiv"
"github.com/catsworld/qq-bot-api"
)
var bot *qqbotapi.BotAPI
var pix *fvckPixiv.PixClient
const Host = "127.0.0.1:6700"
func main() {
var err error
bot, err = qqbotapi.NewBotAPI("", "ws://"+Host, "CQHTTP_SECRET")
if err != nil {
log.Fatal(err)
}
bot.Debug = false
conf := qqbotapi.NewUpdate(0)
conf.PreloadUserInfo = true
updates, err := bot.GetUpdatesChan(conf)
pix = fvckPixiv.NewPixivClient()
pix.PixLogin()
for update := range updates {
if update.Message == nil {
continue
}
log.Println(update.Message)
handleMsg(update)
}
}
func handleMsg(update qqbotapi.Update) {
if msgSlice := strings.Split(update.Message.Text, " ")
len(msgSlice) == 2 {
if msgSlice[0] == "KKP" || msgSlice[0] == "kkp" {
re := regexp.MustCompile(`[0-9]{1,2}`)
if re.MatchString(msgSlice[1]) {
index, _ := strconv.Atoi(msgSlice[1])
picUrl, err := url.Parse(pix.R18illustration.Illusts[index - 1].ImageUrl.Large)
if err != nil {
log.Println(err)}
if update.MessageType == "group" {
bot.NewMessage(update.GroupID, "group").ImageWeb(picUrl).Send()
} else if update.MessageType == "private" {
bot.NewMessage(update.Message.From.ID, "private").ImageWeb(picUrl).Send()
}
} else {
return}
}
} else if len(msgSlice) == 1 {
if msgSlice[0] == "色图GKD" {
pix.PixivGetR18Daily()
}
}
}