-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
304 lines (278 loc) · 10.2 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"runtime"
"sync"
"syscall"
"time"
"unsafe"
"github.com/charmbracelet/lipgloss"
Browser "github.com/chromedp/chromedp"
)
var mu sync.Mutex
type Nettruyen struct {
TruyenUrl string `json:"TruyenUrl"`
SoChapDoc int `json:"SoChapDoc"`
TenTruyen string `json:"TenTruyen"`
}
type Configuration struct {
TrangChuNettruyen string `json:"TrangChuNettruyen"`
TenDangNhap string `json:"TenDangNhap"`
MatKhau string `json:"MatKhau"`
Truyen []Nettruyen `json:"Truyen"`
DelayTime int `json:"DelayTime"`
}
type SharedData struct {
mu sync.Mutex
WebStatus string
}
var sharedData = SharedData{
WebStatus: "Không Rõ!",
}
func readConfig() Configuration {
data, err := ioutil.ReadFile("./config.json")
if err != nil {
log.Fatalf("[LỖI] Không load được file config: %v", err)
}
var config Configuration
err = json.Unmarshal(data, &config)
if err != nil {
log.Fatalf("[LỖI] Config lỗi cú pháp: %v", err)
}
return config
}
func setTitle(title string) {
kernel32 := syscall.NewLazyDLL("kernel32.dll")
setConsoleTitleW := kernel32.NewProc("SetConsoleTitleW")
_, _, _ = setConsoleTitleW.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(title))))
}
func appendLog(message string) {
f, err := os.OpenFile("log.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
defer f.Close()
timestamp := time.Now().Format("2006-01-02 15:04:05")
logMessage := fmt.Sprintf("%s - %s\n", timestamp, message)
if _, err = f.WriteString(logMessage); err != nil {
log.Fatal(err)
}
// fmt.Println(logMessage)
}
func main() {
setTitle("Auto Tu Tiên Ver 1.0")
config := readConfig()
go AutoCheckWebStatus(config.TrangChuNettruyen, 1*time.Second)
ctx, cancel := TaskSetupBrowser()
defer cancel()
var wg sync.WaitGroup
for idx, comic := range config.Truyen {
wg.Add(1)
go func(c Nettruyen, index int) {
defer wg.Done()
ctxChild, cancelCtx := Browser.NewContext(ctx, Browser.WithLogf(log.Printf))
defer cancelCtx()
if err := runTasks(ctxChild, config, c, index); err != nil {
appendLog(fmt.Sprintf("[LỖI] Khi đọc %s: %v", c.TruyenUrl, err))
} else {
appendLog(fmt.Sprintf("[HOÀN THÀNH] Đã đọc xong %s.", c.TruyenUrl))
}
}(comic, idx)
}
wg.Wait()
Browser.Cancel(ctx)
cancel()
}
func TimBraveBrowser() (string, error) {
switch runtime.GOOS {
case "windows":
return `C:\Program Files\BraveSoftware\Brave-Browser\Application\brave.exe`, nil
case "linux":
return "/usr/bin/brave-browser", nil
case "darwin":
return "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser", nil
default:
return "", errors.New("hệ điều hành không được hỗ trợ")
}
}
func TaskSetupBrowser() (context.Context, context.CancelFunc) {
bravePath, err := TimBraveBrowser()
if err != nil {
log.Fatalf("Error finding Brave browser: %v", err)
}
debuggingPort := "9222"
time.Sleep(2 * time.Second)
opts := append(Browser.DefaultExecAllocatorOptions[:],
Browser.NoDefaultBrowserCheck,
// chromedp.WindowSize(500, 500),
Browser.ExecPath(bravePath),
Browser.Flag("remote-debugging-port", debuggingPort),
Browser.Flag("headless", false),
Browser.Flag("disable-gpu", true),
Browser.Flag("no-sandbox", true),
Browser.Flag("disable-setuid-sandbox", true),
Browser.Flag("disable-logging", true),
Browser.Flag("disable-login-animations", true),
Browser.Flag("disable-notifications", true),
Browser.Flag("lang", "vi_VN"),
Browser.Flag("start-maximized", true),
)
ctx, cancel := Browser.NewExecAllocator(context.Background(), opts...)
ctx, cancel = Browser.NewContext(ctx, Browser.WithLogf(log.Printf))
return ctx, cancel
}
func runTasks(ctx context.Context, config Configuration, comic Nettruyen, idx int) error {
return Browser.Run(ctx,
TaskDangNhap(config, comic, idx),
TaskTheoDoi(comic.TruyenUrl, comic, idx),
TaskDocTruyen(ctx, comic.SoChapDoc, config.DelayTime, comic, idx),
)
}
func TaskDangNhap(config Configuration, comic Nettruyen, idx int) Browser.Tasks {
return Browser.Tasks{
Browser.Navigate(config.TrangChuNettruyen),
Browser.ActionFunc(func(ctx context.Context) error {
TextBox(comic.TenTruyen, 0, comic.SoChapDoc, idx, "[INFO] Mở trang chủ nettruyen.")
appendLog("[INFO] Mở trang chủ nettruyen.")
return nil
}),
Browser.WaitVisible(`#header li.login-link > a`, Browser.ByQuery),
Browser.Click(`#header li.login-link > a`, Browser.ByQuery),
Browser.ActionFunc(func(ctx context.Context) error {
TextBox(comic.TenTruyen, 0, comic.SoChapDoc, idx, "[INFO] Click nút đăng nhập.")
appendLog("[INFO] Click nút đăng nhập.")
return nil
}),
Browser.WaitVisible(`#ctl00_mainContent_login1_LoginCtrl_UserName`, Browser.ByQuery),
Browser.SendKeys(`#ctl00_mainContent_login1_LoginCtrl_UserName`, config.TenDangNhap, Browser.ByQuery),
Browser.SendKeys(`#ctl00_mainContent_login1_LoginCtrl_Password`, config.MatKhau, Browser.ByQuery),
Browser.Click(`#ctl00_mainContent_login1_LoginCtrl_Login`, Browser.ByQuery),
Browser.ActionFunc(func(ctx context.Context) error {
TextBox(comic.TenTruyen, 0, comic.SoChapDoc, idx, "[INFO] Bắt đầu đăng nhập.")
appendLog("[INFO] Bắt đầu đăng nhập.")
return nil
}),
Browser.WaitNotPresent(`#ctl00_mainContent_login1_LoginCtrl_Login`, Browser.ByQuery),
Browser.ActionFunc(func(ctx context.Context) error {
TextBox(comic.TenTruyen, 0, comic.SoChapDoc, idx, "[INFO] Đăng nhập thành công.")
appendLog("[INFO] Đăng nhập thành công.")
return nil
}),
}
}
func TaskTheoDoi(url string, comic Nettruyen, idx int) Browser.Tasks {
return Browser.Tasks{
Browser.Navigate(url),
Browser.ActionFunc(func(ctx context.Context) error {
TextBox(comic.TenTruyen, 0, comic.SoChapDoc, idx, "[INFO] Mở trang đọc truyện.")
appendLog("[INFO] Mở trang đọc truyện.")
var followButtonExists bool
err := Browser.Run(ctx, Browser.Evaluate(`!!document.querySelector('i.fa.fa-heart')`, &followButtonExists))
if err != nil {
appendLog("[LỖI] Không thấy nút theo dõi.")
TextBox(comic.TenTruyen, 0, comic.SoChapDoc, idx, "[LỖI] Không thấy nút theo dõi.")
return err
}
if followButtonExists {
err = Browser.Run(ctx, Browser.Click(`i.fa.fa-heart`, Browser.ByQuery))
if err != nil {
appendLog("[LỖI] Lỗi khi click nút theo dõi.")
TextBox(comic.TenTruyen, 0, comic.SoChapDoc, idx, "[LỖI] Lỗi khi click nút theo dõi.")
return err
}
appendLog("[INFO] Đã click vào nút theo dõi truyện.")
TextBox(comic.TenTruyen, 0, comic.SoChapDoc, idx, "[INFO] Đã click vào nút theo dõi truyện.")
return nil
}
var unfollowButtonExists bool
err = Browser.Run(ctx, Browser.Evaluate(`!!document.querySelector('i.fa.fa-times')`, &unfollowButtonExists))
if err != nil {
appendLog("[INFO] Không thấy nút bỏ theo dõi.")
TextBox(comic.TenTruyen, 0, comic.SoChapDoc, idx, "[INFO] Không thấy nút bỏ theo dõi.")
return err
}
if unfollowButtonExists {
appendLog("[INFO] Truyện này đã theo dõi rồi.")
TextBox(comic.TenTruyen, 0, comic.SoChapDoc, idx, "[INFO] Truyện này đã theo dõi rồi.")
return nil
}
appendLog("[INFO] Không tìm thấy nút theo dõi.")
TextBox(comic.TenTruyen, 0, comic.SoChapDoc, idx, "[INFO] Không tìm thấy nút theo dõi.")
return nil
}),
}
}
func NettruyenWebStatus(url string) string {
client := &http.Client{
Timeout: 10 * time.Second,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return nil
},
}
resp, err := client.Get(url)
if err != nil {
return fmt.Sprintf("[LỖI] Thất bại: %v", err)
}
defer resp.Body.Close()
return resp.Status
}
func AutoCheckWebStatus(url string, interval time.Duration) {
for {
status := NettruyenWebStatus(url)
sharedData.mu.Lock()
sharedData.WebStatus = status
sharedData.mu.Unlock()
time.Sleep(interval)
}
}
func TextBox(title string, currentChapter, totalChapters, idx int, status string) {
sharedData.mu.Lock()
webStatus := sharedData.WebStatus
sharedData.mu.Unlock()
mu.Lock()
defer mu.Unlock()
style := lipgloss.NewStyle().
Border(lipgloss.DoubleBorder()).
PaddingLeft(2).PaddingRight(2).
PaddingTop(1).PaddingBottom(1).
Width(70).
Align(lipgloss.Center).
BorderForeground(lipgloss.Color("#6272a4")).
Foreground(lipgloss.Color("#ffffff")).
Background(lipgloss.Color("#282a36"))
content := fmt.Sprintf("%s\nĐang Đọc Chap: %d/%d\nStatus: %s\nWeb Status: %s", title, currentChapter, totalChapters, status, webStatus)
posY := idx*7 + 1
fmt.Printf("\033[%d;1H%s\n", posY, style.Render(content))
}
func TaskDocTruyen(ctx context.Context, SoChapDoc, DelayTime int, TruyenDangDoc Nettruyen, idx int) Browser.Tasks {
return Browser.Tasks{
Browser.WaitVisible(`div.read-action > a:nth-of-type(1)`, Browser.ByQuery),
Browser.Click(`div.read-action > a:nth-of-type(1)`, Browser.ByQuery),
Browser.ActionFunc(func(innerCtx context.Context) error {
appendLog(fmt.Sprintf("[INFO] Bắt đầu đọc truyện: %s", TruyenDangDoc.TenTruyen))
for i := 0; i < SoChapDoc; i++ {
TextBox(TruyenDangDoc.TenTruyen, i+1, SoChapDoc, idx, "[INFO] Đang đọc chap.")
err := Browser.Run(innerCtx,
Browser.WaitVisible(`a.next > em`, Browser.ByQuery),
Browser.Sleep(time.Duration(DelayTime)*time.Millisecond),
Browser.Click(`a.next > em`, Browser.ByQuery),
)
if err != nil {
appendLog(fmt.Sprintf("[LỖI] Lỗi khi đọc %d của %s: %v", i+1, TruyenDangDoc.TenTruyen, err))
TextBox(TruyenDangDoc.TenTruyen, i+1, SoChapDoc, idx, "[LỖI] Đã gặp lỗi.")
return err
}
}
appendLog(fmt.Sprintf("[HOÀN THÀNH] Thành công đọc hết bộ: %s", TruyenDangDoc.TenTruyen))
TextBox(TruyenDangDoc.TenTruyen, SoChapDoc, SoChapDoc, idx, "[HOÀN THÀNH] Đã đọc hết bộ này rồi.")
return nil
}),
}
}