Commit 0a6260b2e0

0a6260b2e026c073f13534dbc882813d3d74b32a

parent: 949bef2c5d

Unsigned

lost+skunk <skunky@ebloid.ru> · 2024-07-04 08:27 UTC

Небольшие улучшения в группах

Layout: unified · split

misc.go −106
@@ -1,79 +1,14 @@
1package devianter 1package devianter
2 2
3import ( 3import (
4 "encoding/json"
5 "errors" 4 "errors"
6 "io"
7 "log" 5 "log"
8 "math" 6 "math"
9 "net/http"
10 u "net/url" 7 u "net/url"
11 "strconv" 8 "strconv"
12 "strings" 9 "strings"
13) 10)
14 11
15// функция для высера ошибки в stderr
16func err(txt error) {
17 if txt != nil {
18 println(txt.Error())
19 }
20}
21
22// сокращение для вызова щенка и парсинга жсона
23func ujson(data string, output any) {
24 input, e := puppy(data)
25 err(e)
26
27 eee := json.Unmarshal([]byte(input), output)
28 err(eee)
29}
30
31/* REQUEST SECTION */
32// структура для ответа сервера
33type reqrt struct {
34 Body string
35 Status int
36 Cookies []*http.Cookie
37 Headers http.Header
38}
39
40// функция для совершения запроса
41func request(uri string, other ...string) reqrt {
42 var r reqrt
43
44 // создаём новый запрос
45 cli := &http.Client{}
46 req, e := http.NewRequest("GET", uri, nil)
47 err(e)
48
49 req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0.0")
50
51 // куки и UA-шник
52 for num, rng := range other {
53 switch num {
54 case 1:
55 req.Header.Set("User-Agent", rng)
56 case 0:
57 req.Header.Set("Cookie", rng)
58 }
59 }
60
61 resp, e := cli.Do(req)
62 err(e)
63 defer resp.Body.Close()
64
65 body, e := io.ReadAll(resp.Body)
66 err(e)
67
68 // заполняем структуру
69 r.Body = string(body)
70 r.Cookies = resp.Cookies()
71 r.Headers = resp.Header
72 r.Status = resp.StatusCode
73
74 return r
75}
76
77/* AVATARS AND EMOJIS */ 12/* AVATARS AND EMOJIS */
78func AEmedia(name string, t rune) (string, error) { 13func AEmedia(name string, t rune) (string, error) {
79 // список всех возможных расширений 14 // список всех возможных расширений
@@ -189,44 +124,3 @@ func SearchFunc(query string, page int, scope rune, user ...string) (ss Search,
189 124
190 return 125 return
191} 126}
192
193/* PUPPY aka DeviantArt API */
194// получение или обновление токена
195var cookie string
196var token string
197
198func UpdateCSRF() error {
199 if cookie == "" {
200 req := request("https://www.deviantart.com/_puppy")
201
202 for _, content := range req.Cookies {
203 cookie = content.Raw
204 }
205 }
206
207 req := request("https://www.deviantart.com", cookie)
208 if req.Status != 200 {
209 return errors.New(req.Body)
210 }
211 token = req.Body[strings.Index(req.Body, "window.__CSRF_TOKEN__ = '")+25 : strings.Index(req.Body, "window.__XHR_LOCAL__")-3]
212
213 return nil
214}
215
216func puppy(data string) (string, error) {
217 var url strings.Builder
218 url.WriteString("https://www.deviantart.com/_puppy/")
219 url.WriteString(data)
220 url.WriteString("&csrf_token=")
221 url.WriteString(token)
222 url.WriteString("&da_minor_version=20230710")
223
224 body := request(url.String(), cookie)
225
226 // если код ответа не 200, возвращается ошибка
227 if body.Status != 200 {
228 return "", errors.New(body.Body)
229 }
230
231 return body.Body, nil
232}
user-group.go +54 −23
@@ -6,13 +6,14 @@ import (
6) 6)
7 7
8// структура группы или пользователя 8// структура группы или пользователя
9type groups struct { 9type GroupAbout struct {
10 GroupAbout struct { 10 FoundatedAt time `json:"foundationTs"`
11 FoundatedAt time `json:"foundationTs"` 11 Description Text
12 Description Text 12}
13 } 13type GroupAdmins struct {
14 GroupAdmins struct { 14 Results []struct {
15 Results []struct { 15 TypeId int
16 User struct {
16 Username string 17 Username string
17 } 18 }
18 } 19 }
@@ -50,11 +51,32 @@ type GRuser struct {
50 Modules []struct { 51 Modules []struct {
51 Name string 52 Name string
52 ModuleData struct { 53 ModuleData struct {
53 groups 54 GroupAbout GroupAbout
55 GroupAdmins GroupAdmins
54 users 56 users
57 }
58 }
59 }
60 }
61 Extra struct {
62 Tag string `json:"gruserTagline"`
63 Stats struct {
64 Deviations, Watchers, Watching, Pageviews, CommentsMade, Favourites, Friends int
65 FeedComments int `json:"commentsReceivedProfile"`
66 }
67 } `json:"pageExtraData"`
68}
55 69
70type Gallery struct {
71 Gruser struct {
72 ID int `json:"gruserId"`
73 Page struct {
74 Modules []struct {
75 Name string
76 ModuleData struct {
56 // группы 77 // группы
57 Folders struct { 78 Folders struct {
79 HasMore bool
58 Results []struct { 80 Results []struct {
59 FolderId int 81 FolderId int
60 Name string 82 Name string
@@ -63,6 +85,7 @@ type GRuser struct {
63 85
64 // галерея 86 // галерея
65 Folder struct { 87 Folder struct {
88 HasMore bool
66 Username string 89 Username string
67 Pages int `json:"totalPageCount"` 90 Pages int `json:"totalPageCount"`
68 Deviations []Deviation 91 Deviations []Deviation
@@ -71,18 +94,13 @@ type GRuser struct {
71 } 94 }
72 } 95 }
73 } 96 }
74 Extra struct { 97 HasMore bool
75 Tag string `json:"gruserTagline"` 98 Results []Deviation
76 Stats struct {
77 Deviations, Watchers, Watching, Pageviews, CommentsMade, Favourites, Friends int
78 FeedComments int `json:"commentsReceivedProfile"`
79 }
80 } `json:"pageExtraData"`
81} 99}
82 100
83type Group struct { 101type Group struct {
84 Name string // обязательно заполнить 102 Name string // обязательно заполнить
85 Content GRuser 103 Content Gallery
86} 104}
87 105
88// подходит как группа, так и пользователь 106// подходит как группа, так и пользователь
@@ -93,14 +111,27 @@ func (s Group) GroupFunc() (g GRuser) {
93} 111}
94 112
95// гарелея пользователя или группы 113// гарелея пользователя или группы
96func (s Group) Gallery(page int) (g Group) { 114func (s Group) Gallery(page int, folderid ...int) (g Group) {
97 var url strings.Builder 115 var url strings.Builder
98 url.WriteString("dauserprofile/init/gallery?username=") 116 if folderid[0] > 0 {
99 url.WriteString(s.Name) 117 page--
100 url.WriteString("&page=") 118 url.WriteString("dashared/gallection/contents?username=")
101 url.WriteString(strconv.Itoa(page)) 119 url.WriteString(s.Name)
102 url.WriteString("&deviations_limit=50&with_subfolders=false") 120 url.WriteString("&folderid=")
121 url.WriteString(strconv.Itoa(folderid[0]))
122 url.WriteString("&offset=")
123 url.WriteString(strconv.Itoa(page * 50))
124 url.WriteString("&type=gallery&")
125 } else {
126 url.WriteString("dauserprofile/init/gallery?username=")
127 url.WriteString(s.Name)
128 url.WriteString("&page=")
129 url.WriteString(strconv.Itoa(page))
130 url.WriteString("&deviations_")
131 }
132 url.WriteString("limit=50")
133 url.WriteString("&with_subfolders=false")
103 134
104 ujson(url.String(), &g) 135 ujson(url.String(), &g.Content)
105 return 136 return
106} 137}
util.go added +112
@@ -0,0 +1,112 @@
1package devianter
2
3import (
4 "encoding/json"
5 "errors"
6 "io"
7 "net/http"
8 "strings"
9)
10
11// функция для высера ошибки в stderr
12func err(txt error) {
13 if txt != nil {
14 println(txt.Error())
15 }
16}
17
18// сокращение для вызова щенка и парсинга жсона
19func ujson(data string, output any) {
20 input, e := puppy(data)
21 err(e)
22
23 eee := json.Unmarshal([]byte(input), output)
24 err(eee)
25}
26
27/* REQUEST SECTION */
28// структура для ответа сервера
29type reqrt struct {
30 Body string
31 Status int
32 Cookies []*http.Cookie
33 Headers http.Header
34}
35
36// функция для совершения запроса
37func request(uri string, other ...string) reqrt {
38 var r reqrt
39
40 // создаём новый запрос
41 cli := &http.Client{}
42 req, e := http.NewRequest("GET", uri, nil)
43 err(e)
44
45 req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0.0")
46
47 // куки и UA-шник
48 for num, rng := range other {
49 switch num {
50 case 1:
51 req.Header.Set("User-Agent", rng)
52 case 0:
53 req.Header.Set("Cookie", rng)
54 }
55 }
56
57 resp, e := cli.Do(req)
58 err(e)
59 defer resp.Body.Close()
60
61 body, e := io.ReadAll(resp.Body)
62 err(e)
63
64 // заполняем структуру
65 r.Body = string(body)
66 r.Cookies = resp.Cookies()
67 r.Headers = resp.Header
68 r.Status = resp.StatusCode
69
70 return r
71}
72
73/* PUPPY aka DeviantArt API */
74// получение или обновление токена
75var cookie string
76var token string
77
78func UpdateCSRF() error {
79 if cookie == "" {
80 req := request("https://www.deviantart.com/_puppy")
81
82 for _, content := range req.Cookies {
83 cookie = content.Raw
84 }
85 }
86
87 req := request("https://www.deviantart.com", cookie)
88 if req.Status != 200 {
89 return errors.New(req.Body)
90 }
91 token = req.Body[strings.Index(req.Body, "window.__CSRF_TOKEN__ = '")+25 : strings.Index(req.Body, "window.__XHR_LOCAL__")-3]
92
93 return nil
94}
95
96func puppy(data string) (string, error) {
97 var url strings.Builder
98 url.WriteString("https://www.deviantart.com/_puppy/")
99 url.WriteString(data)
100 url.WriteString("&csrf_token=")
101 url.WriteString(token)
102 url.WriteString("&da_minor_version=20230710")
103
104 body := request(url.String(), cookie)
105
106 // если код ответа не 200, возвращается ошибка
107 if body.Status != 200 {
108 return "", errors.New(body.Body)
109 }
110
111 return body.Body, nil
112}