Skip to content

Commit dd32f8a

Browse files
committed
feat: addon updates and full uninstall
1 parent 43a03d3 commit dd32f8a

8 files changed

Lines changed: 335 additions & 12 deletions

File tree

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,18 @@ Uninstall BetterDiscord by providing a Discord install path:
9090
bdcli uninstall --path /path/to/Discord
9191
```
9292

93+
Uninject BetterDiscord from all detected Discord installations (without deleting data):
94+
95+
```bash
96+
bdcli uninstall --all
97+
```
98+
99+
Fully uninstall BetterDiscord from all Discord installations and remove all BetterDiscord folders:
100+
101+
```bash
102+
bdcli uninstall --full
103+
```
104+
93105
### Check Version
94106

95107
```bash
@@ -124,6 +136,7 @@ bdcli plugins list
124136
bdcli plugins info <name>
125137
bdcli plugins install <name|id|url>
126138
bdcli plugins update <name|id|url>
139+
bdcli plugins update <name|id> --check # Check for updates without installing
127140
bdcli plugins remove <name|id>
128141
```
129142

@@ -134,6 +147,7 @@ bdcli themes list
134147
bdcli themes info <name>
135148
bdcli themes install <name|id|url>
136149
bdcli themes update <name|id|url>
150+
bdcli themes update <name|id> --check # Check for updates without installing
137151
bdcli themes remove <name|id>
138152
```
139153

cmd/plugins.go

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"github.com/spf13/cobra"
99
)
1010

