You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
378 lines
8.6 KiB
378 lines
8.6 KiB
package service
|
|
|
|
import (
|
|
"archive/tar"
|
|
"compress/gzip"
|
|
"encoding/xml"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"sort"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/akhilrex/podgrab/db"
|
|
"github.com/akhilrex/podgrab/internal/sanitize"
|
|
stringy "github.com/gobeam/stringy"
|
|
)
|
|
|
|
func Download(link string, episodeTitle string, podcastName string, prefix string) (string, error) {
|
|
if link == "" {
|
|
return "", errors.New("Download path empty")
|
|
}
|
|
client := httpClient()
|
|
resp, err := client.Get(link)
|
|
if err != nil {
|
|
Logger.Errorw("Error getting response: "+link, err)
|
|
return "", err
|
|
}
|
|
|
|
fileName := getFileName(link, episodeTitle, ".mp3")
|
|
if prefix != "" {
|
|
fileName = fmt.Sprintf("%s-%s", prefix, fileName)
|
|
}
|
|
folder := createDataFolderIfNotExists(podcastName)
|
|
finalPath := path.Join(folder, fileName)
|
|
|
|
if _, err := os.Stat(finalPath); !os.IsNotExist(err) {
|
|
changeOwnership(finalPath)
|
|
return finalPath, nil
|
|
}
|
|
|
|
file, err := os.Create(finalPath)
|
|
if err != nil {
|
|
Logger.Errorw("Error creating file"+link, err)
|
|
return "", err
|
|
}
|
|
defer resp.Body.Close()
|
|
_, erra := io.Copy(file, resp.Body)
|
|
//fmt.Println(size)
|
|
defer file.Close()
|
|
if erra != nil {
|
|
Logger.Errorw("Error saving file"+link, err)
|
|
return "", erra
|
|
}
|
|
changeOwnership(finalPath)
|
|
return finalPath, nil
|
|
|
|
}
|
|
|
|
func GetPodcastLocalImagePath(link string, podcastName string) string {
|
|
fileName := getFileName(link, "folder", ".jpg")
|
|
folder := createDataFolderIfNotExists(podcastName)
|
|
|
|
finalPath := path.Join(folder, fileName)
|
|
return finalPath
|
|
}
|
|
|
|
func CreateNfoFile(podcast *db.Podcast) error {
|
|
fileName := "album.nfo"
|
|
folder := createDataFolderIfNotExists(podcast.Title)
|
|
|
|
finalPath := path.Join(folder, fileName)
|
|
|
|
type NFO struct {
|
|
XMLName xml.Name `xml:"album"`
|
|
Title string `xml:"title"`
|
|
Type string `xml:"type"`
|
|
Thumb string `xml:"thumb"`
|
|
}
|
|
|
|
toSave := NFO{
|
|
Title: podcast.Title,
|
|
Type: "Broadcast",
|
|
Thumb: podcast.Image,
|
|
}
|
|
out, err := xml.MarshalIndent(toSave, " ", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
toPersist := xml.Header + string(out)
|
|
return ioutil.WriteFile(finalPath, []byte(toPersist), 0644)
|
|
}
|
|
|
|
func DownloadPodcastCoverImage(link string, podcastName string) (string, error) {
|
|
if link == "" {
|
|
return "", errors.New("Download path empty")
|
|
}
|
|
client := httpClient()
|
|
resp, err := client.Get(link)
|
|
if err != nil {
|
|
Logger.Errorw("Error getting response: "+link, err)
|
|
return "", err
|
|
}
|
|
|
|
fileName := getFileName(link, "folder", ".jpg")
|
|
folder := createDataFolderIfNotExists(podcastName)
|
|
|
|
finalPath := path.Join(folder, fileName)
|
|
if _, err := os.Stat(finalPath); !os.IsNotExist(err) {
|
|
changeOwnership(finalPath)
|
|
return finalPath, nil
|
|
}
|
|
|
|
file, err := os.Create(finalPath)
|
|
if err != nil {
|
|
Logger.Errorw("Error creating file"+link, err)
|
|
return "", err
|
|
}
|
|
defer resp.Body.Close()
|
|
_, erra := io.Copy(file, resp.Body)
|
|
//fmt.Println(size)
|
|
defer file.Close()
|
|
if erra != nil {
|
|
Logger.Errorw("Error saving file"+link, err)
|
|
return "", erra
|
|
}
|
|
changeOwnership(finalPath)
|
|
return finalPath, nil
|
|
}
|
|
|
|
func DownloadImage(link string, episodeId string, podcastName string) (string, error) {
|
|
if link == "" {
|
|
return "", errors.New("Download path empty")
|
|
}
|
|
client := httpClient()
|
|
resp, err := client.Get(link)
|
|
if err != nil {
|
|
Logger.Errorw("Error getting response: "+link, err)
|
|
return "", err
|
|
}
|
|
|
|
fileName := getFileName(link, episodeId, ".jpg")
|
|
folder := createDataFolderIfNotExists(podcastName)
|
|
imageFolder := createFolder("images", folder)
|
|
finalPath := path.Join(imageFolder, fileName)
|
|
|
|
if _, err := os.Stat(finalPath); !os.IsNotExist(err) {
|
|
changeOwnership(finalPath)
|
|
return finalPath, nil
|
|
}
|
|
|
|
file, err := os.Create(finalPath)
|
|
if err != nil {
|
|
Logger.Errorw("Error creating file"+link, err)
|
|
return "", err
|
|
}
|
|
defer resp.Body.Close()
|
|
_, erra := io.Copy(file, resp.Body)
|
|
//fmt.Println(size)
|
|
defer file.Close()
|
|
if erra != nil {
|
|
Logger.Errorw("Error saving file"+link, err)
|
|
return "", erra
|
|
}
|
|
changeOwnership(finalPath)
|
|
return finalPath, nil
|
|
|
|
}
|
|
func changeOwnership(path string) {
|
|
uid, err1 := strconv.Atoi(os.Getenv("PUID"))
|
|
gid, err2 := strconv.Atoi(os.Getenv("PGID"))
|
|
fmt.Println(path)
|
|
if err1 == nil && err2 == nil {
|
|
fmt.Println(path + " : Attempting change")
|
|
os.Chown(path, uid, gid)
|
|
}
|
|
|
|
}
|
|
func DeleteFile(filePath string) error {
|
|
if _, err := os.Stat(filePath); os.IsNotExist(err) {
|
|
return err
|
|
}
|
|
if err := os.Remove(filePath); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
func FileExists(filePath string) bool {
|
|
_, err := os.Stat(filePath)
|
|
return err == nil
|
|
|
|
}
|
|
|
|
func GetAllBackupFiles() ([]string, error) {
|
|
var files []string
|
|
folder := createConfigFolderIfNotExists("backups")
|
|
err := filepath.Walk(folder, func(path string, info os.FileInfo, err error) error {
|
|
if !info.IsDir() {
|
|
files = append(files, path)
|
|
}
|
|
return nil
|
|
})
|
|
sort.Sort(sort.Reverse(sort.StringSlice(files)))
|
|
return files, err
|
|
}
|
|
|
|
func GetFileSize(path string) (int64, error) {
|
|
info, err := os.Stat(path)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return info.Size(), nil
|
|
}
|
|
|
|
func deleteOldBackup() {
|
|
files, err := GetAllBackupFiles()
|
|
if err != nil {
|
|
return
|
|
}
|
|
if len(files) <= 5 {
|
|
return
|
|
}
|
|
|
|
toDelete := files[5:]
|
|
for _, file := range toDelete {
|
|
fmt.Println(file)
|
|
DeleteFile(file)
|
|
}
|
|
}
|
|
|
|
func GetFileSizeFromUrl(url string) (int64, error) {
|
|
resp, err := http.Head(url)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
// Is our request ok?
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return 0, fmt.Errorf("Did not receive 200")
|
|
}
|
|
|
|
size, err := strconv.Atoi(resp.Header.Get("Content-Length"))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return int64(size), nil
|
|
}
|
|
|
|
func CreateBackup() (string, error) {
|
|
|
|
backupFileName := "podgrab_backup_" + time.Now().Format("2006.01.02_150405") + ".tar.gz"
|
|
folder := createConfigFolderIfNotExists("backups")
|
|
configPath := os.Getenv("CONFIG")
|
|
tarballFilePath := path.Join(folder, backupFileName)
|
|
file, err := os.Create(tarballFilePath)
|
|
if err != nil {
|
|
return "", errors.New(fmt.Sprintf("Could not create tarball file '%s', got error '%s'", tarballFilePath, err.Error()))
|
|
}
|
|
defer file.Close()
|
|
|
|
dbPath := path.Join(configPath, "podgrab.db")
|
|
_, err = os.Stat(dbPath)
|
|
if err != nil {
|
|
return "", errors.New(fmt.Sprintf("Could not find db file '%s', got error '%s'", dbPath, err.Error()))
|
|
}
|
|
gzipWriter := gzip.NewWriter(file)
|
|
defer gzipWriter.Close()
|
|
|
|
tarWriter := tar.NewWriter(gzipWriter)
|
|
defer tarWriter.Close()
|
|
|
|
err = addFileToTarWriter(dbPath, tarWriter)
|
|
if err == nil {
|
|
deleteOldBackup()
|
|
}
|
|
return backupFileName, err
|
|
}
|
|
|
|
func addFileToTarWriter(filePath string, tarWriter *tar.Writer) error {
|
|
file, err := os.Open(filePath)
|
|
if err != nil {
|
|
return errors.New(fmt.Sprintf("Could not open file '%s', got error '%s'", filePath, err.Error()))
|
|
}
|
|
defer file.Close()
|
|
|
|
stat, err := file.Stat()
|
|
if err != nil {
|
|
return errors.New(fmt.Sprintf("Could not get stat for file '%s', got error '%s'", filePath, err.Error()))
|
|
}
|
|
|
|
header := &tar.Header{
|
|
Name: filePath,
|
|
Size: stat.Size(),
|
|
Mode: int64(stat.Mode()),
|
|
ModTime: stat.ModTime(),
|
|
}
|
|
|
|
err = tarWriter.WriteHeader(header)
|
|
if err != nil {
|
|
return errors.New(fmt.Sprintf("Could not write header for file '%s', got error '%s'", filePath, err.Error()))
|
|
}
|
|
|
|
_, err = io.Copy(tarWriter, file)
|
|
if err != nil {
|
|
return errors.New(fmt.Sprintf("Could not copy the file '%s' data to the tarball, got error '%s'", filePath, err.Error()))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
func httpClient() *http.Client {
|
|
client := http.Client{
|
|
CheckRedirect: func(r *http.Request, via []*http.Request) error {
|
|
// r.URL.Opaque = r.URL.Path
|
|
return nil
|
|
},
|
|
}
|
|
|
|
return &client
|
|
}
|
|
|
|
func createFolder(folder string, parent string) string {
|
|
folder = cleanFileName(folder)
|
|
//str := stringy.New(folder)
|
|
folderPath := path.Join(parent, folder)
|
|
if _, err := os.Stat(folderPath); os.IsNotExist(err) {
|
|
os.MkdirAll(folderPath, 0777)
|
|
changeOwnership(folderPath)
|
|
}
|
|
return folderPath
|
|
}
|
|
|
|
func createDataFolderIfNotExists(folder string) string {
|
|
dataPath := os.Getenv("DATA")
|
|
return createFolder(folder, dataPath)
|
|
}
|
|
func createConfigFolderIfNotExists(folder string) string {
|
|
dataPath := os.Getenv("CONFIG")
|
|
return createFolder(folder, dataPath)
|
|
}
|
|
|
|
func deletePodcastFolder(folder string) error {
|
|
return os.RemoveAll(createDataFolderIfNotExists(folder))
|
|
}
|
|
|
|
func getFileName(link string, title string, defaultExtension string) string {
|
|
fileUrl, err := url.Parse(link)
|
|
checkError(err)
|
|
|
|
parsed := fileUrl.Path
|
|
ext := filepath.Ext(parsed)
|
|
|
|
if len(ext) == 0 {
|
|
ext = defaultExtension
|
|
}
|
|
//str := stringy.New(title)
|
|
str := stringy.New(cleanFileName(title))
|
|
return str.KebabCase().Get() + ext
|
|
|
|
}
|
|
|
|
func cleanFileName(original string) string {
|
|
return sanitize.Name(original)
|
|
}
|
|
|
|
func checkError(err error) {
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|