Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
229572be10 | |||
9af1dda45d | |||
5d4f13827c | |||
69de0397a3 | |||
4e846885dd | |||
d6ed947bb9 | |||
dc7febd2ad | |||
7c6b9c4a74 | |||
|
aeac9e4e26 | ||
|
c9706bd48a | ||
|
c4a1519d77 | ||
|
8306698f9a |
19
cmd/main.go
Normal file
19
cmd/main.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/mattburchett/go_telegram/pkg/core/config"
|
||||
"github.com/mattburchett/go_telegram/pkg/service/telegram"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conf, err := config.GetConfig("config.json")
|
||||
if err != nil {
|
||||
log.Fatal("Failed to read JSON.")
|
||||
}
|
||||
|
||||
tgBot := telegram.Bot{}
|
||||
tgBot.Config = conf
|
||||
tgBot.New(conf.Telegram.Token)
|
||||
}
|
17
go.mod
Normal file
17
go.mod
Normal file
@ -0,0 +1,17 @@
|
||||
module github.com/mattburchett/go_telegram
|
||||
|
||||
go 1.17
|
||||
|
||||
replace gopkg.in/tucnak/telebot.v2 => github.com/tucnak/telebot v0.0.0-20171121031619-29bd3707020c
|
||||
|
||||
require (
|
||||
github.com/yanzay/tbot v1.0.0
|
||||
github.com/yanzay/tbot/v2 v2.1.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect
|
||||
github.com/smartystreets/goconvey v1.7.2 // indirect
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
||||
github.com/yanzay/log v0.0.0-20160419144809-87352bb23506 // indirect
|
||||
)
|
23
go.sum
Normal file
23
go.sum
Normal file
@ -0,0 +1,23 @@
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
|
||||
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/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
|
||||
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
|
||||
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
||||
github.com/yanzay/log v0.0.0-20160419144809-87352bb23506 h1:RPrQRi67MUoUPg/3wwL9K9vKVWAB180e2WJgxC02CJE=
|
||||
github.com/yanzay/log v0.0.0-20160419144809-87352bb23506/go.mod h1:x2hAcqPbZzQz79Fzr9xEe7BM73+UsZ3nBucx2u30oSk=
|
||||
github.com/yanzay/tbot v1.0.0 h1:pKLHIvdiHRgU5iTfpWlgMTCWyD4vIQtAsOy7LCYMsAo=
|
||||
github.com/yanzay/tbot v1.0.0/go.mod h1:rS36e4e2P56jkI0bUuZtzjBBIwMIdBBTUHfI4tgG5BM=
|
||||
github.com/yanzay/tbot/v2 v2.1.0 h1:mppieSOIbzaCjp2en66Fz4unIJ57+aalQfdGbtYmaKg=
|
||||
github.com/yanzay/tbot/v2 v2.1.0/go.mod h1:q0+8JblBq9tLAnKHdBIZsHwDvMS9TfO6mNfaAk1VrHg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
56
pkg/core/config/config.go
Normal file
56
pkg/core/config/config.go
Normal file
@ -0,0 +1,56 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Config - This struct will hold configuration components.
|
||||
type Config struct {
|
||||
Telegram struct {
|
||||
Token string `json:"token"`
|
||||
ChatID string `json:"chatId"`
|
||||
Admins []int `json:"admins"`
|
||||
AuthorizedChats []string `json:"authorizedChats"`
|
||||
} `json:"telegram"`
|
||||
|
||||
Sonarr struct {
|
||||
URL string `json:"url"`
|
||||
APIKey string `json:"apiKey"`
|
||||
SeasonLimit int `json:"seasonLimit"`
|
||||
ProfileID int `json:"profileId"`
|
||||
} `json:"sonarr"`
|
||||
CouchPotato struct {
|
||||
URL string `json:"url"`
|
||||
APIKey string `json:"apiKey"`
|
||||
ProfileID string `json:"profileId`
|
||||
} `json:"couchpotato"`
|
||||
}
|
||||
|
||||
//GetConfig gets the configuration values for the api using the file in the supplied configPath.
|
||||
func GetConfig(configPath string) (Config, error) {
|
||||
if _, err := os.Stat(configPath); os.IsNotExist(err) {
|
||||
return Config{}, fmt.Errorf("could not find the config file at path %s", configPath)
|
||||
}
|
||||
log.Println("Loading Configuration File: " + configPath)
|
||||
return loadConfigFromFile(configPath)
|
||||
}
|
||||
|
||||
//if the config loaded from the file errors, no defaults will be loaded and the app will exit.
|
||||
func loadConfigFromFile(configPath string) (conf Config, err error) {
|
||||
file, err := os.Open(configPath)
|
||||
if err != nil {
|
||||
log.Printf("Error opening config file: %v", err)
|
||||
} else {
|
||||
defer file.Close()
|
||||
|
||||
err = json.NewDecoder(file).Decode(&conf)
|
||||
if err != nil {
|
||||
log.Printf("Error decoding config file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return conf, err
|
||||
}
|
1
pkg/service/couchpotato/admin.go
Normal file
1
pkg/service/couchpotato/admin.go
Normal file
@ -0,0 +1 @@
|
||||
package couchpotato
|
87
pkg/service/couchpotato/couchpotato.go
Normal file
87
pkg/service/couchpotato/couchpotato.go
Normal file
@ -0,0 +1,87 @@
|
||||
package couchpotato
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/mattburchett/go_telegram/pkg/core/config"
|
||||
"github.com/yanzay/tbot/v2"
|
||||
)
|
||||
|
||||
type couchpotatoSearch struct {
|
||||
Movies []struct {
|
||||
Title string `json:"original_title"`
|
||||
Imdb string `json:"imdb"`
|
||||
Year int `json:"year"`
|
||||
InLibrary bool `json:"in_library"`
|
||||
InWanted bool `json:"in_wanted"`
|
||||
} `json:"movies"`
|
||||
Success bool `json:"success"`
|
||||
}
|
||||
|
||||
type request struct {
|
||||
ImdbID string `json:"imdbid"`
|
||||
Title string `json:"title"`
|
||||
Year int `json:"year"`
|
||||
Requested bool `json:"requested"`
|
||||
Downloaded bool `json:"downloaded"`
|
||||
}
|
||||
|
||||
func (search couchpotatoSearch) Convert() []request {
|
||||
requests := []request{}
|
||||
for _, result := range search.Movies {
|
||||
requests = append(requests, request{
|
||||
ImdbID: result.Imdb,
|
||||
Title: result.Title,
|
||||
Year: result.Year,
|
||||
Requested: result.InWanted,
|
||||
Downloaded: result.InLibrary,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
return requests
|
||||
}
|
||||
|
||||
type response struct {
|
||||
Button string `json:"button"`
|
||||
Callback string `json:"callback"`
|
||||
}
|
||||
|
||||
// Search performs the lookup actions within CouchPotato
|
||||
func Search(m *tbot.Message, config config.Config) ([]response, error) {
|
||||
searchLookup, err := http.Get(config.CouchPotato.URL + config.CouchPotato.APIKey + "/movie.search?q=" + url.QueryEscape(strings.TrimPrefix(strings.TrimPrefix(m.Text, "/m"), " ")))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
search := couchpotatoSearch{}
|
||||
|
||||
searchData, err := ioutil.ReadAll(searchLookup.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
requestJSON := json.Unmarshal(searchData, &search)
|
||||
if requestJSON != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
requests := search.Convert()
|
||||
|
||||
responseData := []response{}
|
||||
for _, r := range requests {
|
||||
responseData = append(responseData,
|
||||
response{
|
||||
fmt.Sprintf("%v (%v)", r.Title, r.Year),
|
||||
fmt.Sprintf("%v", r.ImdbID),
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
return responseData, err
|
||||
}
|
24
pkg/service/sonarr/admin.go
Normal file
24
pkg/service/sonarr/admin.go
Normal file
@ -0,0 +1,24 @@
|
||||
package sonarr
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/mattburchett/go_telegram/pkg/core/config"
|
||||
"github.com/yanzay/tbot/v2"
|
||||
)
|
||||
|
||||
// Status contains the Sonarr request for system status.
|
||||
func Status(m *tbot.Message, config config.Config) (string, error) {
|
||||
r, err := http.Get(config.Sonarr.URL + "system/status?apikey=" + config.Sonarr.APIKey)
|
||||
if err != nil {
|
||||
return "Failed to contact Sonarr for data", err
|
||||
}
|
||||
|
||||
rd, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return "Failed to read Sonarr status data.", err
|
||||
}
|
||||
|
||||
return string(rd), err
|
||||
}
|
245
pkg/service/sonarr/sonarr.go
Normal file
245
pkg/service/sonarr/sonarr.go
Normal file
@ -0,0 +1,245 @@
|
||||
package sonarr
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/mattburchett/go_telegram/pkg/core/config"
|
||||
"github.com/yanzay/tbot/v2"
|
||||
)
|
||||
|
||||
// Response holds the information needed for Telegram callback.
|
||||
type response struct {
|
||||
Button string `json:"button"`
|
||||
Callback string `json:"callback"`
|
||||
}
|
||||
|
||||
type sonarrSearch []struct {
|
||||
Title string `json:"title"`
|
||||
SeasonCount int `json:"seasonCount"`
|
||||
Year int `json:"year"`
|
||||
TvdbID int `json:"tvdbId"`
|
||||
Downloaded bool `json:"downloaded"`
|
||||
QualityProfileID int `json:"qualityProfileId"`
|
||||
TitleSlug string `json:"titleSlug"`
|
||||
Images []struct {
|
||||
CoverType string `json:"coverType"`
|
||||
URL string `json:"url"`
|
||||
} `json:"images"`
|
||||
Seasons []struct {
|
||||
SeasonNumber int `json:"seasonNumber"`
|
||||
Monitored bool `json:"monitored"`
|
||||
} `json:"seasons"`
|
||||
ProfileID int `json:"profileId"`
|
||||
}
|
||||
|
||||
type sonarrAdd struct {
|
||||
Title string `json:"title"`
|
||||
TvdbID int `json:"tvdbId"`
|
||||
QualityProfileID int `json:"qualityProfileId"`
|
||||
TitleSlug string `json:"titleSlug"`
|
||||
Images []struct {
|
||||
CoverType string `json:"coverType"`
|
||||
URL string `json:"url"`
|
||||
} `json:"images"`
|
||||
Seasons []struct {
|
||||
SeasonNumber int `json:"seasonNumber"`
|
||||
Monitored bool `json:"monitored"`
|
||||
} `json:"seasons"`
|
||||
ProfileID int `json:"profileId"`
|
||||
RootFolderPath string `json:"rootFolderPath"`
|
||||
AddOptions struct {
|
||||
IgnoreEpisodesWithFiles bool `json:"ignoreEpisodesWithFiles"`
|
||||
IgnoreEpisodesWithoutFiles bool `json:"ignoreEpisodesWithoutFiles"`
|
||||
SearchForMIssingEpisodes bool `json:"searchForMissingEpisodes"`
|
||||
} `json:"addOptions"`
|
||||
}
|
||||
|
||||
type rootFolderLookup []struct {
|
||||
Path string `json:"path"`
|
||||
FreeSpace int64 `json:"freeSpace"`
|
||||
TotalSpace int64 `json:"totalSpace"`
|
||||
UnmappedFolders []struct {
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
} `json:"unmappedFolders"`
|
||||
ID int `json:"id"`
|
||||
}
|
||||
|
||||
// Search performs the lookup actions within Sonarr.
|
||||
func Search(m *tbot.Message, config config.Config) ([]response, error) {
|
||||
|
||||
var remote sonarrSearch
|
||||
var local sonarrSearch
|
||||
|
||||
// Perform series lookup
|
||||
remoteLookup, err := http.Get(config.Sonarr.URL +
|
||||
"series/lookup?apikey=" +
|
||||
config.Sonarr.APIKey +
|
||||
"&term=" +
|
||||
url.QueryEscape(strings.TrimPrefix(strings.TrimPrefix(m.Text, "/s"), " ")))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Perform series local database lookup.
|
||||
localLookup, err := http.Get(config.Sonarr.URL + "series?apikey=" + config.Sonarr.APIKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read remote and local Data
|
||||
remoteData, err := ioutil.ReadAll(remoteLookup.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
localData, err := ioutil.ReadAll(localLookup.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Unmarshal remote and local JSON
|
||||
remoteJSON := json.Unmarshal(remoteData, &remote)
|
||||
if remoteJSON != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
localJSON := json.Unmarshal(localData, &local)
|
||||
if localJSON != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check for downloaded items.
|
||||
for r := range remote {
|
||||
for l := range local {
|
||||
if remote[r].TvdbID == local[l].TvdbID {
|
||||
remote[r].Downloaded = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Form URLs and return to Telegram
|
||||
responseData := []response{}
|
||||
for k := range remote {
|
||||
responseData = append(responseData,
|
||||
response{
|
||||
fmt.Sprintf("%v%v%v (%v) - %v Seasons",
|
||||
seasonHandler(remote[k].SeasonCount, config.Sonarr.SeasonLimit),
|
||||
downloadedHandler(remote[k].Downloaded),
|
||||
remote[k].Title,
|
||||
remote[k].Year,
|
||||
remote[k].SeasonCount),
|
||||
fmt.Sprintf("%d%s%s", remote[k].TvdbID,
|
||||
strings.TrimSuffix(downloadedHandler(remote[k].Downloaded), " "),
|
||||
strings.TrimSuffix(seasonHandler(remote[k].SeasonCount, config.Sonarr.SeasonLimit), " ")),
|
||||
})
|
||||
}
|
||||
|
||||
return responseData, err
|
||||
|
||||
}
|
||||
|
||||
// Add will take the callback data and add the show to Sonarr.
|
||||
func Add(callback string, config config.Config) string {
|
||||
// Separate the TVDB ID
|
||||
tvdbid := strings.TrimPrefix(strings.TrimSuffix(strings.TrimSuffix(callback, "+"), "*"), "tv_")
|
||||
|
||||
// Look it up, to gather the information needed and the title.
|
||||
seriesLookup, err := http.Get(config.Sonarr.URL + "/series/lookup?apikey=" + config.Sonarr.APIKey + "&term=tvdb:" + tvdbid)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
seriesData, err := ioutil.ReadAll(seriesLookup.Body)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
series := sonarrSearch{}
|
||||
seriesJSON := json.Unmarshal(seriesData, &series)
|
||||
if seriesJSON != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
// If the "downloaded" asterisk is already in place, go ahead and return.
|
||||
if strings.Contains(callback, "*") {
|
||||
return fmt.Sprintf("%v has already been requested for download.", series[0].Title)
|
||||
}
|
||||
|
||||
// Gather the root folder location.
|
||||
rootFolderLookupQuery, err := http.Get(config.Sonarr.URL + "/rootfolder?apikey=" + config.Sonarr.APIKey)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
rootFolderData, err := ioutil.ReadAll(rootFolderLookupQuery.Body)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
rootFolder := rootFolderLookup{}
|
||||
rootFolderJSON := json.Unmarshal(rootFolderData, &rootFolder)
|
||||
if rootFolderJSON != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
// Form the JSON needed for adding to Sonarr.
|
||||
seriesAdd := sonarrAdd{
|
||||
TvdbID: series[0].TvdbID,
|
||||
Title: series[0].Title,
|
||||
// QualityProfileID: series[0].QualityProfileID,
|
||||
TitleSlug: series[0].TitleSlug,
|
||||
Images: series[0].Images,
|
||||
Seasons: series[0].Seasons,
|
||||
RootFolderPath: rootFolder[0].Path,
|
||||
ProfileID: config.Sonarr.ProfileID,
|
||||
}
|
||||
seriesAdd.AddOptions.IgnoreEpisodesWithFiles = false
|
||||
seriesAdd.AddOptions.IgnoreEpisodesWithoutFiles = false
|
||||
seriesAdd.AddOptions.SearchForMIssingEpisodes = true
|
||||
|
||||
// Post it to Sonarr to be added.
|
||||
seriesAddJSON, err := json.Marshal(seriesAdd)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
seriesAddReq, err := http.Post(config.Sonarr.URL+"/series?apikey="+config.Sonarr.APIKey, "application/json", bytes.NewBuffer(seriesAddJSON))
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
if seriesAddReq.StatusCode != 201 {
|
||||
return "There was an error processing this request."
|
||||
}
|
||||
return fmt.Sprintf("%s has been queued for download.", series[0].Title)
|
||||
|
||||
}
|
||||
|
||||
// downloadHandler returns the proper string that should be shown in the Telegram response.
|
||||
func downloadedHandler(downloaded bool) string {
|
||||
if downloaded {
|
||||
return "* "
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// seasonHandler returns the proper string that should be shown in the Telegram response.
|
||||
// it is also used to prevent non-admins from downloading shows with a high number of seasons.
|
||||
func seasonHandler(seasonCount int, seasonLimit int) string {
|
||||
if seasonLimit == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
if seasonCount >= seasonLimit {
|
||||
return "+ "
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
36
pkg/service/telegram/admin.go
Normal file
36
pkg/service/telegram/admin.go
Normal file
@ -0,0 +1,36 @@
|
||||
package telegram
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/yanzay/tbot/v2"
|
||||
)
|
||||
|
||||
func (tb *Bot) myID(m *tbot.Message) {
|
||||
if tb.adminCheck(m.From.ID, false) {
|
||||
tb.Client.SendMessage(m.Chat.ID, strconv.Itoa(m.From.ID))
|
||||
return
|
||||
}
|
||||
|
||||
tb.Client.SendMessage(m.Chat.ID, "You are not an authorized admin.")
|
||||
}
|
||||
|
||||
func (tb *Bot) chatID(m *tbot.Message) {
|
||||
if tb.adminCheck(m.From.ID, false) {
|
||||
tb.Client.SendMessage(m.Chat.ID, m.Chat.ID)
|
||||
return
|
||||
}
|
||||
|
||||
tb.Client.SendMessage(m.Chat.ID, "You are not an authorized admin.")
|
||||
}
|
||||
|
||||
// adminCheck checks for valid bot admins.
|
||||
func (tb *Bot) adminCheck(id int, callback bool) bool {
|
||||
for _, admin := range tb.Config.Telegram.Admins {
|
||||
if id == admin {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
73
pkg/service/telegram/handler.go
Normal file
73
pkg/service/telegram/handler.go
Normal file
@ -0,0 +1,73 @@
|
||||
package telegram
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/yanzay/tbot/v2"
|
||||
)
|
||||
|
||||
// Handler creates the active Telegram handlers.
|
||||
func (tb *Bot) Handler() {
|
||||
|
||||
// Bot Healthcheck
|
||||
tb.Bot.HandleMessage("/ping", func(m *tbot.Message) {
|
||||
tb.Client.SendMessage(m.Chat.ID, "pong")
|
||||
})
|
||||
|
||||
// telegram/couchpotato.go
|
||||
tb.Bot.HandleMessage("/m", tb.couchpotatoSearch)
|
||||
|
||||
// telegram/sonar.go
|
||||
tb.Bot.HandleMessage("/s", tb.sonarrSearch)
|
||||
tb.Bot.HandleMessage("/admin sonarrStatus", tb.sonarrStatus)
|
||||
|
||||
// telegram/testhandler.go
|
||||
tb.Bot.HandleMessage("/test", tb.testHandler)
|
||||
|
||||
// telegram/admin.go
|
||||
tb.Bot.HandleMessage("/admin myID", tb.myID)
|
||||
tb.Bot.HandleMessage("/admin chatID", tb.chatID)
|
||||
|
||||
// Help
|
||||
tb.Bot.HandleMessage("/help$", tb.helpHandler)
|
||||
tb.Bot.HandleMessage("/h$", tb.helpHandler)
|
||||
|
||||
// Callback Handler
|
||||
tb.Bot.HandleCallback(tb.callbackHandler)
|
||||
}
|
||||
|
||||
// callbackHandler handles callbacks.
|
||||
func (tb *Bot) callbackHandler(cq *tbot.CallbackQuery) {
|
||||
go func() {
|
||||
tb.Client.AnswerCallbackQuery(cq.ID, tbot.OptText("Request received."))
|
||||
tb.Client.DeleteMessage(tb.CallbackChatID, tb.CallbackMessageID)
|
||||
}()
|
||||
|
||||
if strings.Contains(cq.Data, "tv_") {
|
||||
tb.sonarrAdd(cq)
|
||||
return
|
||||
}
|
||||
|
||||
tb.Client.SendMessage(tb.CallbackChatID, cq.Data)
|
||||
|
||||
}
|
||||
|
||||
func (tb *Bot) helpHandler(m *tbot.Message) {
|
||||
if !tb.whitelistHandler(m) {
|
||||
return
|
||||
}
|
||||
|
||||
tb.Client.SendMessage(m.Chat.ID, "USAGE:\n\n/movie <Movie Name> or /m <Movie Name>\n/show <TV Show Name> or /s <TV Show Name>\n\nEXAMPLES:\n\n/s The Walking Dead\n/m Avatar")
|
||||
}
|
||||
|
||||
func (tb *Bot) whitelistHandler(m *tbot.Message) bool {
|
||||
for _, id := range tb.Config.Telegram.AuthorizedChats {
|
||||
if id == m.Chat.ID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
tb.Client.SendMessage(m.Chat.ID, "This bot is not authorized for use in this chat.")
|
||||
return false
|
||||
|
||||
}
|
85
pkg/service/telegram/sonarr.go
Normal file
85
pkg/service/telegram/sonarr.go
Normal file
@ -0,0 +1,85 @@
|
||||
package telegram
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/mattburchett/go_telegram/pkg/service/sonarr"
|
||||
|
||||
"github.com/yanzay/tbot/v2"
|
||||
)
|
||||
|
||||
// Sonarr Search
|
||||
func (tb *Bot) sonarrSearch(m *tbot.Message) {
|
||||
if !tb.whitelistHandler(m) {
|
||||
return
|
||||
}
|
||||
|
||||
text := strings.TrimPrefix(strings.TrimPrefix(m.Text, "/s"), " ")
|
||||
if len(text) == 0 {
|
||||
tb.Client.SendMessage(m.Chat.ID, "You must specify a show. Type /help for help.")
|
||||
return
|
||||
}
|
||||
|
||||
request, err := sonarr.Search(m, tb.Config)
|
||||
if err != nil {
|
||||
tb.Client.SendMessage(m.Chat.ID, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
inlineResponse := make([][]tbot.InlineKeyboardButton, 0)
|
||||
for _, i := range request {
|
||||
inlineResponse = append(inlineResponse, []tbot.InlineKeyboardButton{{
|
||||
Text: i.Button,
|
||||
CallbackData: "tv_" + i.Callback,
|
||||
}})
|
||||
}
|
||||
|
||||
if len(request) == 0 {
|
||||
tb.Client.SendMessage(m.Chat.ID, "No results found, try harder.")
|
||||
return
|
||||
}
|
||||
|
||||
response, _ := tb.Client.SendMessage(m.Chat.ID, "Please select the show you would like to download.", tbot.OptInlineKeyboardMarkup(&tbot.InlineKeyboardMarkup{InlineKeyboard: inlineResponse}))
|
||||
tb.CallbackMessageID = response.MessageID
|
||||
tb.CallbackChatID = m.Chat.ID
|
||||
|
||||
}
|
||||
|
||||
// sonarrAdd will perform the add requests to Sonarr.
|
||||
func (tb *Bot) sonarrAdd(cq *tbot.CallbackQuery) {
|
||||
if strings.Contains(cq.Data, "+") {
|
||||
if tb.adminCheck(cq.From.ID, true) {
|
||||
tb.Client.SendMessage(tb.CallbackChatID, sonarr.Add(cq.Data, tb.Config))
|
||||
} else {
|
||||
tb.Client.AnswerCallbackQuery(cq.ID, tbot.OptText("This request is over the season limit."))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
tb.Client.SendMessage(tb.CallbackChatID, sonarr.Add(cq.Data, tb.Config))
|
||||
|
||||
}
|
||||
|
||||
// Admin Functions
|
||||
|
||||
// sonarrStatus queries Sonarr for it's system status information.
|
||||
func (tb *Bot) sonarrStatus(m *tbot.Message) {
|
||||
if !tb.whitelistHandler(m) {
|
||||
return
|
||||
}
|
||||
|
||||
if tb.adminCheck(m.From.ID, false) {
|
||||
request, err := sonarr.Status(m, tb.Config)
|
||||
|
||||
if err != nil {
|
||||
tb.Client.SendMessage(m.Chat.ID, fmt.Sprintf("%v: \n %v", request, err))
|
||||
return
|
||||
}
|
||||
|
||||
tb.Client.SendMessage(m.Chat.ID, "Sonarr Status:")
|
||||
tb.Client.SendMessage(m.Chat.ID, request)
|
||||
|
||||
}
|
||||
|
||||
}
|
37
pkg/service/telegram/telegram.go
Normal file
37
pkg/service/telegram/telegram.go
Normal file
@ -0,0 +1,37 @@
|
||||
package telegram
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/mattburchett/go_telegram/pkg/core/config"
|
||||
"github.com/yanzay/tbot/v2"
|
||||
)
|
||||
|
||||
// Bot contains all the necessary bot and callback information.
|
||||
type Bot struct {
|
||||
Client *tbot.Client
|
||||
Config config.Config
|
||||
Bot *tbot.Server
|
||||
CallbackChatID string
|
||||
CallbackMessageID int
|
||||
}
|
||||
|
||||
// Stat middleware.
|
||||
func stat(h tbot.UpdateHandler) tbot.UpdateHandler {
|
||||
return func(u *tbot.Update) {
|
||||
start := time.Now()
|
||||
h(u)
|
||||
log.Printf("Handle time: %v", time.Now().Sub(start))
|
||||
}
|
||||
}
|
||||
|
||||
// New creates an active telegram bot and loads the handlers.
|
||||
func (tb *Bot) New(token string) {
|
||||
tb.Bot = tbot.New(token)
|
||||
tb.Bot.Use(stat)
|
||||
tb.Client = tb.Bot.Client()
|
||||
tb.Handler()
|
||||
tb.Bot.Start()
|
||||
|
||||
}
|
25
pkg/service/telegram/testhandler.go
Normal file
25
pkg/service/telegram/testhandler.go
Normal file
@ -0,0 +1,25 @@
|
||||
package telegram
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/yanzay/tbot/v2"
|
||||
)
|
||||
|
||||
func (tb *Bot) testHandler(m *tbot.Message) {
|
||||
buttons := make([]string, 0)
|
||||
buttons = append(buttons, "ping", "is", "stupid")
|
||||
|
||||
inline2 := make([][]tbot.InlineKeyboardButton, 0)
|
||||
|
||||
for _, i := range buttons {
|
||||
inline2 = append(inline2, []tbot.InlineKeyboardButton{{
|
||||
Text: i,
|
||||
CallbackData: i,
|
||||
}})
|
||||
}
|
||||
|
||||
msg, _ := tb.Client.SendMessage(m.Chat.ID, "Inline test. "+strings.TrimPrefix(m.Text, "/test "), tbot.OptInlineKeyboardMarkup(&tbot.InlineKeyboardMarkup{InlineKeyboard: inline2}))
|
||||
tb.CallbackMessageID = msg.MessageID
|
||||
tb.CallbackChatID = m.Chat.ID
|
||||
}
|
Loading…
Reference in New Issue
Block a user