added settings

pull/24/head
Akhil Gupta 4 years ago
parent 67f040a7fb
commit e1c0a2a021

@ -35,6 +35,7 @@
<hr> <hr>
<div class="row" id="searchContainer"> <div class="row" id="searchContainer">
<h4>Search for your favorite podcast</h4> <h4>Search for your favorite podcast</h4>
<p>Experimental: Uses gpodder API to show search results.</p>
<form action="/search" method="post" @submit="search"> <form action="/search" method="post" @submit="search">
<div class="nine columns"> <div class="nine columns">
<input type="search" name="search" id="search" placeholder="Search for your podcast" v-model="query" class="u-full-width"> <input type="search" name="search" id="search" placeholder="Search for your podcast" v-model="query" class="u-full-width">

@ -45,8 +45,10 @@ hr{
<h1>{{ .title }}</h1> <h1>{{ .title }}</h1>
</section> </section>
{{template "navbar"}} {{template "navbar"}}
<br> <br>{{$setting := .setting}}
{{range .podcastItems}} {{range .podcastItems}}
<div class="podcasts row"> <div class="podcasts row">
<div class="columns two"> <div class="columns two">
<img class="u-full-width" src="{{ .Image }}" alt="{{ .Title }}"> <img class="u-full-width" src="{{ .Image }}" alt="{{ .Title }}">
@ -57,6 +59,10 @@ hr{
<p>{{ .Summary }}</p> <p>{{ .Summary }}</p>
{{if .DownloadPath}} {{if .DownloadPath}}
<a class="button button-primary" href="{{ .DownloadPath }}" download>Download</a> <a class="button button-primary" href="{{ .DownloadPath }}" download>Download</a>
{{else}}
{{if not $setting.AutoDownload}}
<a class="button button-primary" onclick="downloadToDisk('{{.ID}}')" download>Download to Disk</a>
{{end}}
{{end }} {{end }}
</div> </div>
<div class="columns one"> <div class="columns one">
@ -67,5 +73,35 @@ hr{
<hr> <hr>
{{end}} {{end}}
</div> </div>
{{template "scripts"}}
<script>
function downloadToDisk(id){
axios.get("/podcastitems/"+id+"/download")
.then(function(response){
Vue.toasted.show('Podcast download enqueued.' ,{
theme: "bubble",
position: "top-right",
duration : 5000
});
var row = document.getElementById('podcast-'+id);
row.remove();
})
.catch(function(error){
if(error.response){
Vue.toasted.show(error.response.data?.message, {
theme: "bubble",
position: "top-right",
duration : 5000
})
}
}).
then(function(){
})
return false;
}
</script>
</body> </body>
</html> </html>

@ -133,6 +133,7 @@
</section> </section>
{{template "navbar"}} {{template "navbar"}}
<br> <br>
{{$setting := .setting}}
{{range .podcast.PodcastItems}} {{range .podcast.PodcastItems}}
<div class="podcasts row"> <div class="podcasts row">
<div class="columns three"> <div class="columns three">
@ -143,7 +144,13 @@
<small>{{ formatDate .PubDate }}</small> <small>{{ formatDate .PubDate }}</small>
<p>{{ .Summary }}</p> <p>{{ .Summary }}</p>
{{if .DownloadPath}}
<a class="button button-primary" href="{{ .DownloadPath }}" download>Download</a> <a class="button button-primary" href="{{ .DownloadPath }}" download>Download</a>
{{else}}
{{if not $setting.AutoDownload}}
<a class="button button-primary" onclick="downloadToDisk('{{.ID}}')" download>Download to Disk</a>
{{end}}
{{end }}
</div> </div>
<div class="columns one"> <div class="columns one">
@ -154,5 +161,35 @@
<hr> <hr>
{{end}} {{end}}
</div> </div>
{{template "scripts"}}
<script>
function downloadToDisk(id){
axios.get("/podcastitems/"+id+"/download")
.then(function(response){
Vue.toasted.show('Podcast download enqueued.' ,{
theme: "bubble",
position: "top-right",
duration : 5000
});
var row = document.getElementById('podcast-'+id);
row.remove();
})
.catch(function(error){
if(error.response){
Vue.toasted.show(error.response.data?.message, {
theme: "bubble",
position: "top-right",
duration : 5000
})
}
}).
then(function(){
})
return false;
}
</script>
</body> </body>
</html> </html>

@ -30,7 +30,8 @@ func PodcastPage(c *gin.Context) {
var podcast db.Podcast var podcast db.Podcast
if err := db.GetPodcastById(searchByIdQuery.Id, &podcast); err == nil { if err := db.GetPodcastById(searchByIdQuery.Id, &podcast); err == nil {
c.HTML(http.StatusOK, "podcast.html", gin.H{"title": podcast.Title, "podcast": podcast}) setting := c.MustGet("setting").(*db.Setting)
c.HTML(http.StatusOK, "podcast.html", gin.H{"title": podcast.Title, "podcast": podcast, "setting": setting})
} else { } else {
c.JSON(http.StatusBadRequest, err) c.JSON(http.StatusBadRequest, err)
} }
@ -52,7 +53,8 @@ func AllEpisodesPage(c *gin.Context) {
var podcastItems []db.PodcastItem var podcastItems []db.PodcastItem
if err := db.GetPaginatedPodcastItems(page, count, &podcastItems); err == nil { if err := db.GetPaginatedPodcastItems(page, count, &podcastItems); err == nil {
c.HTML(http.StatusOK, "episodes.html", gin.H{"title": "All Episodes", "podcastItems": podcastItems}) setting := c.MustGet("setting").(*db.Setting)
c.HTML(http.StatusOK, "episodes.html", gin.H{"title": "All Episodes", "podcastItems": podcastItems, "setting": setting})
} else { } else {
c.JSON(http.StatusBadRequest, err) c.JSON(http.StatusBadRequest, err)
} }

@ -97,6 +97,17 @@ func GetPodcastItemById(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"}) c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
} }
} }
func DownloadPodcastItem(c *gin.Context) {
var searchByIdQuery SearchByIdQuery
if c.ShouldBindUri(&searchByIdQuery) == nil {
go service.DownloadSingleEpisode(searchByIdQuery.Id)
c.JSON(200, gin.H{})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
}
}
func AddPodcast(c *gin.Context) { func AddPodcast(c *gin.Context) {
var addPodcastData AddPodcastData var addPodcastData AddPodcastData
@ -104,7 +115,10 @@ func AddPodcast(c *gin.Context) {
if err == nil { if err == nil {
pod, err := service.AddPodcast(addPodcastData.Url) pod, err := service.AddPodcast(addPodcastData.Url)
if err == nil { if err == nil {
go service.RefreshEpisodes() setting := c.MustGet("setting").(*db.Setting)
if setting.DownloadOnAdd {
go service.RefreshEpisodes()
}
c.JSON(200, pod) c.JSON(200, pod)
} else { } else {
if v, ok := err.(*model.PodcastAlreadyExistsError); ok { if v, ok := err.(*model.PodcastAlreadyExistsError); ok {

@ -2,9 +2,9 @@ package db
import ( import (
"fmt" "fmt"
"log"
"os" "os"
"path" "path"
"log"
"gorm.io/driver/sqlite" "gorm.io/driver/sqlite"
@ -35,7 +35,7 @@ func Init() (*gorm.DB, error) {
//Migrate Database //Migrate Database
func Migrate() { func Migrate() {
DB.AutoMigrate(&Podcast{}, &PodcastItem{}) DB.AutoMigrate(&Podcast{}, &PodcastItem{}, &Setting{})
} }

@ -1,8 +1,10 @@
package db package db
import ( import (
"errors"
"time" "time"
"gorm.io/gorm"
"gorm.io/gorm/clause" "gorm.io/gorm/clause"
) )
@ -31,7 +33,9 @@ func GetPaginatedPodcastItems(page int, count int, podcasts *[]PodcastItem) erro
} }
func GetPodcastById(id string, podcast *Podcast) error { func GetPodcastById(id string, podcast *Podcast) error {
result := DB.Preload(clause.Associations).First(&podcast, "id=?", id) result := DB.Preload("PodcastItems", func(db *gorm.DB) *gorm.DB {
return db.Order("podcast_items.pub_date DESC")
}).First(&podcast, "id=?", id)
return result.Error return result.Error
} }
@ -87,3 +91,12 @@ func UpdatePodcastItem(podcastItem *PodcastItem) error {
tx := DB.Omit("Podcast").Save(&podcastItem) tx := DB.Omit("Podcast").Save(&podcastItem)
return tx.Error return tx.Error
} }
func GetOrCreateSetting() *Setting {
var setting Setting
result := DB.First(&setting)
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
DB.Save(&Setting{})
DB.First(&setting)
}
return &setting
}

@ -42,3 +42,10 @@ type PodcastItem struct {
DownloadDate time.Time DownloadDate time.Time
DownloadPath string DownloadPath string
} }
type Setting struct {
Base
DownloadOnAdd bool `gorm:"default:true"`
InitialDownloadCount int `gorm:"default:5"`
AutoDownload bool `gorm:"default:true"`
}

@ -31,6 +31,8 @@ func main() {
dataPath := os.Getenv("DATA") dataPath := os.Getenv("DATA")
r.Static("/webassets", "./webassets") r.Static("/webassets", "./webassets")
r.Static("/assets", dataPath) r.Static("/assets", dataPath)
r.Use(setupSettings())
funcMap := template.FuncMap{ funcMap := template.FuncMap{
"formatDate": func(raw time.Time) string { "formatDate": func(raw time.Time) string {
return raw.Format("Jan 2 2006") return raw.Format("Jan 2 2006")
@ -58,6 +60,7 @@ func main() {
r.GET("/podcastitems", controllers.GetAllPodcastItems) r.GET("/podcastitems", controllers.GetAllPodcastItems)
r.GET("/podcastitems/:id", controllers.GetPodcastItemById) r.GET("/podcastitems/:id", controllers.GetPodcastItemById)
r.GET("/podcastitems/:id/download", controllers.DownloadPodcastItem)
r.GET("/add", controllers.AddPage) r.GET("/add", controllers.AddPage)
r.GET("/search", controllers.Search) r.GET("/search", controllers.Search)
@ -71,6 +74,14 @@ func main() {
r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080") r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
} }
func setupSettings() gin.HandlerFunc {
return func(c *gin.Context) {
setting := db.GetOrCreateSetting()
c.Set("setting", setting)
c.Next()
}
}
func intiCron() { func intiCron() {
checkFrequency, err := strconv.Atoi(os.Getenv("CHECK_FREQUENCY")) checkFrequency, err := strconv.Atoi(os.Getenv("CHECK_FREQUENCY"))

@ -56,14 +56,14 @@ func AddPodcast(url string) (db.Podcast, error) {
} }
func AddPodcastItems(podcast *db.Podcast) error { func AddPodcastItems(podcast *db.Podcast) error {
fmt.Println("Creating: " + podcast.ID) //fmt.Println("Creating: " + podcast.ID)
data, err := FetchURL(podcast.URL) data, err := FetchURL(podcast.URL)
if err != nil { if err != nil {
//log.Fatal(err) //log.Fatal(err)
return err return err
} }
//p := bluemonday.StrictPolicy() setting := db.GetOrCreateSetting()
limit := 5 limit := setting.InitialDownloadCount
if len(data.Channel.Item) < limit { if len(data.Channel.Item) < limit {
limit = len(data.Channel.Item) limit = len(data.Channel.Item)
} }
@ -91,20 +91,22 @@ func AddPodcastItems(podcast *db.Podcast) error {
return err return err
} }
func SetPodcastItemAsDownloaded(id string, location string) { func SetPodcastItemAsDownloaded(id string, location string) error {
var podcastItem db.PodcastItem var podcastItem db.PodcastItem
db.GetPodcastItemById(id, &podcastItem) err := db.GetPodcastItemById(id, &podcastItem)
if err != nil {
return err
}
podcastItem.DownloadDate = time.Now() podcastItem.DownloadDate = time.Now()
podcastItem.DownloadPath = location podcastItem.DownloadPath = location
db.UpdatePodcastItem(&podcastItem) return db.UpdatePodcastItem(&podcastItem)
} }
func DownloadMissingEpisodes() error { func DownloadMissingEpisodes() error {
data, err := db.GetAllPodcastItemsToBeDownloaded() data, err := db.GetAllPodcastItemsToBeDownloaded()
fmt.Println("Processing episodes: ", strconv.Itoa(len(*data))) //fmt.Println("Processing episodes: ", strconv.Itoa(len(*data)))
if err != nil { if err != nil {
return err return err
} }
@ -115,6 +117,21 @@ func DownloadMissingEpisodes() error {
} }
return nil return nil
} }
func DownloadSingleEpisode(podcastItemId string) error {
var podcastItem db.PodcastItem
err := db.GetPodcastItemById(podcastItemId, &podcastItem)
//fmt.Println("Processing episodes: ", strconv.Itoa(len(*data)))
if err != nil {
return err
}
url, err := Download(podcastItem.FileURL, podcastItem.Title, podcastItem.Podcast.Title)
if err != nil {
return err
}
return SetPodcastItemAsDownloaded(podcastItem.ID, url)
}
func RefreshEpisodes() error { func RefreshEpisodes() error {
var data []db.Podcast var data []db.Podcast
@ -127,7 +144,10 @@ func RefreshEpisodes() error {
AddPodcastItems(&item) AddPodcastItems(&item)
} }
go DownloadMissingEpisodes() setting := db.GetOrCreateSetting()
if setting.AutoDownload {
go DownloadMissingEpisodes()
}
return nil return nil
} }

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save