Compare commits

...

2 commits

Author SHA1 Message Date
899ac49336
chore: split plugin configuration templates
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/tag/release Pipeline was successful
2025-06-15 13:03:52 +02:00
fc77c97547
feat: add configuration options for instagram and twitter plugins 2025-06-15 12:17:54 +02:00
9 changed files with 99 additions and 31 deletions

View file

@ -10,6 +10,11 @@ When creating, modifying, or removing plugins:
- Brief description of functionality
- Usage instructions with examples
- Any configuration requirements
3. **For plugins with configuration options:**
- Set `ConfigRequired: true` in the plugin's BasePlugin struct
- Add corresponding HTML form fields in `internal/admin/templates/channel_plugin_config.html`
- Use conditional template logic: `{{else if eq .ChannelPlugin.PluginID "plugin.id"}}`
- Include proper form labels, help text, and value binding
## Testing

View file

@ -23,5 +23,5 @@
### Social Media
- Twitter Link Expander: Automatically converts twitter.com and x.com links to fxtwitter.com links and removes tracking parameters. This allows for better media embedding in chat platforms.
- Instagram Link Expander: Automatically converts instagram.com links to ddinstagram.com links and removes tracking parameters. This allows for better media embedding in chat platforms.
- Twitter Link Expander: Automatically converts twitter.com and x.com links to alternative domain links and removes tracking parameters. This allows for better media embedding in chat platforms. Configure with `domain` option to set replacement domain (default: fxtwitter.com).
- Instagram Link Expander: Automatically converts instagram.com links to alternative domain links and removes tracking parameters. This allows for better media embedding in chat platforms. Configure with `domain` option to set replacement domain (default: ddinstagram.com).

View file