11-
func init() {
11+
func initPluginsCmd() {
1212
// Parent command: plugins
1313
pluginsCmd.AddCommand(pluginsListCmd)
1414
pluginsCmd.AddCommand(pluginsInfoCmd)
@@ -18,6 +18,11 @@ func init() {
1818
rootCmd.AddCommand(pluginsCmd)
1919
}
2020

21+
func init() {
22+
initPluginsCmd()
23+
pluginsUpdateCmd.Flags().BoolP("check", "c", false, "Check for available updates without installing")
24+
}
25+
2126
var pluginsCmd = &cobra.Command{
2227
Use: "plugins",
2328
Short: "Manage BetterDiscord plugins",
@@ -80,6 +85,18 @@ var pluginsInstallCmd = &cobra.Command{
8085
Args: cobra.ExactArgs(1),
8186
RunE: func(cmd *cobra.Command, args []string) error {
8287
identifier := args[0]
88+
// Check if not a URL and already installed
89+
if !isURL(identifier) {
90+
if existing := betterdiscord.FindAddon(betterdiscord.AddonPlugin, identifier); existing != nil {
91+
name := existing.Meta.Name
92+
if name == "" {
93+
name = existing.BaseName
94+
}
95+
output.Printf("⚠️ Plugin '%s' is already installed.\n", name)
96+
output.Println("💡 To update the plugin, use: bdcli plugins update <name|id|url>")
97+
return nil
98+
}
99+
}
83100
resolved, err := betterdiscord.InstallAddon(betterdiscord.AddonPlugin, identifier)
84101
if err != nil {
85102
return err
@@ -96,10 +113,20 @@ var pluginsRemoveCmd = &cobra.Command{
96113
Args: cobra.ExactArgs(1),
97114
RunE: func(cmd *cobra.Command, args []string) error {
98115
identifier := args[0]
116+
// Check if addon exists before attempting removal
117+
existing := betterdiscord.FindAddon(betterdiscord.AddonPlugin, identifier)
118+
if existing == nil {
119+
output.Printf("❌ Plugin '%s' is not installed.\n", identifier)
120+
return nil
121+
}
99122
if err := betterdiscord.RemoveAddon(betterdiscord.AddonPlugin, identifier); err != nil {
100123
return err
101124
}
102-
output.Printf("✅ Plugin removed: %s\n", identifier)
125+
name := existing.Meta.Name
126+
if name == "" {
127+
name = existing.BaseName
128+
}
129+
output.Printf("✅ Plugin removed: %s\n", name)
103130
return nil
104131
},
105132
}
@@ -110,6 +137,50 @@ var pluginsUpdateCmd = &cobra.Command{
110137
Args: cobra.ExactArgs(1),
111138
RunE: func(cmd *cobra.Command, args []string) error {
112139
identifier := args[0]
140+
checkOnly, _ := cmd.Flags().GetBool("check")
141+
142+
// For non-URL identifiers, check if update is available
143+
if !isURL(identifier) {
144+
existing := betterdiscord.FindAddon(betterdiscord.AddonPlugin, identifier)
145+
if existing == nil {
146+
output.Printf("❌ Plugin '%s' is not installed.\n", identifier)
147+
return nil
148+
}
149+
150+
// Try to fetch from store to check version
151+
store, err := betterdiscord.FetchAddonFromStore(identifier)
152+
if err == nil && store != nil {
153+
localVersion := existing.Meta.Version
154+
storeVersion := store.Version
155+
156+
if localVersion == storeVersion {
157+
localName := existing.Meta.Name
158+
if localName == "" {
159+
localName = existing.BaseName
160+
}
161+
output.Printf("✅ Plugin '%s' is already up to date (v%s)\n", localName, localVersion)
162+
return nil
163+
}
164+
165+
localName := existing.Meta.Name
166+
if localName == "" {
167+
localName = existing.BaseName
168+
}
169+
170+
if checkOnly {
171+
output.Printf("📦 Update available for '%s'\n", localName)
172+
output.Printf(" Current: v%s → Available: v%s\n", localVersion, storeVersion)
173+
output.Println("💡 To install the update, use: bdcli plugins update <name|id|url> (without --check)")
174+
return nil
175+
}
176+
}
177+
}
178+
179+
if checkOnly {
180+
output.Println("⚠️ Cannot check version when using direct URL")
181+
return nil
182+
}
183+
113184
resolved, err := betterdiscord.UpdateAddon(betterdiscord.AddonPlugin, identifier)
114185
if err != nil {
115186
return err
@@ -118,3 +189,4 @@ var pluginsUpdateCmd = &cobra.Command{
118189
return nil
119190
},
120191
}
192+

cmd/root.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cmd
33
import (
44
"fmt"
55
"io"
6+
"net/url"
67
"os"
78
"strings"
89

@@ -44,6 +45,12 @@ func IsDebugBuild() bool {
4445
return buildVersion == "dev"
4546
}
4647

48+
// isURL checks if a string is a valid URL
49+
func isURL(input string) bool {
50+
parsed, err := url.Parse(input)
51+
return err == nil && parsed.Scheme != "" && parsed.Host != ""
52+
}
53+
4754
var silent bool
4855

4956
func init() {

cmd/themes.go

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,7 @@ import (
99
)
1010

1111
func init() {
12-
// Parent command: themes
13-
themesCmd.AddCommand(themesListCmd)
14-
themesCmd.AddCommand(themesInfoCmd)
15-
themesCmd.AddCommand(themesInstallCmd)
16-
themesCmd.AddCommand(themesRemoveCmd)
17-
themesCmd.AddCommand(themesUpdateCmd)
18-
rootCmd.AddCommand(themesCmd)
12+
initThemesCmd()
1913
}
2014

2115
var themesCmd = &cobra.Command{
@@ -80,6 +74,18 @@ var themesInstallCmd = &cobra.Command{
8074
Args: cobra.ExactArgs(1),
8175
RunE: func(cmd *cobra.Command, args []string) error {
8276
identifier := args[0]
77+
// Check if not a URL and already installed
78+
if !isURL(identifier) {
79+
if existing := betterdiscord.FindAddon(betterdiscord.AddonTheme, identifier); existing != nil {
80+
name := existing.Meta.Name
81+
if name == "" {
82+
name = existing.BaseName
83+
}
84+
output.Printf("⚠️ Theme '%s' is already installed.\n", name)
85+
output.Println("💡 To update the theme, use: bdcli themes update <name|id|url>")
86+
return nil
87+
}
88+
}
8389
resolved, err := betterdiscord.InstallAddon(betterdiscord.AddonTheme, identifier)
8490
if err != nil {
8591
return err
@@ -96,10 +102,20 @@ var themesRemoveCmd = &cobra.Command{
96102
Args: cobra.ExactArgs(1),
97103
RunE: func(cmd *cobra.Command, args []string) error {
98104
identifier := args[0]
105+
// Check if addon exists before attempting removal
106+
existing := betterdiscord.FindAddon(betterdiscord.AddonTheme, identifier)
107+
if existing == nil {
108+
output.Printf("❌ Theme '%s' is not installed.\n", identifier)
109+
return nil
110+
}
99111
if err := betterdiscord.RemoveAddon(betterdiscord.AddonTheme, identifier); err != nil {
100112
return err
101113
}
102-
output.Printf("✅ Theme removed: %s\n", identifier)
114+
name := existing.Meta.Name
115+
if name == "" {
116+
name = existing.BaseName
117+
}
118+
output.Printf("✅ Theme removed: %s\n", name)
103119
return nil
104120
},
105121
}
@@ -110,6 +126,50 @@ var themesUpdateCmd = &cobra.Command{
110126
Args: cobra.ExactArgs(1),
111127
RunE: func(cmd *cobra.Command, args []string) error {
112128
identifier := args[0]
129+
checkOnly, _ := cmd.Flags().GetBool("check")
130+
131+
// For non-URL identifiers, check if update is available
132+
if !isURL(identifier) {
133+
existing := betterdiscord.FindAddon(betterdiscord.AddonTheme, identifier)
134+
if existing == nil {
135+
output.Printf("❌ Theme '%s' is not installed.\n", identifier)
136+
return nil
137+
}
138+
139+
// Try to fetch from store to check version
140+
store, err := betterdiscord.FetchAddonFromStore(identifier)
141+
if err == nil && store != nil {
142+
localVersion := existing.Meta.Version
143+
storeVersion := store.Version
144+
145+
if localVersion == storeVersion {
146+
localName := existing.Meta.Name
147+
if localName == "" {
148+
localName = existing.BaseName
149+
}
150+
output.Printf("✅ Theme '%s' is already up to date (v%s)\n", localName, localVersion)
151+
return nil
152+
}
153+
154+
localName := existing.Meta.Name
155+
if localName == "" {
156+
localName = existing.BaseName
157+
}
158+
159+
if checkOnly {
160+
output.Printf("📦 Update available for '%s'\n", localName)
161+
output.Printf(" Current: v%s → Available: v%s\n", localVersion, storeVersion)
162+
output.Println("💡 To install the update, use: bdcli themes update <name|id|url> (without --check)")
163+
return nil
164+
}
165+
}
166+
}
167+
168+
if checkOnly {
169+
output.Println("⚠️ Cannot check version when using direct URL")
170+
return nil
171+
}
172+
113173
resolved, err := betterdiscord.UpdateAddon(betterdiscord.AddonTheme, identifier)
114174
if err != nil {
115175
return err
@@ -118,3 +178,14 @@ var themesUpdateCmd = &cobra.Command{
118178
return nil
119179
},
120180
}
181+
182+
func initThemesCmd() {
183+
// Parent command: themes
184+
themesCmd.AddCommand(themesListCmd)
185+
themesCmd.AddCommand(themesInfoCmd)
186+
themesCmd.AddCommand(themesInstallCmd)
187+
themesCmd.AddCommand(themesRemoveCmd)
188+
themesCmd.AddCommand(themesUpdateCmd)
189+
rootCmd.AddCommand(themesCmd)
190+
themesUpdateCmd.Flags().BoolP("check", "c", false, "Check for available updates without installing")
191+
}

0 commit comments

Comments
 (0)