diff --git a/config.example.ini b/config.example.ini index 5a83ae7..9cbc888 100644 --- a/config.example.ini +++ b/config.example.ini @@ -122,6 +122,33 @@ link-viewer=xdg-open # y2-pattern=*youtu.be/* # y2-use=mpv +[desktop-notification] +# Under this section you can turn on desktop notifications + +# Notification when someone follows you +# default=false +followers=false + +# Notification when someone favorites one of your toots +# default=false +favorite=false + +# Notification when someone mentions you +# default=false +mention=false + +# Notification when someone boosts one of your toots +# default=false +boost=false + +# Notification of poll results +# default=false +poll=false + +# New posts in current timeline +# default=false +posts=false + [style] # All styles can be represented in their HEX value like #ffffff or # with their name, so in this case white. diff --git a/config.go b/config.go index 85cf657..9e8d55d 100644 --- a/config.go +++ b/config.go @@ -12,11 +12,12 @@ import ( ) type Config struct { - General GeneralConfig - Style StyleConfig - Media MediaConfig - OpenPattern OpenPatternConfig - OpenCustom OpenCustomConfig + General GeneralConfig + Style StyleConfig + Media MediaConfig + OpenPattern OpenPatternConfig + OpenCustom OpenCustomConfig + NotificationConfig NotificationConfig } type GeneralConfig struct { @@ -89,6 +90,26 @@ type OpenCustomConfig struct { OpenCustoms []OpenCustom } +type NotificationType uint + +const ( + NotificationFollower = iota + NotificationFavorite + NotificationMention + NotificationBoost + NotificationPoll + NotificationPost +) + +type NotificationConfig struct { + NotificationFollower bool + NotificationFavorite bool + NotificationMention bool + NotificationBoost bool + NotificationPoll bool + NotificationPost bool +} + func parseColor(input string, def string, xrdb map[string]string) tcell.Color { if input == "" { return tcell.GetColor(def) @@ -339,6 +360,17 @@ func ParseCustom(cfg *ini.File) OpenCustomConfig { return oc } +func ParseNotifications(cfg *ini.File) NotificationConfig { + nc := NotificationConfig{} + nc.NotificationFollower = cfg.Section("desktop-notification").Key("followers").MustBool(false) + nc.NotificationFavorite = cfg.Section("desktop-notification").Key("favorite").MustBool(false) + nc.NotificationMention = cfg.Section("desktop-notification").Key("mention").MustBool(false) + nc.NotificationBoost = cfg.Section("desktop-notification").Key("boost").MustBool(false) + nc.NotificationPoll = cfg.Section("desktop-notification").Key("poll").MustBool(false) + nc.NotificationPost = cfg.Section("desktop-notification").Key("posts").MustBool(false) + return nc +} + func ParseConfig(filepath string) (Config, error) { cfg, err := ini.LoadSources(ini.LoadOptions{ SpaceBeforeInlineComment: true, @@ -352,6 +384,7 @@ func ParseConfig(filepath string) (Config, error) { conf.Style = parseStyle(cfg) conf.OpenPattern = ParseOpenPattern(cfg) conf.OpenCustom = ParseCustom(cfg) + conf.NotificationConfig = ParseNotifications(cfg) return conf, nil } @@ -498,6 +531,33 @@ link-viewer=xdg-open # y2-pattern=*youtu.be/* # y2-use=mpv +[desktop-notification] +# Under this section you can turn on desktop notifications + +# Notification when someone follows you +# default=false +followers=false + +# Notification when someone favorites one of your toots +# default=false +favorite=false + +# Notification when someone mentions you +# default=false +mention=false + +# Notification when someone boosts one of your toots +# default=false +boost=false + +# Notification of poll results +# default=false +poll=false + +# New posts in current timeline +# default=false +posts=false + [style] # All styles can be represented in their HEX value like #ffffff or # with their name, so in this case white. diff --git a/feed.go b/feed.go index 8511f32..16d17f3 100644 --- a/feed.go +++ b/feed.go @@ -533,6 +533,11 @@ func (t *TimelineFeed) LoadNewer() int { statuses, err = t.app.API.GetStatuses(t.timelineType) } else { statuses, err = t.app.API.GetStatusesNewer(t.timelineType, t.statuses[0]) + newCount := len(statuses) + if newCount > 0 { + Notify(t.app.Config.NotificationConfig, NotificationPost, + fmt.Sprintf("%d new toots", newCount), "") + } } if err != nil { t.app.UI.CmdBar.ShowError(fmt.Sprintf("Couldn't load new toots. Error: %v\n", err)) @@ -1031,6 +1036,25 @@ func (n *NotificationsFeed) LoadNewer() int { notifications, err = n.app.API.GetNotifications() } else { notifications, err = n.app.API.GetNotificationsNewer(n.notifications[0]) + for _, o := range notifications { + switch o.Type { + case "follow": + Notify(n.app.Config.NotificationConfig, NotificationFollower, + "New follower", fmt.Sprintf("%s follows you", o.Account.Username)) + case "favourite": + Notify(n.app.Config.NotificationConfig, NotificationFavorite, + "Favorited your toot", fmt.Sprintf("%s favorited your toot", o.Account.Username)) + case "reblog": + Notify(n.app.Config.NotificationConfig, NotificationBoost, + "Boosted your toot", fmt.Sprintf("%s boosted your toot", o.Account.Username)) + case "mention": + Notify(n.app.Config.NotificationConfig, NotificationMention, + "Mentioned in toot", fmt.Sprintf("%s mentioned you", o.Account.Username)) + case "poll": + Notify(n.app.Config.NotificationConfig, NotificationPoll, + "Poll has ended", "") + } + } } if err != nil { n.app.UI.CmdBar.ShowError(fmt.Sprintf("Couldn't load new toots. Error: %v\n", err)) diff --git a/go.mod b/go.mod index 5c7d106..9679b0e 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,9 @@ go 1.14 require ( github.com/atotto/clipboard v0.1.4 github.com/gdamore/tcell/v2 v2.4.0 + github.com/gen2brain/beeep v0.0.0-20210529141713-5586760f0cc1 github.com/gobwas/glob v0.2.3 + github.com/godbus/dbus/v5 v5.0.4 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/icza/gox v0.0.0-20201215141822-6edfac6c05b5 github.com/kyoh86/xdg v1.2.0 diff --git a/go.sum b/go.sum index 223d9cd..c318496 100644 --- a/go.sum +++ b/go.sum @@ -11,10 +11,20 @@ github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo github.com/gdamore/tcell/v2 v2.3.3/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU= github.com/gdamore/tcell/v2 v2.4.0 h1:W6dxJEmaxYvhICFoTY3WrLLEXsQ11SaFnKGVEXW57KM= github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU= +github.com/gen2brain/beeep v0.0.0-20210529141713-5586760f0cc1 h1:Xh9mvwEmhbdXlRSsgn+N0zj/NqnKvpeqL08oKDHln2s= +github.com/gen2brain/beeep v0.0.0-20210529141713-5586760f0cc1/go.mod h1:ElSskYZe3oM8kThaHGJ+kiN2yyUMVXMZ7WxF9QqLDS8= +github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 h1:qZNfIGkIANxGv/OqtnntR4DfOY2+BgwR60cAcu/i3SE= +github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4/go.mod h1:kW3HQ4UdaAyrUCSSDR4xUzBKW6O2iA4uHhk7AtyYp10= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherwasm v1.1.0 h1:fA2uLoctU5+T3OhOn2vYP0DVT6pxc7xhTlBB1paATqQ= +github.com/gopherjs/gopherwasm v1.1.0/go.mod h1:SkZ8z7CWBz5VXbhJel8TxCmAcsQqzgWGR/8nMhyhZSI= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -42,6 +52,8 @@ github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= github.com/microcosm-cc/bluemonday v1.0.15 h1:J4uN+qPng9rvkBZBoBb8YGR+ijuklIMpSOZZLjYpbeY= github.com/microcosm-cc/bluemonday v1.0.15/go.mod h1:ZLvAzeakRwrGnzQEvstVzVt3ZpqOF2+sdFr0Om+ce30= +github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= +github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/rivo/tview v0.0.0-20210624155130-5f8430624688 h1:ljIaK7yl7pN/wBgNy6g86tzI9kNDldJT1dzo7aqr8Yk= @@ -53,6 +65,8 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykE github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk= +github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -70,6 +84,7 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/util.go b/util.go index 801b50c..9813612 100644 --- a/util.go +++ b/util.go @@ -15,6 +15,7 @@ import ( "github.com/atotto/clipboard" "github.com/gdamore/tcell/v2" + "github.com/gen2brain/beeep" "github.com/icza/gox/timex" "github.com/mattn/go-mastodon" "github.com/microcosm-cc/bluemonday" @@ -336,3 +337,34 @@ func OutputDate(status time.Time, today time.Time, long, short string, relativeD } return dateOutput } + +func Notify(nc NotificationConfig, t NotificationType, title string, body string) { + switch t { + case NotificationFollower: + if nc.NotificationFollower == false { + return + } + case NotificationFavorite: + if nc.NotificationFavorite == false { + return + } + case NotificationMention: + if nc.NotificationMention == false { + return + } + case NotificationBoost: + if nc.NotificationBoost == false { + return + } + case NotificationPoll: + if nc.NotificationPoll == false { + return + } + case NotificationPost: + if nc.NotificationPost == false { + return + } + } + + beeep.Notify(title, body, "") +}