@ -16,7 +16,7 @@ import (
"github.com/gorilla/sessions"
)
//go:embed templates/*.html
//go:embed templates/*.html templates/plugins/*.html
var templateFS embed.FS
const (
@ -90,7 +90,7 @@ func New(cfg *config.Config, database *db.Database, version string) *Admin {
}
// Parse and register all templates
templateFiles := []string{
mainTemplateFiles := []string{
"index.html",
"login.html",
"change_password.html",
@ -101,7 +101,13 @@ func New(cfg *config.Config, database *db.Database, version string) *Admin {
"channel_plugin_config.html",
}
for _, tf := range templateFiles {
pluginTemplateFiles := []string{
"plugins/security.domainblock.html",
"plugins/social.instagram.html",
"plugins/social.twitter.html",
}
for _, tf := range mainTemplateFiles {
// Read template content from embedded filesystem
content, err := templateFS.ReadFile("templates/" + tf)
if err != nil {
@ -120,6 +126,20 @@ func New(cfg *config.Config, database *db.Database, version string) *Admin {
panic(err)
}
// If this is the channel_plugin_config template, also parse plugin templates
if tf == "channel_plugin_config.html" {
for _, pluginTf := range pluginTemplateFiles {
pluginContent, err := templateFS.ReadFile("templates/" + pluginTf)
if err != nil {
panic(err)
}
t, err = t.Parse(string(pluginContent))
if err != nil {
panic(err)
}
}
}
templates[tf] = t
}

View file

@ -9,16 +9,11 @@
<form method="post">
<!-- Plugin configuration fields -->
{{if eq .ChannelPlugin.PluginID "security.domainblock"}}
<div class="mb-3">
<label class="form-label">Blocked Domains</label>
<input type="text" class="form-control" name="blocked_domains"
value="{{with .ChannelPlugin.Config}}{{index . "blocked_domains"}}{{end}}"
placeholder="example.com, evil.org, ads.com">
<div class="form-text text-muted">
Enter comma-separated list of domains to block (e.g., example.com, evil.org).
Messages containing links to these domains will be blocked.
</div>
</div>
{{template "plugins/security.domainblock.html" .}}
{{else if eq .ChannelPlugin.PluginID "social.instagram"}}
{{template "plugins/social.instagram.html" .}}
{{else if eq .ChannelPlugin.PluginID "social.twitter"}}
{{template "plugins/social.twitter.html" .}}
{{else}}
<div class="alert alert-warning">
This plugin doesn't have specific configuration fields implemented yet.

View file

@ -0,0 +1,12 @@
{{define "plugins/security.domainblock.html"}}
<div class="mb-3">
<label class="form-label">Blocked Domains</label>
<input type="text" class="form-control" name="blocked_domains"
value="{{with .ChannelPlugin.Config}}{{index . "blocked_domains"}}{{end}}"
placeholder="example.com, evil.org, ads.com">
<div class="form-text text-muted">
Enter comma-separated list of domains to block (e.g., example.com, evil.org).
Messages containing links to these domains will be blocked.
</div>
</div>
{{end}}

View file

@ -0,0 +1,11 @@
{{define "plugins/social.instagram.html"}}
<div class="mb-3">
<label class="form-label">Replacement Domain</label>
<input type="text" class="form-control" name="domain"
value="{{with .ChannelPlugin.Config}}{{index . "domain"}}{{end}}"
placeholder="ddinstagram.com">
<div class="form-text text-muted">
Enter the domain to replace instagram.com links with. Default is ddinstagram.com if left empty.
</div>
</div>
{{end}}

View file

@ -0,0 +1,11 @@
{{define "plugins/social.twitter.html"}}
<div class="mb-3">
<label class="form-label">Replacement Domain</label>
<input type="text" class="form-control" name="domain"
value="{{with .ChannelPlugin.Config}}{{index . "domain"}}{{end}}"
placeholder="fxtwitter.com">
<div class="form-text text-muted">
Enter the domain to replace twitter.com and x.com links with. Default is fxtwitter.com if left empty.
</div>
</div>
{{end}}

View file

@ -18,9 +18,10 @@ type InstagramExpander struct {
func NewInstagramExpander() *InstagramExpander {
return &InstagramExpander{
BasePlugin: plugin.BasePlugin{
ID: "social.instagram",
Name: "Instagram Link Expander",
Help: "Automatically converts instagram.com links to ddinstagram.com links and removes tracking parameters",
ID: "social.instagram",
Name: "Instagram Link Expander",
Help: "Automatically converts instagram.com links to alternative domain links and removes tracking parameters. Configure 'domain' option to set replacement domain (default: ddinstagram.com)",
ConfigRequired: true,
},
}
}
@ -32,6 +33,12 @@ func (p *InstagramExpander) OnMessage(msg *model.Message, config map[string]inte
return nil
}
// Get replacement domain from config, default to ddinstagram.com
replacementDomain := "ddinstagram.com"
if domain, ok := config["domain"].(string); ok && domain != "" {
replacementDomain = domain
}
// Regex to match instagram.com links
// Match both http://instagram.com and https://instagram.com formats
// Also match www.instagram.com
@ -42,7 +49,7 @@ func (p *InstagramExpander) OnMessage(msg *model.Message, config map[string]inte
return nil
}
// Replace instagram.com with ddinstagram.com in the message and clean query parameters
// Replace instagram.com with configured domain in the message and clean query parameters
transformed := instagramRegex.ReplaceAllStringFunc(msg.Text, func(link string) string {
// Parse the URL
parsedURL, err := url.Parse(link)
@ -51,13 +58,13 @@ func (p *InstagramExpander) OnMessage(msg *model.Message, config map[string]inte
return link
}
// Ensure we don't change links that already come from ddinstagram.com
// Ensure we don't change links that already come from the replacement domain
if parsedURL.Host != "instagram.com" && parsedURL.Host != "www.instagram.com" {
return link
}
// Change the host
parsedURL.Host = "d.ddinstagram.com"
// Change the host to the configured domain
parsedURL.Host = replacementDomain
// Remove query parameters
parsedURL.RawQuery = ""

View file

@ -18,9 +18,10 @@ type TwitterExpander struct {
func NewTwitterExpander() *TwitterExpander {
return &TwitterExpander{
BasePlugin: plugin.BasePlugin{
ID: "social.twitter",
Name: "Twitter Link Expander",
Help: "Automatically converts twitter.com links to fxtwitter.com links and removes tracking parameters",
ID: "social.twitter",
Name: "Twitter Link Expander",
Help: "Automatically converts twitter.com and x.com links to alternative domain links and removes tracking parameters. Configure 'domain' option to set replacement domain (default: fxtwitter.com)",
ConfigRequired: true,
},
}
}
@ -32,6 +33,12 @@ func (p *TwitterExpander) OnMessage(msg *model.Message, config map[string]interf
return nil
}
// Get replacement domain from config, default to fxtwitter.com
replacementDomain := "fxtwitter.com"
if domain, ok := config["domain"].(string); ok && domain != "" {
replacementDomain = domain
}
// Regex to match twitter.com links
// Match both http://twitter.com and https://twitter.com formats
// Also match www.twitter.com
@ -42,22 +49,22 @@ func (p *TwitterExpander) OnMessage(msg *model.Message, config map[string]interf
return nil
}
// Replace twitter.com with fxtwitter.com in the message and clean query parameters
// Replace twitter.com/x.com with configured domain in the message and clean query parameters
transformed := twitterRegex.ReplaceAllStringFunc(msg.Text, func(link string) string {
// Parse the URL
parsedURL, err := url.Parse(link)
if err != nil {
// If parsing fails, just do the simple replacement
link = strings.Replace(link, "twitter.com", "fxtwitter.com", 1)
link = strings.Replace(link, "x.com", "fxtwitter.com", 1)
link = strings.Replace(link, "twitter.com", replacementDomain, 1)
link = strings.Replace(link, "x.com", replacementDomain, 1)
return link
}
// Change the host
// Change the host to the configured domain
if strings.Contains(parsedURL.Host, "twitter.com") {
parsedURL.Host = strings.Replace(parsedURL.Host, "twitter.com", "fxtwitter.com", 1)
parsedURL.Host = strings.Replace(parsedURL.Host, "twitter.com", replacementDomain, 1)
} else if strings.Contains(parsedURL.Host, "x.com") {
parsedURL.Host = strings.Replace(parsedURL.Host, "x.com", "fxtwitter.com", 1)
parsedURL.Host = strings.Replace(parsedURL.Host, "x.com", replacementDomain, 1)
}
// Remove query parameters