2024-06-05 05:01:15 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/alexflint/go-arg"
|
|
|
|
|
2024-06-07 21:17:54 +00:00
|
|
|
"archive/zip"
|
2024-06-05 05:01:15 +00:00
|
|
|
"bufio"
|
2024-06-07 21:17:54 +00:00
|
|
|
"bytes"
|
2024-06-06 04:50:42 +00:00
|
|
|
"errors"
|
2024-06-05 05:01:15 +00:00
|
|
|
"fmt"
|
2024-06-06 04:50:42 +00:00
|
|
|
"io"
|
|
|
|
"net/http"
|
2024-06-05 05:01:15 +00:00
|
|
|
"os"
|
2024-06-06 04:50:42 +00:00
|
|
|
"path/filepath"
|
2024-06-05 05:01:15 +00:00
|
|
|
"regexp"
|
2024-06-06 04:50:42 +00:00
|
|
|
"runtime"
|
2024-06-05 05:01:15 +00:00
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
var args struct {
|
2024-06-06 04:50:42 +00:00
|
|
|
Addon_list_path string `arg:"-i,--addon-list" help:"path to addon list file"`
|
|
|
|
Out_dir string `arg:"-o,--live-dir" help:"path to eso live directory"`
|
2024-06-05 05:26:03 +00:00
|
|
|
Ttc bool `arg:"-t,--ttc" help:"only update tamriel trade centre db"`
|
2024-06-05 05:01:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
arg.MustParse(&args)
|
2024-06-06 04:50:42 +00:00
|
|
|
eso_live_path := eso_live_path_get()
|
|
|
|
if args.Addon_list_path == "" {
|
|
|
|
args.Addon_list_path = filepath.Join(eso_live_path, "addons.list")
|
|
|
|
}
|
2024-06-07 05:26:49 +00:00
|
|
|
if args.Out_dir == "" {
|
2024-06-07 21:17:54 +00:00
|
|
|
args.Out_dir = filepath.Join(eso_live_path, "AddOns")
|
2024-06-07 05:26:49 +00:00
|
|
|
}
|
2024-06-07 21:17:54 +00:00
|
|
|
fmt.Println("args", args)
|
2024-06-07 05:26:49 +00:00
|
|
|
|
2024-06-06 04:50:42 +00:00
|
|
|
_, error := os.Stat(args.Addon_list_path)
|
|
|
|
if errors.Is(error, os.ErrNotExist) {
|
|
|
|
error = addon_list_create(args.Addon_list_path)
|
|
|
|
if error != nil {
|
|
|
|
panic(error)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
addon_urls, error := addon_list_read(args.Addon_list_path)
|
|
|
|
if error != nil {
|
|
|
|
panic(error)
|
|
|
|
}
|
|
|
|
|
2024-06-07 21:44:31 +00:00
|
|
|
error = ttc_update(filepath.Join(args.Out_dir, "TamrielTradeCentre"))
|
|
|
|
if error != nil {
|
|
|
|
panic(error)
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println("Update,", TCC_PRICE_TABLE_URI)
|
|
|
|
|
|
|
|
if args.Ttc {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-06-07 21:17:54 +00:00
|
|
|
addon_paths, error := os.ReadDir(args.Out_dir)
|
2024-06-07 05:26:49 +00:00
|
|
|
if error != nil {
|
|
|
|
panic(error)
|
|
|
|
}
|
|
|
|
|
|
|
|
var eso_live_addon_names []string
|
|
|
|
for _, path := range addon_paths {
|
|
|
|
if path.IsDir() {
|
|
|
|
eso_live_addon_names = append(eso_live_addon_names, path.Name())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var eso_ui_list []EsoAddon
|
2024-06-06 04:50:42 +00:00
|
|
|
for _, url := range addon_urls {
|
2024-06-07 05:26:49 +00:00
|
|
|
eso_ui, error := eso_ui_stat_init(url)
|
2024-06-06 04:50:42 +00:00
|
|
|
if error != nil {
|
|
|
|
panic(error)
|
|
|
|
}
|
|
|
|
|
2024-06-07 05:26:49 +00:00
|
|
|
eso_ui_list = append(eso_ui_list, eso_ui)
|
|
|
|
}
|
|
|
|
|
2024-06-07 06:15:14 +00:00
|
|
|
var eso_live_list []EsoAddon
|
2024-06-07 05:26:49 +00:00
|
|
|
for _, eso_live_name := range eso_live_addon_names {
|
2024-06-07 06:15:14 +00:00
|
|
|
eso_live, error := eso_live_stat_init(eso_live_name)
|
|
|
|
if error != nil {
|
|
|
|
panic(error)
|
|
|
|
}
|
|
|
|
|
2024-06-07 05:26:49 +00:00
|
|
|
matching := ""
|
|
|
|
|
|
|
|
for _, eso_ui := range eso_ui_list {
|
2024-06-07 06:15:14 +00:00
|
|
|
if strings.Contains(eso_live_name, eso_ui.name) {
|
2024-06-07 05:26:49 +00:00
|
|
|
matching = eso_live_name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if matching == "" {
|
2024-06-07 06:15:14 +00:00
|
|
|
fmt.Println("Removing inactive addon", eso_live.path)
|
|
|
|
// TODO os.RemoveAll(eso_live.path)
|
|
|
|
continue
|
2024-06-07 05:26:49 +00:00
|
|
|
}
|
2024-06-07 06:15:14 +00:00
|
|
|
|
|
|
|
eso_live_list = append(eso_live_list, eso_live)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, eso_live := range eso_live_list {
|
2024-06-07 21:17:54 +00:00
|
|
|
fmt.Printf("Live, %s, %s\n", eso_live.name, eso_live.version)
|
2024-06-07 06:15:14 +00:00
|
|
|
}
|
|
|
|
for _, eso_ui := range eso_ui_list {
|
2024-06-07 21:17:54 +00:00
|
|
|
fmt.Printf("Update, %s, %s\n", eso_ui.name, eso_ui.version)
|
|
|
|
error = eso_ui_get_unzip(eso_ui.path, args.Out_dir)
|
|
|
|
if error != nil {
|
|
|
|
panic(error)
|
|
|
|
}
|
2024-06-06 04:50:42 +00:00
|
|
|
}
|
2024-06-05 05:01:15 +00:00
|
|
|
}
|
|
|
|
|
2024-06-05 05:26:03 +00:00
|
|
|
const (
|
|
|
|
CONFIG_TEMPLATE = `https://www.esoui.com/downloads/info7-LibAddonMenu.html
|
|
|
|
https://www.esoui.com/downloads/info1245-TamrielTradeCentre.html
|
|
|
|
https://www.esoui.com/downloads/info1146-LibCustomMenu.html
|
|
|
|
`
|
|
|
|
ESO_LIVE_PATH_WINDOWS = `Documents\Elder Scrolls Online\live`
|
|
|
|
ESO_LIVE_PATH_STEAMOS = ".steam/steam/steamapps/compatdata/306130/pfx/drive_c/users/steamuser/Documents/Elder Scrolls Online/live/"
|
|
|
|
TCC_PRICE_TABLE_URI = "https://us.tamrieltradecentre.com/download/PriceTable"
|
|
|
|
TCC_PRICE_TABLE_NAME = "TamrielTradeCentre"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2024-06-07 21:17:54 +00:00
|
|
|
ESOUI_NAME = regexp.MustCompile(`(?:https://www.esoui.com/downloads/info[0-9]+\-)([A-Za-z]+)(?:\.html)`)
|
|
|
|
ESOUI_VERSION = regexp.MustCompile(`(?:<div\s+id="version">Version:\s+)(.*)(?:</div>)`)
|
|
|
|
ESOUI_DOWNLOAD = regexp.MustCompile(`https://cdn.esoui.com/downloads/file[^"]*`)
|
|
|
|
LIVE_VERSION = regexp.MustCompile(`(?:##\s+Version:\s+)(.*)(?:\n)`)
|
2024-06-05 05:26:03 +00:00
|
|
|
)
|
|
|
|
|
2024-06-06 04:50:42 +00:00
|
|
|
func eso_live_path_get() string {
|
|
|
|
home_path, error := os.UserHomeDir()
|
|
|
|
if error != nil {
|
|
|
|
panic(error)
|
|
|
|
}
|
|
|
|
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
return filepath.Join(home_path, ESO_LIVE_PATH_WINDOWS)
|
|
|
|
} else {
|
|
|
|
return filepath.Join(home_path, ESO_LIVE_PATH_STEAMOS)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func addon_list_create(addon_list_path string) error {
|
|
|
|
file_open, error := os.Create(addon_list_path)
|
|
|
|
if error != nil {
|
|
|
|
return error
|
|
|
|
}
|
|
|
|
defer file_open.Close()
|
|
|
|
|
|
|
|
_, error = file_open.Write([]byte(CONFIG_TEMPLATE))
|
|
|
|
if error != nil {
|
|
|
|
return error
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-06-05 05:01:15 +00:00
|
|
|
func addon_list_read(addon_list_path string) ([]string, error) {
|
|
|
|
file_open, error := os.OpenFile(addon_list_path, os.O_RDONLY, 0644)
|
|
|
|
defer file_open.Close()
|
|
|
|
if error != nil {
|
|
|
|
return nil, error
|
|
|
|
}
|
|
|
|
|
|
|
|
file_scanner := bufio.NewScanner(file_open)
|
|
|
|
lines := []string{}
|
|
|
|
|
|
|
|
for file_scanner.Scan() {
|
|
|
|
line := file_scanner.Text()
|
|
|
|
|
2024-06-05 05:26:03 +00:00
|
|
|
switch {
|
2024-06-06 04:50:42 +00:00
|
|
|
case line == "":
|
|
|
|
continue
|
2024-06-05 05:26:03 +00:00
|
|
|
case strings.HasPrefix(line, "#"):
|
|
|
|
continue
|
|
|
|
case strings.HasPrefix(line, "//"):
|
|
|
|
continue
|
|
|
|
case strings.HasPrefix(line, "-"):
|
2024-06-05 05:01:15 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
lines = append(lines, line)
|
|
|
|
}
|
|
|
|
|
|
|
|
return lines, nil
|
|
|
|
}
|
2024-06-06 04:50:42 +00:00
|
|
|
|
2024-06-07 05:26:49 +00:00
|
|
|
type EsoAddon struct {
|
2024-06-07 06:15:14 +00:00
|
|
|
name string
|
|
|
|
version string
|
|
|
|
path string
|
2024-06-06 04:50:42 +00:00
|
|
|
}
|
|
|
|
|
2024-06-07 05:26:49 +00:00
|
|
|
func eso_ui_stat_init(addon_url string) (EsoAddon, error) {
|
2024-06-07 21:17:54 +00:00
|
|
|
addon_resp, error := http.Get(addon_url)
|
2024-06-06 04:50:42 +00:00
|
|
|
if error != nil {
|
2024-06-07 05:26:49 +00:00
|
|
|
return EsoAddon{}, error
|
2024-06-06 04:50:42 +00:00
|
|
|
}
|
2024-06-07 21:17:54 +00:00
|
|
|
defer addon_resp.Body.Close()
|
2024-06-06 04:50:42 +00:00
|
|
|
|
2024-06-07 21:17:54 +00:00
|
|
|
if addon_resp.StatusCode == http.StatusNotFound {
|
|
|
|
return EsoAddon{}, errors.New(http.StatusText(addon_resp.StatusCode))
|
2024-06-06 04:50:42 +00:00
|
|
|
}
|
|
|
|
|
2024-06-07 21:17:54 +00:00
|
|
|
addon_body, error := io.ReadAll(addon_resp.Body)
|
|
|
|
if error != nil {
|
|
|
|
return EsoAddon{}, error
|
|
|
|
}
|
|
|
|
|
|
|
|
download_page_url := strings.Replace(addon_url, "info", "download", -1)
|
|
|
|
download_resp, error := http.Get(download_page_url)
|
|
|
|
if error != nil {
|
|
|
|
return EsoAddon{}, error
|
|
|
|
}
|
|
|
|
defer download_resp.Body.Close()
|
|
|
|
|
|
|
|
if download_resp.StatusCode == http.StatusNotFound {
|
|
|
|
return EsoAddon{}, errors.New(http.StatusText(download_resp.StatusCode))
|
|
|
|
}
|
|
|
|
|
|
|
|
download_body, error := io.ReadAll(download_resp.Body)
|
2024-06-06 04:50:42 +00:00
|
|
|
if error != nil {
|
2024-06-07 05:26:49 +00:00
|
|
|
return EsoAddon{}, error
|
2024-06-06 04:50:42 +00:00
|
|
|
}
|
|
|
|
|
2024-06-07 06:15:14 +00:00
|
|
|
name := ESOUI_NAME.FindStringSubmatch(addon_url)[1]
|
2024-06-07 21:17:54 +00:00
|
|
|
version := ESOUI_VERSION.FindStringSubmatch(string(addon_body))[1]
|
|
|
|
path := string(ESOUI_DOWNLOAD.Find(download_body))
|
2024-06-07 06:15:14 +00:00
|
|
|
|
|
|
|
return EsoAddon{name, version, path}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func eso_live_stat_init(eso_live_name string) (EsoAddon, error) {
|
2024-06-07 21:17:54 +00:00
|
|
|
path := filepath.Join(args.Out_dir, eso_live_name)
|
2024-06-07 06:15:14 +00:00
|
|
|
|
|
|
|
content, error := os.ReadFile(filepath.Join(path, eso_live_name+".txt"))
|
|
|
|
if error != nil {
|
|
|
|
return EsoAddon{}, error
|
|
|
|
}
|
|
|
|
|
|
|
|
version := LIVE_VERSION.FindStringSubmatch(string(content))[1]
|
2024-06-06 04:50:42 +00:00
|
|
|
|
2024-06-07 06:15:14 +00:00
|
|
|
return EsoAddon{eso_live_name, version, path}, nil
|
2024-06-06 04:50:42 +00:00
|
|
|
}
|
2024-06-07 21:17:54 +00:00
|
|
|
|
|
|
|
func eso_ui_get_unzip(esoui_url string, out_dir string) error {
|
|
|
|
response, error := http.Get(esoui_url)
|
|
|
|
if error != nil {
|
|
|
|
return error
|
|
|
|
}
|
|
|
|
defer response.Body.Close()
|
|
|
|
|
|
|
|
if response.StatusCode == http.StatusNotFound {
|
|
|
|
return errors.New(http.StatusText(response.StatusCode))
|
|
|
|
}
|
|
|
|
|
|
|
|
body, error := io.ReadAll(response.Body)
|
|
|
|
if error != nil {
|
|
|
|
return error
|
|
|
|
}
|
|
|
|
|
|
|
|
reader := bytes.NewReader(body)
|
|
|
|
zip_reader, error := zip.NewReader(reader, int64(len(body)))
|
|
|
|
if error != nil {
|
|
|
|
return error
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, zipped_file := range zip_reader.File {
|
|
|
|
if zipped_file.Mode().IsDir() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
zipped_file_open, error := zipped_file.Open()
|
|
|
|
if error != nil {
|
|
|
|
return error
|
|
|
|
}
|
|
|
|
|
|
|
|
name := filepath.Join(out_dir, zipped_file.Name)
|
|
|
|
os.MkdirAll(filepath.Dir(name), os.ModePerm)
|
|
|
|
|
|
|
|
create, error := os.Create(name)
|
|
|
|
if error != nil {
|
|
|
|
return error
|
|
|
|
}
|
|
|
|
defer create.Close()
|
|
|
|
|
|
|
|
create.ReadFrom(zipped_file_open)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2024-06-07 21:44:31 +00:00
|
|
|
|
|
|
|
func ttc_update(out_path string) error {
|
|
|
|
response, error := http.Get(TCC_PRICE_TABLE_URI)
|
|
|
|
if error != nil {
|
|
|
|
return error
|
|
|
|
}
|
|
|
|
defer response.Body.Close()
|
|
|
|
|
|
|
|
if response.StatusCode == http.StatusNotFound {
|
|
|
|
return errors.New(http.StatusText(response.StatusCode))
|
|
|
|
}
|
|
|
|
|
|
|
|
body, error := io.ReadAll(response.Body)
|
|
|
|
if error != nil {
|
|
|
|
return error
|
|
|
|
}
|
|
|
|
|
|
|
|
reader := bytes.NewReader(body)
|
|
|
|
zip_reader, error := zip.NewReader(reader, int64(len(body)))
|
|
|
|
if error != nil {
|
|
|
|
return error
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, zipped_file := range zip_reader.File {
|
|
|
|
if zipped_file.Mode().IsDir() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
zipped_file_open, error := zipped_file.Open()
|
|
|
|
if error != nil {
|
|
|
|
return error
|
|
|
|
}
|
|
|
|
|
|
|
|
name := filepath.Join(out_path, zipped_file.Name)
|
|
|
|
os.MkdirAll(filepath.Dir(name), os.ModePerm)
|
|
|
|
|
|
|
|
create, error := os.Create(name)
|
|
|
|
if error != nil {
|
|
|
|
return error
|
|
|
|
}
|
|
|
|
defer create.Close()
|
|
|
|
|
|
|
|
create.ReadFrom(zipped_file_open)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|