A little more updating.
This commit is contained in:
parent
bc9461359f
commit
145fe10513
3
.gitignore
vendored
3
.gitignore
vendored
@ -1 +1,2 @@
|
||||
config.json
|
||||
config.json
|
||||
housekeeper
|
19
README.md
19
README.md
@ -1,2 +1,21 @@
|
||||
# Housekeeper
|
||||
|
||||
Housekeeper is a cleanup tool for Plex environements.
|
||||
|
||||
It requires two things - Plex and PlexPy (now known as Tautulli). It has a option for communicating with Telegram for cleanup purposes.
|
||||
|
||||
Please use the example configuration file for configuration.
|
||||
|
||||
The command line args that can be passed:
|
||||
|
||||
```Usage of ./housekeeper:
|
||||
-c string
|
||||
Configuration to load
|
||||
-check
|
||||
Perform only a check. Do not delete. (default true)
|
||||
-days int
|
||||
days to poll
|
||||
-delete
|
||||
Perform the delete task.
|
||||
-sectionid int
|
||||
pick a section ID```
|
25
cmd/main.go
25
cmd/main.go
@ -4,7 +4,9 @@ import (
|
||||
"flag"
|
||||
"log"
|
||||
|
||||
"git.linuxrocker.com/mattburchett/Housekeeper/pkg/communicator"
|
||||
"git.linuxrocker.com/mattburchett/Housekeeper/pkg/config"
|
||||
"git.linuxrocker.com/mattburchett/Housekeeper/pkg/eraser"
|
||||
"git.linuxrocker.com/mattburchett/Housekeeper/pkg/locator"
|
||||
)
|
||||
|
||||
@ -39,10 +41,14 @@ func main() {
|
||||
var c string
|
||||
var days int
|
||||
var sectionID int
|
||||
var check bool
|
||||
var delete bool
|
||||
|
||||
flag.StringVar(&c, "c", "", "Configuration to load")
|
||||
flag.IntVar(&days, "days", 0, "days to poll")
|
||||
flag.IntVar(§ionID, "sectionid", 0, "pick a section ID")
|
||||
flag.BoolVar(&check, "check", true, "Perform only a check. Do not delete.")
|
||||
flag.BoolVar(&delete, "delete", false, "Perform the delete task.")
|
||||
flag.Parse()
|
||||
if c == "" {
|
||||
log.Fatal("You need to specify a configuration file.")
|
||||
@ -55,5 +61,22 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
locator.GetTitles(cfg, sectionID, days)
|
||||
|
||||
ids, titles := locator.GetTitles(cfg, sectionID, days)
|
||||
|
||||
if check {
|
||||
err = communicator.TelegramPost(cfg, titles)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if delete {
|
||||
files := eraser.LookupFileLocation(cfg, ids)
|
||||
err = eraser.DeleteMedia(delete, files)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
11
config_example.json
Normal file
11
config_example.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"baseURL": "http://dvr.example.com",
|
||||
"plexPyContext": "/plexpy",
|
||||
"plexPyAPIKey": "abc1234",
|
||||
"plexToken": "ABC1234ABC1234",
|
||||
"plexHost": "http://192.168.1.1",
|
||||
"plexPort": 32400,
|
||||
"telegramToken": "123456789:ABCDEFG",
|
||||
"telegramChatID": "12345678",
|
||||
"serverName": "Plex"
|
||||
}
|
@ -1 +1,38 @@
|
||||
package communicator
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"git.linuxrocker.com/mattburchett/Housekeeper/pkg/config"
|
||||
)
|
||||
|
||||
// TelegramPost will send a message to a specific ChatID in Telegram containing the list of items to be cleaned with this cleaner.
|
||||
func TelegramPost(config config.Config, titles []string) error {
|
||||
url := "https://api.telegram.org/bot" + config.TelegramToken + "/sendMessage"
|
||||
|
||||
values := map[string]string{"chat_id": config.TelegramChatID, "text": "The following items are to be removed from " + config.ServerName + " in 24 hours. Please go to Plex and start the title to keep it on" + config.ServerName + ". You do not need to keep watching, just hit play and load a few seconds.\n\n" + fmt.Sprintf("%v", strings.Join(titles, "\n")), "disable_notifications": "true"}
|
||||
|
||||
jsonValue, _ := json.Marshal(values)
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonValue))
|
||||
req.Header.Set("X-Custom-Header", "Housekeeper")
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
fmt.Println("response Status:", resp.Status)
|
||||
fmt.Println("response Headers:", resp.Header)
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
fmt.Println("response Body:", string(body))
|
||||
|
||||
return err
|
||||
}
|
||||
|
@ -9,13 +9,15 @@ import (
|
||||
|
||||
// Config - This struct will hold configuration components.
|
||||
type Config struct {
|
||||
BaseURL string `json:"baseURL"`
|
||||
PlexPyContext string `json:"plexPyContext"`
|
||||
PlexPyAPIKey string `json:"plexPyAPIKey"`
|
||||
PlexToken string `json:"plexToken"`
|
||||
PlexHost string `json:"plexHost"`
|
||||
PlexPort int `json:"plexPort"`
|
||||
TelegramToken string `json:"telegramToken"`
|
||||
BaseURL string `json:"baseURL"`
|
||||
PlexPyContext string `json:"plexPyContext"`
|
||||
PlexPyAPIKey string `json:"plexPyAPIKey"`
|
||||
PlexToken string `json:"plexToken"`
|
||||
PlexHost string `json:"plexHost"`
|
||||
PlexPort int `json:"plexPort"`
|
||||
TelegramToken string `json:"telegramToken"`
|
||||
TelegramChatID string `json:"telegramChatID"`
|
||||
ServerName string `json:"serverName"`
|
||||
}
|
||||
|
||||
//GetConfig gets the configuration values for the api using the file in the supplied configPath.
|
||||
|
@ -1 +1,64 @@
|
||||
package eraser
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"git.linuxrocker.com/mattburchett/Housekeeper/pkg/config"
|
||||
"git.linuxrocker.com/mattburchett/Housekeeper/pkg/model"
|
||||
)
|
||||
|
||||
// LookupFileLocation will gather a list of Information based on IDs returned by locator.GetTitles
|
||||
func LookupFileLocation(config config.Config, ids []int) []string {
|
||||
fileList := make([]string, 0)
|
||||
|
||||
for _, i := range ids {
|
||||
plexURL := fmt.Sprintf("%s:%d%s%d%s%s", config.PlexHost, config.PlexPort, "/library/metadata/", i, "/?X-Plex-Token=", config.PlexToken)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, plexURL, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
httpClient := http.Client{}
|
||||
req.Header.Set("User-Agent", "Housekeeper")
|
||||
|
||||
res, getErr := httpClient.Do(req)
|
||||
if getErr != nil {
|
||||
log.Fatal(getErr)
|
||||
}
|
||||
|
||||
body, readErr := ioutil.ReadAll(res.Body)
|
||||
if readErr != nil {
|
||||
log.Fatal(readErr)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
plexModel := model.XMLPlexAPI{}
|
||||
xml.Unmarshal(body, &plexModel)
|
||||
fileList = append(fileList, filepath.Dir(plexModel.Video.Media.Part.File))
|
||||
}
|
||||
return fileList
|
||||
}
|
||||
|
||||
// DeleteMedia will actually perform the deletion.
|
||||
func DeleteMedia(delete bool, files []string) error {
|
||||
var err error
|
||||
if delete {
|
||||
for _, i := range files {
|
||||
fmt.Printf("Removing %v\n", i)
|
||||
err = os.RemoveAll(i)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -2,20 +2,19 @@ package locator
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.linuxrocker.com/mattburchett/Housekeeper/pkg/config"
|
||||
"git.linuxrocker.com/mattburchett/Housekeeper/pkg/model"
|
||||
"git.linuxrocker.com/mattburchett/Housekeeper/pkg/util"
|
||||
)
|
||||
|
||||
// GetCount will gather a count of media in a specific library, required for GetTitles.
|
||||
func GetCount(config config.Config, sectionID int) int {
|
||||
countURL := fmt.Sprintf("%s%s%s%s%s%d", config.BaseURL, config.PlexPyContext, "/api/v2?apikey=", config.PlexPyAPIKey, "&cmd=get_library§ion_id=", sectionID)
|
||||
req, err := http.NewRequest(http.MethodGet, countURL, nil)
|
||||
@ -48,7 +47,7 @@ func GetCount(config config.Config, sectionID int) int {
|
||||
}
|
||||
|
||||
// GetTitles will gather a list of information from the media in the library, based on the previous count.
|
||||
func GetTitles(config config.Config, sectionID int, days int) {
|
||||
func GetTitles(config config.Config, sectionID int, days int) ([]int, []string) {
|
||||
count := GetCount(config, sectionID)
|
||||
|
||||
titlesURL := fmt.Sprintf("%s%s%s%s%s%d%s%d", config.BaseURL, config.PlexPyContext, "/api/v2?apikey=", config.PlexPyAPIKey, "&cmd=get_library_media_info§ion_id=", sectionID, "&order_column=last_played&refresh=true&order_dir=asc&length=", count)
|
||||
@ -108,47 +107,5 @@ func GetTitles(config config.Config, sectionID int, days int) {
|
||||
}
|
||||
}
|
||||
sort.Strings(titles)
|
||||
|
||||
LookupFileLocation(config, ids)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func LookupFileLocation(config config.Config, ids []int) {
|
||||
// fileLocations := make([]string, 0)
|
||||
|
||||
for _, i := range ids {
|
||||
plexURL := fmt.Sprintf("%s:%d%s%d%s%s", config.PlexHost, config.PlexPort, "/library/metadata/", i, "/?X-Plex-Token=", config.PlexToken)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, plexURL, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
httpClient := http.Client{}
|
||||
req.Header.Set("User-Agent", "Housekeeper")
|
||||
|
||||
res, getErr := httpClient.Do(req)
|
||||
if getErr != nil {
|
||||
log.Fatal(getErr)
|
||||
}
|
||||
|
||||
body, readErr := ioutil.ReadAll(res.Body)
|
||||
if readErr != nil {
|
||||
log.Fatal(readErr)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
plexModel := model.XMLPlexAPI{}
|
||||
xml.Unmarshal(body, &plexModel)
|
||||
|
||||
fileList := strings.Split(plexModel.Video.Media.Part.File, "/")
|
||||
|
||||
fmt.Printf("/%v/%v/%v/%v/%v\n", fileList[1], fileList[2], fileList[3], fileList[4], fileList[5])
|
||||
}
|
||||
|
||||
// http://172.19.0.105:32400/library/metadata/9/?X-Plex-Token=K1WCALqRK5HVzSQ1J3bM
|
||||
|
||||
return ids, titles
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ type XMLPlexAPI struct {
|
||||
Text string `xml:",chardata"`
|
||||
RatingKey string `xml:"ratingKey,attr"`
|
||||
Key string `xml:"key,attr"`
|
||||
Guid string `xml:"guid,attr"`
|
||||
GUID string `xml:"guid,attr"`
|
||||
LibrarySectionTitle string `xml:"librarySectionTitle,attr"`
|
||||
LibrarySectionID string `xml:"librarySectionID,attr"`
|
||||
LibrarySectionKey string `xml:"librarySectionKey,attr"`
|
||||
|
@ -1 +0,0 @@
|
||||
package rotator
|
@ -2,6 +2,7 @@ package util
|
||||
|
||||
import "time"
|
||||
|
||||
// SubtractedEpoch will take the current time in epoch and subtract (days) worth of seconds from the current epoch time.
|
||||
func SubtractedEpoch(days int) int64 {
|
||||
now := time.Now()
|
||||
unix := now.Unix()
|
||||
|
Loading…
Reference in New Issue
Block a user