diff --git a/main.go b/main.go index 8c065c9..e7b6993 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "encoding/json" "fmt" "io/ioutil" @@ -9,18 +10,26 @@ import ( "os" "path" "runtime" + "strings" ) +type obsPackageFile struct { + URL string `json:"url"` + Version int `json:"version"` + Files []struct { + Name string `json:"name"` + Version int `json:"version"` + } `json:"files"` +} + type obsServicesFile struct { - FormatVersion int `json:"format_version"` - Services []obsService `json:"services"` + FormatVersion int `json:"format_version"` + Services []interface{} `json:"services"` } type obsService struct { - Name string `json:"name"` - AltNames []string `json:"alt_names,omitempty"` - Common bool `json:"common,omitempty"` - Servers []struct { + Name string `json:"name"` + Servers []struct { Name string `json:"name"` URL string `json:"url"` } `json:"servers"` @@ -33,16 +42,6 @@ type obsService struct { Bframes *int `json:"bframes,omitempty"` X264Opts string `json:"x264opts,omitempty"` } `json:"recommended,omitempty"` - // For some reason a few services use 'recommend' instead of 'recommended' - Recommend *struct { - Keyint *int `json:"keyint,omitempty"` - Profile string `json:"profile,omitempty"` - Output string `json:"output,omitempty"` - MaxVideoBitrate int `json:"max video bitrate,omitempty"` - MaxAudioBitrate int `json:"max audio bitrate,omitempty"` - Bframes *int `json:"bframes,omitempty"` - X264Opts string `json:"x264opts,omitempty"` - } `json:"recommend,omitempty"` } type logWriter struct { @@ -73,12 +72,16 @@ func main() { log.Println() - servicesFiles := findObsDirectories() + servicePaths := findObsDirectories() + + for _, servicePath := range servicePaths { + updateFromOfficialSource(servicePath) + } log.Println() - for _, serviceFile := range servicesFiles { - patchFile(serviceFile, glimeshService) + for _, servicePath := range servicePaths { + patchFile(path.Join(servicePath, "services.json"), glimeshService) } log.Println() @@ -117,20 +120,15 @@ func patchFile(filePath string, newService obsService) { byteValue, err := ioutil.ReadAll(servicesFile) json.Unmarshal(byteValue, &services) - foundGlimesh := false - for i := 0; i < len(services.Services); i++ { - if services.Services[i].Name == "Glimesh" { - foundGlimesh = true - } - } + foundGlimesh := strings.Contains(string(byteValue), "Glimesh") servicesFile.Close() if foundGlimesh == false { services.Services = append(services.Services, newService) - whatever, err := json.MarshalIndent(services, "", " ") - err = os.WriteFile(filePath, whatever, 0644) + newContents, err := customJSONMarshal(services) + err = os.WriteFile(filePath, newContents, 0644) if err != nil { log.Printf("⛔️ Failed to patch file: %s", filePath) panicAndPause("⛔️ Please try running the program as an Administrator") @@ -142,6 +140,43 @@ func patchFile(filePath string, newService obsService) { } } +func updateFromOfficialSource(servicePath string) { + jsonFile, err := os.Open(path.Join(servicePath, "package.json")) + if err != nil { + fmt.Println(err) + } + defer jsonFile.Close() + packageRaw, _ := ioutil.ReadAll(jsonFile) + + var obsPackage obsPackageFile + json.Unmarshal(packageRaw, &obsPackage) + + packageURL := obsPackage.URL + "/services.json" + + resp, err := http.Get(packageURL) + if err != nil { + panicAndPause(err) + } + + if resp.StatusCode != http.StatusOK { + panicAndPause(fmt.Sprintf("Got an error code from %s", packageURL)) + } + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + panicAndPause(err) + } + + servicesFile := path.Join(servicePath, "services2.json") + err = os.WriteFile(servicesFile, data, 0644) + if err != nil { + log.Printf("⛔️ Failed to patch file: %s", servicesFile) + panicAndPause("⛔️ Please try running the program as an Administrator") + } + + log.Printf("💽 Downloaded fresh services file from %s\n", packageURL) +} + func findObsDirectories() (services []string) { configDir, err := os.UserConfigDir() if err != nil { @@ -149,16 +184,16 @@ func findObsDirectories() (services []string) { } // Traditional config based path, that beautiful open source projects like OBS Studio use - obsPath := path.Join(configDir, "obs-studio", "plugin_config", "rtmp-services", "services.json") - slobsPath := path.Join(configDir, "slobs-client", "plugin_config", "rtmp-services", "services.json") + obsPath := path.Join(configDir, "obs-studio", "plugin_config", "rtmp-services") + slobsPath := path.Join(configDir, "slobs-client", "plugin_config", "rtmp-services") - if _, err := os.Stat(obsPath); err == nil { + if _, err := os.Stat(path.Join(obsPath, "services.json")); err == nil { // OBS Studio Exists log.Printf("🔍 Detected OBS Studio at: %s\n", obsPath) services = append(services, obsPath) } - if _, err := os.Stat(slobsPath); err == nil { + if _, err := os.Stat(path.Join(slobsPath, "services.json")); err == nil { // Streamlabs OBS Exists log.Printf("🔍 Detected Streamlabs OBS at: %s\n", slobsPath) services = append(services, slobsPath) @@ -168,17 +203,17 @@ func findObsDirectories() (services []string) { if runtime.GOOS == "windows" { // Weird compiled electron path for Windows SLOBS // C:\Program Files\Streamlabs OBS\resources\app.asar.unpacked\node_modules\obs-studio-node\data\obs-plugins\rtmp-services - slobs32bitPath := path.Join(os.Getenv("programfiles(x86)"), "Streamlabs OBS", "resources", "app.asar.unpacked", "node_modules", "obs-studio-node", "data", "obs-plugins", "rtmp-services", "services.json") + slobs32bitPath := path.Join(os.Getenv("programfiles(x86)"), "Streamlabs OBS", "resources", "app.asar.unpacked", "node_modules", "obs-studio-node", "data", "obs-plugins", "rtmp-services") - slobs64bitPath := path.Join(os.Getenv("programfiles"), "Streamlabs OBS", "resources", "app.asar.unpacked", "node_modules", "obs-studio-node", "data", "obs-plugins", "rtmp-services", "services.json") + slobs64bitPath := path.Join(os.Getenv("programfiles"), "Streamlabs OBS", "resources", "app.asar.unpacked", "node_modules", "obs-studio-node", "data", "obs-plugins", "rtmp-services") - if _, err := os.Stat(slobs32bitPath); err == nil { + if _, err := os.Stat(path.Join(slobs32bitPath, "services.json")); err == nil { // OBS Studio Exists log.Printf("🔍 Detected SLOBS Electron 32-bit at: %s\n", slobs32bitPath) services = append(services, slobs32bitPath) } - if _, err := os.Stat(slobs64bitPath); err == nil { + if _, err := os.Stat(path.Join(slobs64bitPath, "services.json")); err == nil { // OBS Studio Exists log.Printf("🔍 Detected SLOBS Electron 64-bit at: %s\n", slobs64bitPath) services = append(services, slobs64bitPath) @@ -189,9 +224,9 @@ func findObsDirectories() (services []string) { if runtime.GOOS == "darwin" { // Weird compiled electron path for Mac SLOBS // /Applications/Streamlabs OBS.app/Contents/Resources/app.asar.unpacked/node_modules/obs-studio-node/data/obs-plugins/rtmp-services/services.json - slobsAppPath := path.Join("/", "Applications", "Streamlabs OBS.app", "Contents", "Resources", "app.asar.unpacked", "node_modules", "obs-studio-node", "data", "obs-plugins", "rtmp-services", "services.json") + slobsAppPath := path.Join("/", "Applications", "Streamlabs OBS.app", "Contents", "Resources", "app.asar.unpacked", "node_modules", "obs-studio-node", "data", "obs-plugins", "rtmp-services") - if _, err := os.Stat(slobsAppPath); err == nil { + if _, err := os.Stat(path.Join(slobsAppPath, "services.json")); err == nil { // OBS Studio Exists log.Printf("🔍 Detected SLOBS Electron at: %s\n", slobsAppPath) services = append(services, slobsAppPath) @@ -200,3 +235,19 @@ func findObsDirectories() (services []string) { return services } + +func customJSONMarshal(t interface{}) ([]byte, error) { + buffer := &bytes.Buffer{} + + encoder := json.NewEncoder(buffer) + encoder.SetEscapeHTML(false) + err := encoder.Encode(t) + + var buf bytes.Buffer + err = json.Indent(&buf, buffer.Bytes(), "", " ") + if err != nil { + return nil, err + } + + return buf.Bytes(), err +}