diff --git a/Readme.md b/Readme.md index edc5f2b..bb86acd 100644 --- a/Readme.md +++ b/Readme.md @@ -148,13 +148,14 @@ Distributed under the MIT License. See `LICENSE` for more information. - [x] Append Date to filename - [x] iTunes Search - [x] Existing episodes detection (Will not redownload if files exist even with a fresh install) -- [x] Rudimentary downloading/downloaded indicator +- [x] Downloading/downloaded indicator - [x] Played/Unplayed Flag - [x] OPML import - [x] OPML export - [x] In built podcast player - [ ] Set ID3 tags if not set - [ ] Filtering and Sorting options +- [ ] Native installer for Windows/Linux/MacOS diff --git a/client/episodes.html b/client/episodes.html index 9487bb2..2f0423f 100644 --- a/client/episodes.html +++ b/client/episodes.html @@ -65,7 +65,7 @@ {{ .Title }} diff --git a/client/player.html b/client/player.html index 8c81fe0..95925ed 100644 --- a/client/player.html +++ b/client/player.html @@ -867,11 +867,15 @@ div#large-visualization{ }, getSongsFromItems(items){ return items.map(x=>{ + var image = x.LocalImage; + if(!image){ + image=x.Image; + } var toReturn= { id:x.ID, name:x.Title, url:x.DownloadPath, - cover_art_url:x.Image, + cover_art_url:image, artist:x.Podcast.Title, album: new Date(x.PubDate.substr(0,10)).toDateString() } diff --git a/client/settings.html b/client/settings.html index 7bd937c..d4fc67a 100644 --- a/client/settings.html +++ b/client/settings.html @@ -82,6 +82,11 @@ Use Dark Mode + + @@ -135,7 +140,8 @@ var app = new Vue({ autoDownload:self.autoDownload, appendDateToFileName:self.appendDateToFileName, appendEpisodeNumberToFileName:self.appendEpisodeNumberToFileName, - darkMode:self.darkMode + darkMode:self.darkMode, + downloadEpisodeImages:self.downloadEpisodeImages }) .then(function(response){ @@ -176,7 +182,8 @@ var app = new Vue({ appendDateToFileName: {{ .setting.AppendDateToFileName }}, appendEpisodeNumberToFileName:{{ .setting.AppendEpisodeNumberToFileName }}, darkMode:{{ .setting.DarkMode }}, - originalThemeSetting:{{ .setting.DarkMode }} + originalThemeSetting:{{ .setting.DarkMode }}, + downloadEpisodeImages:{{.setting.DownloadEpisodeImages }}, }, }) diff --git a/controllers/pages.go b/controllers/pages.go index 650edfd..ced4524 100644 --- a/controllers/pages.go +++ b/controllers/pages.go @@ -26,6 +26,7 @@ type SettingModel struct { AppendDateToFileName bool `form:"appendDateToFileName" json:"appendDateToFileName" query:"appendDateToFileName"` AppendEpisodeNumberToFileName bool `form:"appendEpisodeNumberToFileName" json:"appendEpisodeNumberToFileName" query:"appendEpisodeNumberToFileName"` DarkMode bool `form:"darkMode" json:"darkMode" query:"darkMode"` + DownloadEpisodeImages bool `form:"downloadEpisodeImages" json:"downloadEpisodeImages" query:"downloadEpisodeImages"` } func AddPage(c *gin.Context) { diff --git a/controllers/podcast.go b/controllers/podcast.go index c737b40..850ece4 100644 --- a/controllers/podcast.go +++ b/controllers/podcast.go @@ -305,7 +305,9 @@ func UpdateSetting(c *gin.Context) { if err == nil { - err = service.UpdateSettings(model.DownloadOnAdd, model.InitialDownloadCount, model.AutoDownload, model.AppendDateToFileName, model.AppendEpisodeNumberToFileName, model.DarkMode) + err = service.UpdateSettings(model.DownloadOnAdd, model.InitialDownloadCount, + model.AutoDownload, model.AppendDateToFileName, model.AppendEpisodeNumberToFileName, + model.DarkMode, model.DownloadEpisodeImages) if err == nil { c.JSON(200, gin.H{"message": "Success"}) diff --git a/db/dbfunctions.go b/db/dbfunctions.go index 6d92eaf..81b30d5 100644 --- a/db/dbfunctions.go +++ b/db/dbfunctions.go @@ -96,6 +96,13 @@ func UpdateLastEpisodeDateForPodcast(podcastId string, lastEpisode time.Time) er return result.Error } +func GetAllPodcastItemsWithoutImage() (*[]PodcastItem, error) { + var podcastItems []PodcastItem + result := DB.Debug().Preload(clause.Associations).Where("local_image is ?", nil).Where("image != ?", "").Where("download_status=?", Downloaded).Order("created_at desc").Find(&podcastItems) + //fmt.Println("To be downloaded : " + string(len(podcastItems))) + return &podcastItems, result.Error +} + func GetAllPodcastItemsToBeDownloaded() (*[]PodcastItem, error) { var podcastItems []PodcastItem result := DB.Debug().Preload(clause.Associations).Where("download_status=?", NotDownloaded).Find(&podcastItems) diff --git a/db/podcast.go b/db/podcast.go index 54bc557..53275eb 100644 --- a/db/podcast.go +++ b/db/podcast.go @@ -52,6 +52,8 @@ type PodcastItem struct { IsPlayed bool `gorm:"default:false"` BookmarkDate time.Time + + LocalImage string } type DownloadStatus int @@ -71,6 +73,7 @@ type Setting struct { AppendDateToFileName bool `gorm:"default:false"` AppendEpisodeNumberToFileName bool `gorm:"default:false"` DarkMode bool `gorm:"default:false"` + DownloadEpisodeImages bool `gorm:"default:false"` } type Migration struct { Base diff --git a/main.go b/main.go index afe428f..c2e7de6 100644 --- a/main.go +++ b/main.go @@ -168,6 +168,7 @@ func intiCron() { gocron.Every(uint64(checkFrequency)).Minutes().Do(service.RefreshEpisodes) gocron.Every(uint64(checkFrequency)).Minutes().Do(service.CheckMissingFiles) gocron.Every(uint64(checkFrequency) * 2).Minutes().Do(service.UnlockMissedJobs) + gocron.Every(uint64(checkFrequency)).Minutes().Do(service.DownloadMissingImages) gocron.Every(2).Days().Do(service.CreateBackup) <-gocron.Start() } diff --git a/service/fileService.go b/service/fileService.go index aa2e7f0..ea25a9c 100644 --- a/service/fileService.go +++ b/service/fileService.go @@ -58,6 +58,45 @@ func Download(link string, episodeTitle string, podcastName string, prefix strin 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")) diff --git a/service/podcastService.go b/service/podcastService.go index 68f189b..655880b 100644 --- a/service/podcastService.go +++ b/service/podcastService.go @@ -306,6 +306,33 @@ func SetPodcastItemAsQueuedForDownload(id string) error { return db.UpdatePodcastItem(&podcastItem) } +func DownloadMissingImages() error { + setting := db.GetOrCreateSetting() + if !setting.DownloadEpisodeImages { + fmt.Println("No Need To Download Images") + return nil + } + items, err := db.GetAllPodcastItemsWithoutImage() + if err != nil { + return err + } + for _, item := range *items { + downloadImageLocally(item) + } + return nil +} + +func downloadImageLocally(podcastItem db.PodcastItem) error { + path, err := DownloadImage(podcastItem.Image, podcastItem.ID, podcastItem.Podcast.Title) + if err != nil { + return err + } + + podcastItem.LocalImage = path + + return db.UpdatePodcastItem(&podcastItem) +} + func SetPodcastItemBookmarkStatus(id string, bookmark bool) error { var podcastItem db.PodcastItem err := db.GetPodcastItemById(id, &podcastItem) @@ -447,6 +474,10 @@ func DeleteEpisodeFile(podcastItemId string) error { return err } + if podcastItem.LocalImage != "" { + go DeleteFile(podcastItem.LocalImage) + } + return SetPodcastItemAsNotDownloaded(podcastItem.ID, db.Deleted) } func DownloadSingleEpisode(podcastItemId string) error { @@ -465,6 +496,9 @@ func DownloadSingleEpisode(podcastItemId string) error { if err != nil { return err } + if setting.DownloadEpisodeImages { + go downloadImageLocally(podcastItem) + } return SetPodcastItemAsDownloaded(podcastItem.ID, url) } @@ -527,6 +561,10 @@ func DeletePodcast(id string, deleteFiles bool) error { for _, item := range podcastItems { if deleteFiles { DeleteFile(item.DownloadPath) + if item.LocalImage != "" { + DeleteFile(item.LocalImage) + } + } db.DeletePodcastItemById(item.ID) @@ -577,7 +615,7 @@ func GetSearchFromItunes(pod model.ItunesSingleResult) *model.CommonSearchResult return p } -func UpdateSettings(downloadOnAdd bool, initialDownloadCount int, autoDownload bool, appendDateToFileName bool, appendEpisodeNumberToFileName bool, darkMode bool) error { +func UpdateSettings(downloadOnAdd bool, initialDownloadCount int, autoDownload bool, appendDateToFileName bool, appendEpisodeNumberToFileName bool, darkMode bool, downloadEpisodeImages bool) error { setting := db.GetOrCreateSetting() setting.AutoDownload = autoDownload @@ -586,6 +624,7 @@ func UpdateSettings(downloadOnAdd bool, initialDownloadCount int, autoDownload b setting.AppendDateToFileName = appendDateToFileName setting.AppendEpisodeNumberToFileName = appendEpisodeNumberToFileName setting.DarkMode = darkMode + setting.DownloadEpisodeImages = downloadEpisodeImages return db.UpdateSettings(setting) }