krz/devianter

A DeviantArt guest API library for Go.

clone: git clone https://gitbay.org/krz/devianter.git

0a6260b2e026c073f13534dbc882813d3d74b32a

unsigned

author: lost+skunk <skunky@ebloid.ru> · 2024-07-04T08:27:56Z

Небольшие улучшения в группах
 misc.go       | 106 ------------------------------------------------------
 user-group.go |  77 ++++++++++++++++++++++++++++------------
 util.go       | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 166 insertions(+), 129 deletions(-)

diff --git a/misc.go b/misc.go
index 400ac8b..654ed5e 100644
--- a/misc.go
+++ b/misc.go
@@ -1,79 +1,14 @@
 package devianter
 
 import (
-	"encoding/json"
 	"errors"
-	"io"
 	"log"
 	"math"
-	"net/http"
 	u "net/url"
 	"strconv"
 	"strings"
 )
 
-// функция для высера ошибки в stderr
-func err(txt error) {
-	if txt != nil {
-		println(txt.Error())
-	}
-}
-
-// сокращение для вызова щенка и парсинга жсона
-func ujson(data string, output any) {
-	input, e := puppy(data)
-	err(e)
-
-	eee := json.Unmarshal([]byte(input), output)
-	err(eee)
-}
-
-/* REQUEST SECTION */
-// структура для ответа сервера
-type reqrt struct {
-	Body    string
-	Status  int
-	Cookies []*http.Cookie
-	Headers http.Header
-}
-
-// функция для совершения запроса
-func request(uri string, other ...string) reqrt {
-	var r reqrt
-
-	// создаём новый запрос
-	cli := &http.Client{}
-	req, e := http.NewRequest("GET", uri, nil)
-	err(e)
-
-	req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0.0")
-
-	// куки и UA-шник
-	for num, rng := range other {
-		switch num {
-		case 1:
-			req.Header.Set("User-Agent", rng)
-		case 0:
-			req.Header.Set("Cookie", rng)
-		}
-	}
-
-	resp, e := cli.Do(req)
-	err(e)
-	defer resp.Body.Close()
-
-	body, e := io.ReadAll(resp.Body)
-	err(e)
-
-	// заполняем структуру
-	r.Body = string(body)
-	r.Cookies = resp.Cookies()
-	r.Headers = resp.Header
-	r.Status = resp.StatusCode
-
-	return r
-}
-
 /* AVATARS AND EMOJIS */
 func AEmedia(name string, t rune) (string, error) {
 	// список всех возможных расширений
@@ -189,44 +124,3 @@ func SearchFunc(query string, page int, scope rune, user ...string) (ss Search,
 
 	return
 }
-
-/* PUPPY aka DeviantArt API */
-// получение или обновление токена
-var cookie string
-var token string
-
-func UpdateCSRF() error {
-	if cookie == "" {
-		req := request("https://www.deviantart.com/_puppy")
-
-		for _, content := range req.Cookies {
-			cookie = content.Raw
-		}
-	}
-
-	req := request("https://www.deviantart.com", cookie)
-	if req.Status != 200 {
-		return errors.New(req.Body)
-	}
-	token = req.Body[strings.Index(req.Body, "window.__CSRF_TOKEN__ = '")+25 : strings.Index(req.Body, "window.__XHR_LOCAL__")-3]
-
-	return nil
-}
-
-func puppy(data string) (string, error) {
-	var url strings.Builder
-	url.WriteString("https://www.deviantart.com/_puppy/")
-	url.WriteString(data)
-	url.WriteString("&csrf_token=")
-	url.WriteString(token)
-	url.WriteString("&da_minor_version=20230710")
-
-	body := request(url.String(), cookie)
-
-	// если код ответа не 200, возвращается ошибка
-	if body.Status != 200 {
-		return "", errors.New(body.Body)
-	}
-
-	return body.Body, nil
-}
diff --git a/user-group.go b/user-group.go
index 1247ffe..bfa1971 100644
--- a/user-group.go
+++ b/user-group.go
@@ -6,13 +6,14 @@ import (
 )
 
 // структура группы или пользователя
-type groups struct {
-	GroupAbout struct {
-		FoundatedAt time `json:"foundationTs"`
-		Description Text
-	}
-	GroupAdmins struct {
-		Results []struct {
+type GroupAbout struct {
+	FoundatedAt time `json:"foundationTs"`
+	Description Text
+}
+type GroupAdmins struct {
+	Results []struct {
+		TypeId int
+		User   struct {
 			Username string
 		}
 	}
@@ -50,11 +51,32 @@ type GRuser struct {
 			Modules []struct {
 				Name       string
 				ModuleData struct {
-					groups
+					GroupAbout  GroupAbout
+					GroupAdmins GroupAdmins
 					users
+				}
+			}
+		}
+	}
+	Extra struct {
+		Tag   string `json:"gruserTagline"`
+		Stats struct {
+			Deviations, Watchers, Watching, Pageviews, CommentsMade, Favourites, Friends int
+			FeedComments                                                                 int `json:"commentsReceivedProfile"`
+		}
+	} `json:"pageExtraData"`
+}
 
+type Gallery struct {
+	Gruser struct {
+		ID   int `json:"gruserId"`
+		Page struct {
+			Modules []struct {
+				Name       string
+				ModuleData struct {
 					// группы
 					Folders struct {
+						HasMore bool
 						Results []struct {
 							FolderId int
 							Name     string
@@ -63,6 +85,7 @@ type GRuser struct {
 
 					// галерея
 					Folder struct {
+						HasMore    bool
 						Username   string
 						Pages      int `json:"totalPageCount"`
 						Deviations []Deviation
@@ -71,18 +94,13 @@ type GRuser struct {
 			}
 		}
 	}
-	Extra struct {
-		Tag   string `json:"gruserTagline"`
-		Stats struct {
-			Deviations, Watchers, Watching, Pageviews, CommentsMade, Favourites, Friends int
-			FeedComments                                                                 int `json:"commentsReceivedProfile"`
-		}
-	} `json:"pageExtraData"`
+	HasMore bool
+	Results []Deviation
 }
 
 type Group struct {
 	Name    string // обязательно заполнить
-	Content GRuser
+	Content Gallery
 }
 
 // подходит как группа, так и пользователь
@@ -93,14 +111,27 @@ func (s Group) GroupFunc() (g GRuser) {
 }
 
 // гарелея пользователя или группы
-func (s Group) Gallery(page int) (g Group) {
+func (s Group) Gallery(page int, folderid ...int) (g Group) {
 	var url strings.Builder
-	url.WriteString("dauserprofile/init/gallery?username=")
-	url.WriteString(s.Name)
-	url.WriteString("&page=")
-	url.WriteString(strconv.Itoa(page))
-	url.WriteString("&deviations_limit=50&with_subfolders=false")
+	if folderid[0] > 0 {
+		page--
+		url.WriteString("dashared/gallection/contents?username=")
+		url.WriteString(s.Name)
+		url.WriteString("&folderid=")
+		url.WriteString(strconv.Itoa(folderid[0]))
+		url.WriteString("&offset=")
+		url.WriteString(strconv.Itoa(page * 50))
+		url.WriteString("&type=gallery&")
+	} else {
+		url.WriteString("dauserprofile/init/gallery?username=")
+		url.WriteString(s.Name)
+		url.WriteString("&page=")
+		url.WriteString(strconv.Itoa(page))
+		url.WriteString("&deviations_")
+	}
+	url.WriteString("limit=50")
+	url.WriteString("&with_subfolders=false")
 
-	ujson(url.String(), &g)
+	ujson(url.String(), &g.Content)
 	return
 }
diff --git a/util.go b/util.go
new file mode 100644
index 0000000..b98aa1f
--- /dev/null
+++ b/util.go
@@ -0,0 +1,112 @@
+package devianter
+
+import (
+	"encoding/json"
+	"errors"
+	"io"
+	"net/http"
+	"strings"
+)
+
+// функция для высера ошибки в stderr
+func err(txt error) {
+	if txt != nil {
+		println(txt.Error())
+	}
+}
+
+// сокращение для вызова щенка и парсинга жсона
+func ujson(data string, output any) {
+	input, e := puppy(data)
+	err(e)
+
+	eee := json.Unmarshal([]byte(input), output)
+	err(eee)
+}
+
+/* REQUEST SECTION */
+// структура для ответа сервера
+type reqrt struct {
+	Body    string
+	Status  int
+	Cookies []*http.Cookie
+	Headers http.Header
+}
+
+// функция для совершения запроса
+func request(uri string, other ...string) reqrt {
+	var r reqrt
+
+	// создаём новый запрос
+	cli := &http.Client{}
+	req, e := http.NewRequest("GET", uri, nil)
+	err(e)
+
+	req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0.0")
+
+	// куки и UA-шник
+	for num, rng := range other {
+		switch num {
+		case 1:
+			req.Header.Set("User-Agent", rng)
+		case 0:
+			req.Header.Set("Cookie", rng)
+		}
+	}
+
+	resp, e := cli.Do(req)
+	err(e)
+	defer resp.Body.Close()
+
+	body, e := io.ReadAll(resp.Body)
+	err(e)
+
+	// заполняем структуру
+	r.Body = string(body)
+	r.Cookies = resp.Cookies()
+	r.Headers = resp.Header
+	r.Status = resp.StatusCode
+
+	return r
+}
+
+/* PUPPY aka DeviantArt API */
+// получение или обновление токена
+var cookie string
+var token string
+
+func UpdateCSRF() error {
+	if cookie == "" {
+		req := request("https://www.deviantart.com/_puppy")
+
+		for _, content := range req.Cookies {
+			cookie = content.Raw
+		}
+	}
+
+	req := request("https://www.deviantart.com", cookie)
+	if req.Status != 200 {
+		return errors.New(req.Body)
+	}
+	token = req.Body[strings.Index(req.Body, "window.__CSRF_TOKEN__ = '")+25 : strings.Index(req.Body, "window.__XHR_LOCAL__")-3]
+
+	return nil
+}
+
+func puppy(data string) (string, error) {
+	var url strings.Builder
+	url.WriteString("https://www.deviantart.com/_puppy/")
+	url.WriteString(data)
+	url.WriteString("&csrf_token=")
+	url.WriteString(token)
+	url.WriteString("&da_minor_version=20230710")
+
+	body := request(url.String(), cookie)
+
+	// если код ответа не 200, возвращается ошибка
+	if body.Status != 200 {
+		return "", errors.New(body.Body)
+	}
+
+	return body.Body, nil
+}