@@ -3,103 +3,134 @@ package main
3
3
import (
4
4
"encoding/json"
5
5
"fmt"
6
- "io/ioutil"
7
- "log"
8
6
"net/http"
9
7
"os"
10
8
"os/exec"
9
+ "strconv"
11
10
)
12
11
13
- type GameData struct {
12
+ const (
13
+ KB = 1024
14
+ MB = 1024 * KB
15
+ GB = 1024 * MB
16
+
17
+ URL = "https://sdk-os-static.mihoyo.com/hk4e_global/mdk/launcher/api/resource?channel_id=1&key=gcStgarh&launcher_id=10&sub_channel_id=0"
18
+ )
19
+
20
+ type GenshinData struct {
14
21
Data struct {
15
22
Game struct {
16
23
Latest struct {
17
24
Version string `json:"version"`
18
- } `json:"latest"`
25
+ }
19
26
Diffs []struct {
20
- Version string `json:"version"`
21
- Path string `json:"path"`
22
- MD5 string `json:"md5"`
23
- VoicePacks []VoicePack `json:"voice_packs"`
27
+ Name string `json:"name"`
28
+ Version string `json:"version"`
29
+ Path string `json:"path"`
30
+ Size string `json:"package_size"`
31
+ Hash string `json:"md5"`
32
+ Voice []struct {
33
+ Language string `json:"language"`
34
+ Name string `json:"name"`
35
+ Path string `json:"path"`
36
+ Size string `json:"package_size"`
37
+ Hash string `json:"md5"`
38
+ } `json:"voice_packs"`
24
39
} `json:"diffs"`
25
40
} `json:"game"`
26
41
} `json:"data"`
27
42
}
28
43
29
- type VoicePack struct {
30
- Path string `json:"path"`
31
- MD5 string `json:"md5"`
32
- }
33
-
34
44
func main () {
35
- url := "https://sdk-os-static.mihoyo.com/hk4e_global/mdk/launcher/api/resource?channel_id=1&key=gcStgarh&launcher_id=10&sub_channel_id=0"
45
+ // create http client with 10s timeout
46
+ client := & http.Client {
47
+ Timeout : 10e9 ,
48
+ }
36
49
37
- // Fetch the JSON data
38
- response , err := http .Get ( url )
50
+ // create http request
51
+ req , err := http .NewRequest ( "GET" , URL , http . NoBody )
39
52
if err != nil {
40
- log .Fatal (err )
53
+ fmt .Println (err )
54
+ return
41
55
}
42
- defer response .Body .Close ()
43
56
44
- body , err := ioutil .ReadAll (response .Body )
57
+ // send http request
58
+ resp , err := client .Do (req )
45
59
if err != nil {
46
- log .Fatal (err )
60
+ fmt .Println (err )
61
+ return
47
62
}
63
+ defer resp .Body .Close ()
48
64
49
- // Parse the JSON data
50
- var data GameData
51
- err = json .Unmarshal ( body , & data )
65
+ // parse http response
66
+ var data GenshinData
67
+ err = json .NewDecoder ( resp . Body ). Decode ( & data )
52
68
if err != nil {
53
- log .Fatal (err )
69
+ fmt .Println (err )
70
+ return
54
71
}
55
72
56
- // Extract the required values
73
+ // extract the required values
57
74
oldVer := data .Data .Game .Diffs [0 ].Version
58
75
newVer := data .Data .Game .Latest .Version
76
+ gameData := data .Data .Game .Diffs [0 ]
59
77
60
- fmt .Printf ("Genshin Impact Patch Downloader\n update version : %s to %s\n \n " , oldVer , newVer )
61
- fmt .Println ("1. Game Update" )
62
- fmt .Println ("2. Chinese Voice" )
63
- fmt .Println ("3. English Voice" )
64
- fmt .Println ("4. Japanese Voice" )
65
- fmt .Println ("5. Korean Voice" )
78
+ // print available updates
79
+ fmt .Printf ("Genshin Impact Patch Downloader\n Update Version : %s to %s\n \n " , oldVer , newVer )
80
+ fmt .Printf ("1. game update (%s)\n " , convertSize (gameData .Size ))
81
+ for i , voiceData := range gameData .Voice {
82
+ fmt .Printf ("%d. %s voice (%s)\n " , i + 2 , voiceData .Language , convertSize (voiceData .Size ))
83
+ }
84
+
85
+ var name , path , hash string
66
86
67
- // Prompt user to select the option
68
- var option int
69
- validOption := false
70
- for ! validOption {
71
- fmt .Print ("select an option (1-5): " )
72
- _ , err = fmt .Scanln (& option )
73
- if err != nil || option < 1 || option > 5 {
74
- fmt .Println ("invalid option selected" )
87
+ // ask user to select update
88
+ for {
89
+ var choice int
90
+ fmt .Print ("\n Select Update : " )
91
+ fmt .Scanln (& choice )
92
+ if choice == 1 {
93
+ name = gameData .Name
94
+ path = gameData .Path
95
+ hash = gameData .Hash
96
+ } else if choice > 1 && choice < len (gameData .Voice )+ 2 {
97
+ name = gameData .Voice [choice - 2 ].Name
98
+ path = gameData .Voice [choice - 2 ].Path
99
+ hash = gameData .Voice [choice - 2 ].Hash
100
+ } else {
101
+ fmt .Println ("Wrong Choice" )
75
102
continue
76
103
}
77
-
78
- validOption = true
79
- }
80
-
81
- // Download the selected file
82
- path := ""
83
- md5 := ""
84
- if option == 1 {
85
- path = data .Data .Game .Diffs [0 ].Path
86
- md5 = data .Data .Game .Diffs [0 ].MD5
87
- } else if option >= 2 && option <= 5 {
88
- index := option - 2
89
- path = data .Data .Game .Diffs [0 ].VoicePacks [index ].Path
90
- md5 = data .Data .Game .Diffs [0 ].VoicePacks [index ].MD5
104
+ break
91
105
}
92
106
93
- fmt .Println ("\n downloading..." )
94
- downloadCommand := fmt .Sprintf ("aria2c.exe --conf-path=aria2.conf --checksum=md5=%s %s" , md5 , path )
95
- cmd := exec .Command ("cmd" , "/C" , downloadCommand )
107
+ // download update file
108
+ fmt .Println ("Downloading:" , name )
109
+ command := fmt .Sprintf ("aria2c.exe --conf-path=aria2.conf --checksum=md5=%s %s" , hash , path )
110
+ cmd := exec .Command ("cmd" , "/C" , command )
96
111
cmd .Stdout = os .Stdout
97
112
cmd .Stderr = os .Stderr
98
113
err = cmd .Run ()
99
114
if err != nil {
100
- log .Fatal (err )
115
+ fmt .Println (err )
116
+ return
101
117
}
102
118
103
119
fmt .Print ("\n press enter to exit..." )
104
120
fmt .Scanln ()
105
121
}
122
+
123
+ // convert size from string bytes to human readable format
124
+ func convertSize (s string ) string {
125
+ size , _ := strconv .ParseInt (s , 10 , 64 )
126
+ switch {
127
+ case size > GB :
128
+ return fmt .Sprintf ("%.2f GB" , float64 (size )/ GB )
129
+ case size > MB :
130
+ return fmt .Sprintf ("%d MB" , size / MB )
131
+ case size > KB :
132
+ return fmt .Sprintf ("%d KB" , size / KB )
133
+ default :
134
+ return fmt .Sprintf ("%d B" , size )
135
+ }
136
+ }
0 commit comments