#1 - Sonarr Delete Fix #8
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,2 +1,3 @@
 | 
			
		||||
config.json
 | 
			
		||||
housekeeper
 | 
			
		||||
housekeeper
 | 
			
		||||
.vscode
 | 
			
		||||
@@ -57,6 +57,8 @@ func main() {
 | 
			
		||||
			}
 | 
			
		||||
		} else if libraryType == "show" {
 | 
			
		||||
			files := eraser.LookupTVFileLocation(cfg, ids)
 | 
			
		||||
			sonarrIDs := locator.GetSonarrIDs(cfg, titles)
 | 
			
		||||
			eraser.DeleteSeriesFromSonarr(cfg, sonarrIDs)
 | 
			
		||||
			err = eraser.DeleteFiles(delete, files)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println(err)
 | 
			
		||||
 
 | 
			
		||||
@@ -11,28 +11,38 @@ import (
 | 
			
		||||
	"git.linuxrocker.com/mattburchett/Housekeeper/pkg/config"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type error interface {
 | 
			
		||||
	Error() string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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"
 | 
			
		||||
	var err error
 | 
			
		||||
	if len(titles) != 0 {
 | 
			
		||||
		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"}
 | 
			
		||||
		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")
 | 
			
		||||
		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)
 | 
			
		||||
		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))
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
		fmt.Println("There are no titles, therefore no message to send!")
 | 
			
		||||
	}
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,8 @@ type Config struct {
 | 
			
		||||
	TelegramToken  string `json:"telegramToken"`
 | 
			
		||||
	TelegramChatID string `json:"telegramChatID"`
 | 
			
		||||
	ServerName     string `json:"serverName"`
 | 
			
		||||
	SonarrContext  string `json:"sonarrContext"`
 | 
			
		||||
	SonarrAPIKey   string `json:"sonarrAPIKey"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//GetConfig gets the configuration values for the api using the file in the supplied configPath.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package eraser
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"encoding/xml"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
@@ -8,6 +9,7 @@ import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"git.linuxrocker.com/mattburchett/Housekeeper/pkg/config"
 | 
			
		||||
	"git.linuxrocker.com/mattburchett/Housekeeper/pkg/model"
 | 
			
		||||
@@ -92,6 +94,39 @@ func LookupTVFileLocation(config config.Config, ids []int) []string {
 | 
			
		||||
	return results
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DeleteSeriesFromSonarr(config config.Config, ids []int) {
 | 
			
		||||
	for _, i := range ids {
 | 
			
		||||
		sonarrURL := fmt.Sprintf("%s%s%s%d%s%s", config.BaseURL, config.SonarrContext, "/api/series/", i, "/?deleteFiles=true&apikey=", config.SonarrAPIKey)
 | 
			
		||||
		req, err := http.NewRequest(http.MethodDelete, sonarrURL, 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)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		deleteModel := model.SonarrResponse{}
 | 
			
		||||
		jsonErr := json.Unmarshal(body, &deleteModel)
 | 
			
		||||
		if jsonErr != nil {
 | 
			
		||||
			log.Fatal(jsonErr)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if strings.Contains("does not exist", deleteModel.Message) {
 | 
			
		||||
			log.Printf("The following ID does not exist: %v", i)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteFiles will actually perform the deletion.
 | 
			
		||||
func DeleteFiles(delete bool, files []string) error {
 | 
			
		||||
	var err error
 | 
			
		||||
 
 | 
			
		||||
@@ -144,3 +144,42 @@ func GetTitles(config config.Config, sectionID int, days int) ([]int, []string)
 | 
			
		||||
	sort.Strings(titles)
 | 
			
		||||
	return ids, titles
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetSonarrIDs gets the IDs to delete from the title list in PlexPy.
 | 
			
		||||
func GetSonarrIDs(config config.Config, titles []string) []int {
 | 
			
		||||
	ids := make([]int, 0)
 | 
			
		||||
	sonarrURL := fmt.Sprintf("%s%s%s%s", config.BaseURL, config.SonarrContext, "/api/series?apikey=", config.SonarrAPIKey)
 | 
			
		||||
	req, err := http.NewRequest(http.MethodGet, sonarrURL, 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)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sonarrModel := model.SonarrSeries{}
 | 
			
		||||
	jsonErr := json.Unmarshal(body, &sonarrModel)
 | 
			
		||||
	if jsonErr != nil {
 | 
			
		||||
		log.Fatal(jsonErr)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, r := range sonarrModel {
 | 
			
		||||
		for _, s := range titles {
 | 
			
		||||
			if r.Title == s {
 | 
			
		||||
				ids = append(ids, r.ID)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ids
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -230,3 +230,8 @@ type XMLPlexTVAPI struct {
 | 
			
		||||
		} `xml:"Writer"`
 | 
			
		||||
	} `xml:"Video"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SonarrResponse struct {
 | 
			
		||||
	Message     string `json:"message"`
 | 
			
		||||
	Description string `json:"description"`
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,9 @@
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import "encoding/xml"
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/xml"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// PlexPyLibraryInfo will gather all the library related info. We really just need the count from this...
 | 
			
		||||
type PlexPyLibraryInfo struct {
 | 
			
		||||
@@ -88,3 +91,66 @@ type XMLPlexLibraryType struct {
 | 
			
		||||
		Search    string `xml:"search,attr"`
 | 
			
		||||
	} `xml:"Directory"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SonarrSeries type takes all the data from Sonarr and places it in a struct
 | 
			
		||||
type SonarrSeries []struct {
 | 
			
		||||
	Title           string `json:"title"`
 | 
			
		||||
	AlternateTitles []struct {
 | 
			
		||||
		Title        string `json:"title"`
 | 
			
		||||
		SeasonNumber int    `json:"seasonNumber"`
 | 
			
		||||
	} `json:"alternateTitles"`
 | 
			
		||||
	SortTitle         string    `json:"sortTitle"`
 | 
			
		||||
	SeasonCount       int       `json:"seasonCount"`
 | 
			
		||||
	TotalEpisodeCount int       `json:"totalEpisodeCount"`
 | 
			
		||||
	EpisodeCount      int       `json:"episodeCount"`
 | 
			
		||||
	EpisodeFileCount  int       `json:"episodeFileCount"`
 | 
			
		||||
	SizeOnDisk        int64     `json:"sizeOnDisk"`
 | 
			
		||||
	Status            string    `json:"status"`
 | 
			
		||||
	Overview          string    `json:"overview"`
 | 
			
		||||
	PreviousAiring    time.Time `json:"previousAiring"`
 | 
			
		||||
	Network           string    `json:"network"`
 | 
			
		||||
	AirTime           string    `json:"airTime,omitempty"`
 | 
			
		||||
	Images            []struct {
 | 
			
		||||
		CoverType string `json:"coverType"`
 | 
			
		||||
		URL       string `json:"url"`
 | 
			
		||||
	} `json:"images"`
 | 
			
		||||
	Seasons []struct {
 | 
			
		||||
		SeasonNumber int  `json:"seasonNumber"`
 | 
			
		||||
		Monitored    bool `json:"monitored"`
 | 
			
		||||
		Statistics   struct {
 | 
			
		||||
			PreviousAiring    time.Time `json:"previousAiring"`
 | 
			
		||||
			EpisodeFileCount  int       `json:"episodeFileCount"`
 | 
			
		||||
			EpisodeCount      int       `json:"episodeCount"`
 | 
			
		||||
			TotalEpisodeCount int       `json:"totalEpisodeCount"`
 | 
			
		||||
			SizeOnDisk        int64     `json:"sizeOnDisk"`
 | 
			
		||||
			PercentOfEpisodes float64   `json:"percentOfEpisodes"`
 | 
			
		||||
		} `json:"statistics"`
 | 
			
		||||
	} `json:"seasons"`
 | 
			
		||||
	Year              int           `json:"year"`
 | 
			
		||||
	Path              string        `json:"path"`
 | 
			
		||||
	ProfileID         int           `json:"profileId"`
 | 
			
		||||
	SeasonFolder      bool          `json:"seasonFolder"`
 | 
			
		||||
	Monitored         bool          `json:"monitored"`
 | 
			
		||||
	UseSceneNumbering bool          `json:"useSceneNumbering"`
 | 
			
		||||
	Runtime           int           `json:"runtime"`
 | 
			
		||||
	TvdbID            int           `json:"tvdbId"`
 | 
			
		||||
	TvRageID          int           `json:"tvRageId"`
 | 
			
		||||
	TvMazeID          int           `json:"tvMazeId"`
 | 
			
		||||
	FirstAired        time.Time     `json:"firstAired"`
 | 
			
		||||
	LastInfoSync      time.Time     `json:"lastInfoSync"`
 | 
			
		||||
	SeriesType        string        `json:"seriesType"`
 | 
			
		||||
	CleanTitle        string        `json:"cleanTitle"`
 | 
			
		||||
	ImdbID            string        `json:"imdbId,omitempty"`
 | 
			
		||||
	TitleSlug         string        `json:"titleSlug"`
 | 
			
		||||
	Certification     string        `json:"certification,omitempty"`
 | 
			
		||||
	Genres            []string      `json:"genres"`
 | 
			
		||||
	Tags              []interface{} `json:"tags"`
 | 
			
		||||
	Added             time.Time     `json:"added"`
 | 
			
		||||
	Ratings           struct {
 | 
			
		||||
		Votes int     `json:"votes"`
 | 
			
		||||
		Value float64 `json:"value"`
 | 
			
		||||
	} `json:"ratings"`
 | 
			
		||||
	QualityProfileID int       `json:"qualityProfileId"`
 | 
			
		||||
	ID               int       `json:"id"`
 | 
			
		||||
	NextAiring       time.Time `json:"nextAiring,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user