use enum for PodcastEpisodeStatus and PodcastAutoDownload
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -179,21 +179,21 @@
|
|||||||
<table id="podcast-preferences">
|
<table id="podcast-preferences">
|
||||||
{{ range $pref := .Podcasts }}
|
{{ range $pref := .Podcasts }}
|
||||||
<tr>
|
<tr>
|
||||||
<form id="podcast-{{ $pref.ID }}-delete" action="{{ printf "/admin/delete_podcast_do?id=%d" $pref.ID | path }}" method="post"></form>
|
|
||||||
<form id="podcast-{{ $pref.ID }}-download" action="{{ printf "/admin/download_podcast_do?id=%d" $pref.ID | path }}" method="post"></form>
|
<form id="podcast-{{ $pref.ID }}-download" action="{{ printf "/admin/download_podcast_do?id=%d" $pref.ID | path }}" method="post"></form>
|
||||||
<form id="podcast-{{ $pref.ID }}-autodl" action="{{ printf "/admin/update_podcast_do?id=%d" $pref.ID | path }}" method="post"></form>
|
<form id="podcast-{{ $pref.ID }}-auto-download" action="{{ printf "/admin/update_podcast_do?id=%d" $pref.ID | path }}" method="post"></form>
|
||||||
|
<form id="podcast-{{ $pref.ID }}-delete" action="{{ printf "/admin/delete_podcast_do?id=%d" $pref.ID | path }}" method="post"></form>
|
||||||
<td>{{ $pref.Title }}</td>
|
<td>{{ $pref.Title }}</td>
|
||||||
<td><select form="podcast-{{ $pref.ID }}-autodl" name="auto_dl">
|
<td><select form="podcast-{{ $pref.ID }}-auto-download" name="setting">
|
||||||
{{ if eq $pref.AutoDownload "dl_latest" }}
|
{{ if eq $pref.AutoDownload "latest" }}
|
||||||
<option value="dl_latest" selected="selected">download latest</option>
|
<option value="latest" selected="selected">download latest</option>
|
||||||
<option value="dl_none">no auto download</option>
|
<option value="none">no auto download</option>
|
||||||
{{ else }}
|
{{ else }}
|
||||||
<option value="dl_none" selected="selected" >no auto download</option>
|
<option value="none" selected="selected" >no auto download</option>
|
||||||
<option value="dl_latest">download latest</option>
|
<option value="latest">download latest</option>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</select></td>
|
</select></td>
|
||||||
<td><input form="podcast-{{ $pref.ID }}-download" type="submit" value="download all"></td>
|
<td><input form="podcast-{{ $pref.ID }}-download" type="submit" value="download all"></td>
|
||||||
<td><input form="podcast-{{ $pref.ID }}-autodl" type="submit" value="save"></td>
|
<td><input form="podcast-{{ $pref.ID }}-auto-download" type="submit" value="save"></td>
|
||||||
<td><input form="podcast-{{ $pref.ID }}-delete" type="submit" value="delete"></td>
|
<td><input form="podcast-{{ $pref.ID }}-delete" type="submit" value="delete"></td>
|
||||||
</tr>
|
</tr>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|||||||
@@ -470,16 +470,28 @@ func (c *Controller) ServePodcastUpdateDo(r *http.Request) *Response {
|
|||||||
code: 400,
|
code: 400,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
autoDlSetting := r.FormValue("auto_dl")
|
setting := db.PodcastAutoDownload(r.FormValue("setting"))
|
||||||
if err := c.Podcasts.SetAutoDownload(id, autoDlSetting); err != nil {
|
var message string
|
||||||
|
switch setting {
|
||||||
|
case db.PodcastAutoDownloadLatest:
|
||||||
|
message = "future podcast episodes will be automatically downloaded"
|
||||||
|
case db.PodcastAutoDownloadNone:
|
||||||
|
message = "future podcast episodes will not be downloaded"
|
||||||
|
default:
|
||||||
return &Response{
|
return &Response{
|
||||||
err: "please provide a valid podcast id and dl setting",
|
err: "please provide a valid podcast download type",
|
||||||
|
code: 400,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := c.Podcasts.SetAutoDownload(id, setting); err != nil {
|
||||||
|
return &Response{
|
||||||
|
flashW: []string{fmt.Sprintf("could not update auto download setting: %v", err)},
|
||||||
code: 400,
|
code: 400,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &Response{
|
return &Response{
|
||||||
redirect: "/admin/home",
|
redirect: "/admin/home",
|
||||||
flashN: []string{"future podcast episodes will be automatically downloaded"},
|
flashN: []string{message},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func NewPodcastEpisode(p *db.Podcast, e *db.PodcastEpisode) *PodcastEpisode {
|
|||||||
ChannelID: p.SID(),
|
ChannelID: p.SID(),
|
||||||
Title: e.Title,
|
Title: e.Title,
|
||||||
Description: e.Description,
|
Description: e.Description,
|
||||||
Status: e.Status,
|
Status: string(e.Status),
|
||||||
CoverArt: p.SID(),
|
CoverArt: p.SID(),
|
||||||
PublishDate: *e.PublishDate,
|
PublishDate: *e.PublishDate,
|
||||||
Genre: "Podcast",
|
Genre: "Podcast",
|
||||||
|
|||||||
@@ -289,6 +289,13 @@ type AlbumGenre struct {
|
|||||||
GenreID int `gorm:"not null; unique_index:idx_album_id_genre_id" sql:"default: null; type:int REFERENCES genres(id) ON DELETE CASCADE"`
|
GenreID int `gorm:"not null; unique_index:idx_album_id_genre_id" sql:"default: null; type:int REFERENCES genres(id) ON DELETE CASCADE"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PodcastAutoDownload string
|
||||||
|
|
||||||
|
const (
|
||||||
|
PodcastAutoDownloadLatest PodcastAutoDownload = "latest"
|
||||||
|
PodcastAutoDownloadNone PodcastAutoDownload = "none"
|
||||||
|
)
|
||||||
|
|
||||||
type Podcast struct {
|
type Podcast struct {
|
||||||
ID int `gorm:"primary_key"`
|
ID int `gorm:"primary_key"`
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
@@ -301,7 +308,7 @@ type Podcast struct {
|
|||||||
ImagePath string
|
ImagePath string
|
||||||
Error string
|
Error string
|
||||||
Episodes []*PodcastEpisode
|
Episodes []*PodcastEpisode
|
||||||
AutoDownload string
|
AutoDownload PodcastAutoDownload
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Podcast) Fullpath(podcastPath string) string {
|
func (p *Podcast) Fullpath(podcastPath string) string {
|
||||||
@@ -313,6 +320,15 @@ func (p *Podcast) SID() *specid.ID {
|
|||||||
return &specid.ID{Type: specid.Podcast, Value: p.ID}
|
return &specid.ID{Type: specid.Podcast, Value: p.ID}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PodcastEpisodeStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
PodcastEpisodeStatusDownloading PodcastEpisodeStatus = "downloading"
|
||||||
|
PodcastEpisodeStatusSkipped PodcastEpisodeStatus = "skipped"
|
||||||
|
PodcastEpisodeStatusDeleted PodcastEpisodeStatus = "deleted"
|
||||||
|
PodcastEpisodeStatusCompleted PodcastEpisodeStatus = "completed"
|
||||||
|
)
|
||||||
|
|
||||||
type PodcastEpisode struct {
|
type PodcastEpisode struct {
|
||||||
ID int `gorm:"primary_key"`
|
ID int `gorm:"primary_key"`
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
@@ -328,7 +344,7 @@ type PodcastEpisode struct {
|
|||||||
Size int
|
Size int
|
||||||
Path string
|
Path string
|
||||||
Filename string
|
Filename string
|
||||||
Status string
|
Status PodcastEpisodeStatus
|
||||||
Error string
|
Error string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,21 +24,13 @@ import (
|
|||||||
"go.senan.xyz/gonic/server/scanner/tags"
|
"go.senan.xyz/gonic/server/scanner/tags"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const DownloadAllWaitInterval = 3 * time.Second
|
||||||
|
|
||||||
type Podcasts struct {
|
type Podcasts struct {
|
||||||
DB *db.DB
|
DB *db.DB
|
||||||
PodcastBasePath string
|
PodcastBasePath string
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
episodeDownloading = "downloading"
|
|
||||||
episodeSkipped = "skipped"
|
|
||||||
episodeDeleted = "deleted"
|
|
||||||
episodeCompleted = "completed"
|
|
||||||
|
|
||||||
autoDlLatest = "dl_latest"
|
|
||||||
autoDlNone = "dl_none"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (p *Podcasts) GetPodcastOrAll(userID int, id int, includeEpisodes bool) ([]*db.Podcast, error) {
|
func (p *Podcasts) GetPodcastOrAll(userID int, id int, includeEpisodes bool) ([]*db.Podcast, error) {
|
||||||
podcasts := []*db.Podcast{}
|
podcasts := []*db.Podcast{}
|
||||||
q := p.DB.Where("user_id=?", userID)
|
q := p.DB.Where("user_id=?", userID)
|
||||||
@@ -102,9 +94,7 @@ func (p *Podcasts) AddNewPodcast(rssURL string, feed *gofeed.Feed,
|
|||||||
return &podcast, nil
|
return &podcast, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var errNoSuchAutoDlOption = errors.New("invalid autodownload setting")
|
func (p *Podcasts) SetAutoDownload(podcastID int, setting db.PodcastAutoDownload) error {
|
||||||
|
|
||||||
func (p *Podcasts) SetAutoDownload(podcastID int, setting string) error {
|
|
||||||
podcast := db.Podcast{}
|
podcast := db.Podcast{}
|
||||||
err := p.DB.
|
err := p.DB.
|
||||||
Where("id=?", podcastID).
|
Where("id=?", podcastID).
|
||||||
@@ -113,15 +103,11 @@ func (p *Podcasts) SetAutoDownload(podcastID int, setting string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
switch setting {
|
podcast.AutoDownload = setting
|
||||||
case autoDlLatest:
|
if err := p.DB.Save(&podcast).Error; err != nil {
|
||||||
podcast.AutoDownload = autoDlLatest
|
return fmt.Errorf("save setting: %w", err)
|
||||||
return p.DB.Save(&podcast).Error
|
|
||||||
case autoDlNone:
|
|
||||||
podcast.AutoDownload = autoDlNone
|
|
||||||
return p.DB.Save(&podcast).Error
|
|
||||||
}
|
}
|
||||||
return errNoSuchAutoDlOption
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEntriesAfterDate(feed []*gofeed.Item, after time.Time) []*gofeed.Item {
|
func getEntriesAfterDate(feed []*gofeed.Item, after time.Time) []*gofeed.Item {
|
||||||
@@ -160,8 +146,8 @@ func (p *Podcasts) AddNewEpisodes(podcast *db.Podcast, items []*gofeed.Item) err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if podcast.AutoDownload == autoDlLatest &&
|
if podcast.AutoDownload == db.PodcastAutoDownloadLatest &&
|
||||||
(episode.Status != episodeCompleted && episode.Status != episodeDownloading) {
|
(episode.Status != db.PodcastEpisodeStatusCompleted && episode.Status != db.PodcastEpisodeStatusDownloading) {
|
||||||
if err := p.DownloadEpisode(episode.ID); err != nil {
|
if err := p.DownloadEpisode(episode.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -240,7 +226,7 @@ func itemToEpisode(podcastID, size, duration int, audio string,
|
|||||||
Size: size,
|
Size: size,
|
||||||
PublishDate: item.PublishedParsed,
|
PublishDate: item.PublishedParsed,
|
||||||
AudioURL: audio,
|
AudioURL: audio,
|
||||||
Status: episodeSkipped,
|
Status: db.PodcastEpisodeStatusSkipped,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,14 +313,16 @@ func (p *Podcasts) DownloadPodcastAll(podcastID int) error {
|
|||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
for _, episode := range podcastEpisodes {
|
for _, episode := range podcastEpisodes {
|
||||||
if episode.Status == episodeDownloading || episode.Status == episodeCompleted {
|
if episode.Status == db.PodcastEpisodeStatusDownloading || episode.Status == db.PodcastEpisodeStatusCompleted {
|
||||||
log.Println("skipping episode is in progress or already downloaded")
|
log.Println("skipping episode is in progress or already downloaded")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := p.DownloadEpisode(episode.ID); err != nil {
|
if err := p.DownloadEpisode(episode.ID); err != nil {
|
||||||
log.Println(err)
|
log.Printf("error downloading episode: %v", err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
log.Printf("Finished downloading episode: \"%s\"", episode.Title)
|
log.Printf("finished downloading episode: %q", episode.Title)
|
||||||
|
time.Sleep(DownloadAllWaitInterval)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return nil
|
return nil
|
||||||
@@ -357,11 +345,11 @@ func (p *Podcasts) DownloadEpisode(episodeID int) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("get podcast by id: %w", err)
|
return fmt.Errorf("get podcast by id: %w", err)
|
||||||
}
|
}
|
||||||
if podcastEpisode.Status == episodeDownloading {
|
if podcastEpisode.Status == db.PodcastEpisodeStatusDownloading {
|
||||||
log.Printf("Already downloading podcast episode with id %d", episodeID)
|
log.Printf("Already downloading podcast episode with id %d", episodeID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
podcastEpisode.Status = episodeDownloading
|
podcastEpisode.Status = db.PodcastEpisodeStatusDownloading
|
||||||
p.DB.Save(&podcastEpisode)
|
p.DB.Save(&podcastEpisode)
|
||||||
// nolint: bodyclose
|
// nolint: bodyclose
|
||||||
resp, err := http.Get(podcastEpisode.AudioURL)
|
resp, err := http.Get(podcastEpisode.AudioURL)
|
||||||
@@ -475,7 +463,7 @@ func (p *Podcasts) doPodcastDownload(podcastEpisode *db.PodcastEpisode, file *os
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
podcastEpisode.Bitrate = podcastTags.Bitrate()
|
podcastEpisode.Bitrate = podcastTags.Bitrate()
|
||||||
podcastEpisode.Status = episodeCompleted
|
podcastEpisode.Status = db.PodcastEpisodeStatusCompleted
|
||||||
podcastEpisode.Length = podcastTags.Length()
|
podcastEpisode.Length = podcastTags.Length()
|
||||||
podcastEpisode.Size = int(stat.Size())
|
podcastEpisode.Size = int(stat.Size())
|
||||||
return p.DB.Save(podcastEpisode).Error
|
return p.DB.Save(podcastEpisode).Error
|
||||||
@@ -517,7 +505,7 @@ func (p *Podcasts) DeletePodcastEpisode(podcastEpisodeID int) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
episode.Status = episodeDeleted
|
episode.Status = db.PodcastEpisodeStatusDeleted
|
||||||
p.DB.Save(&episode)
|
p.DB.Save(&episode)
|
||||||
if err := os.Remove(filepath.Join(p.PodcastBasePath, episode.Path)); err != nil {
|
if err := os.Remove(filepath.Join(p.PodcastBasePath, episode.Path)); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
Reference in New Issue
Block a user