optimize home page query & paginte podcast listing

pull/18/merge
Akhil Gupta 4 years ago
parent 50ec6deff2
commit eb96373e4e

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PodGrab</title>
<title>{{.title}} - PodGrab</title>
{{template "commoncss"}}
<style>
img {

@ -68,9 +68,11 @@
<div class="row">
<div class="columns four">
Last Ep : {{ latestEpisodeDate .PodcastItems}}
{{if .LastEpisode}}
Last Ep : {{ formatDate .LastEpisode }}
{{end}}
</div>
{{$downloading:=downloadingEpisodes .PodcastItems}}
{{$downloading:= .DownloadingEpisodesCount}}
<div
class="columns five"
title="{{downloadedEpisodes .PodcastItems}} episodes downloaded out of total {{ len .PodcastItems}} episodes.
@ -78,7 +80,7 @@
"
>
{{if gt $downloading 0}} ({{$downloading}})/{{end}}{{downloadedEpisodes .PodcastItems}}/{{ len .PodcastItems }} episodes
{{if gt $downloading 0}} ({{$downloading}})/{{end}}{{.DownloadedEpisodesCount}}/{{.AllEpisodesCount}} episodes
</div>
<div class="columns three" style="">

@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" integrity="sha512-EZLkOqwILORob+p0BXZc+Vm3RgJBOe1Iq/0fiI7r/wJgzOFZMlsqTa29UEl6v6U6gsV4uIpsNZoV32YZqrCRCQ==" crossorigin="anonymous" />
<title>PodGrab</title>
<title>Episodes - PodGrab</title>
<style>
.container {

@ -32,7 +32,7 @@ func AddPage(c *gin.Context) {
}
func HomePage(c *gin.Context) {
//var podcasts []db.Podcast
podcasts := service.GetAllPodcasts()
podcasts := service.GetAllPodcasts("")
c.HTML(http.StatusOK, "index.html", gin.H{"title": "Podgrab", "podcasts": podcasts})
}
func PodcastPage(c *gin.Context) {
@ -42,19 +42,46 @@ func PodcastPage(c *gin.Context) {
var podcast db.Podcast
if err := db.GetPodcastById(searchByIdQuery.Id, &podcast); err == nil {
setting := c.MustGet("setting").(*db.Setting)
c.HTML(http.StatusOK, "episodes.html", gin.H{
"title": podcast.Title,
"podcastItems": podcast.PodcastItems,
"setting": setting,
"page": 1,
"count": 10,
"totalCount": len(podcast.PodcastItems),
"totalPages": 0,
"nextPage": 0,
"previousPage": 0,
"downloadedOnly": false,
})
var pagination Pagination
if c.ShouldBindQuery(&pagination) == nil {
var page, count int
if page = pagination.Page; page == 0 {
page = 1
}
if count = pagination.Count; count == 0 {
count = 10
}
setting := c.MustGet("setting").(*db.Setting)
totalCount := len(podcast.PodcastItems)
totalPages := math.Ceil(float64(totalCount) / float64(count))
nextPage, previousPage := 0, 0
if float64(page) < totalPages {
nextPage = page + 1
}
if page > 1 {
previousPage = page - 1
}
from := (page - 1) * count
to := page * count
if to > totalCount {
to = totalCount
}
c.HTML(http.StatusOK, "episodes.html", gin.H{
"title": podcast.Title,
"podcastItems": podcast.PodcastItems[from:to],
"setting": setting,
"page": page,
"count": count,
"totalCount": totalCount,
"totalPages": totalPages,
"nextPage": nextPage,
"previousPage": previousPage,
"downloadedOnly": false,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
}
} else {
c.JSON(http.StatusBadRequest, err)
}
@ -151,7 +178,7 @@ func Search(c *gin.Context) {
if c.ShouldBindQuery(&searchQuery) == nil {
itunesService := new(service.ItunesService)
data := itunesService.Query(searchQuery.Q)
allPodcasts := service.GetAllPodcasts()
allPodcasts := service.GetAllPodcasts("")
urls := make(map[string]string, len(*allPodcasts))
for _, pod := range *allPodcasts {

@ -4,6 +4,7 @@ import (
"fmt"
"log"
"net/http"
"strings"
"github.com/akhilrex/podgrab/model"
"github.com/akhilrex/podgrab/service"
@ -12,11 +13,27 @@ import (
"github.com/gin-gonic/gin"
)
const (
DateAdded = "dateadded"
Name = "name"
LastEpisode = "lastepisode"
)
const (
Asc = "asc"
Desc = "desc"
)
type SearchQuery struct {
Q string `binding:"required" form:"q"`
Type string `form:"type"`
}
type PodcastListQuery struct {
Sort string `uri:"sort" query:"sort" json:"sort" form:"sort" default:"created_at"`
Order string `uri:"order" query:"order" json:"order" form:"order" default:"asc"`
}
type SearchByIdQuery struct {
Id string `binding:"required" uri:"id" json:"id" form:"id"`
}
@ -37,9 +54,25 @@ type AddPodcastData struct {
}
func GetAllPodcasts(c *gin.Context) {
var podcasts []db.Podcast
db.GetAllPodcasts(&podcasts)
c.JSON(200, podcasts)
var podcastListQuery PodcastListQuery
if c.ShouldBindQuery(&podcastListQuery) == nil {
var order = strings.ToLower(podcastListQuery.Order)
var sorting = "created_at"
switch sort := strings.ToLower(podcastListQuery.Sort); sort {
case DateAdded:
sorting = "created_at"
case Name:
sorting = "title"
case LastEpisode:
sorting = "last_episode"
}
if order == Desc {
sorting = fmt.Sprintf("%s desc", sorting)
}
c.JSON(200, service.GetAllPodcasts(sorting))
}
}
func GetPodcastById(c *gin.Context) {
@ -179,7 +212,6 @@ func DownloadPodcastItem(c *gin.Context) {
var searchByIdQuery SearchByIdQuery
if c.ShouldBindUri(&searchByIdQuery) == nil {
go service.DownloadSingleEpisode(searchByIdQuery.Id)
c.JSON(200, gin.H{})
} else {

@ -1,6 +1,7 @@
package db
import (
"database/sql"
"errors"
"fmt"
"time"
@ -18,9 +19,11 @@ func GetPodcastsByURLList(urls []string, podcasts *[]Podcast) error {
result := DB.Preload(clause.Associations).Where("url in ?", urls).First(&podcasts)
return result.Error
}
func GetAllPodcasts(podcasts *[]Podcast) error {
result := DB.Preload("PodcastItems").Find(&podcasts)
func GetAllPodcasts(podcasts *[]Podcast, sorting string) error {
if sorting == "" {
sorting = "created_at"
}
result := DB.Debug().Order(sorting).Find(&podcasts)
return result.Error
}
func GetAllPodcastItems(podcasts *[]PodcastItem) error {
@ -74,6 +77,10 @@ func SetAllEpisodesToDownload(podcastId string) error {
result := DB.Debug().Model(PodcastItem{}).Where(&PodcastItem{PodcastID: podcastId, DownloadStatus: Deleted}).Update("download_status", NotDownloaded)
return result.Error
}
func UpdateLastEpisodeDateForPodcast(podcastId string, lastEpisode time.Time) error {
result := DB.Debug().Model(Podcast{}).Where("id=?", podcastId).Update("last_episode", lastEpisode)
return result.Error
}
func GetAllPodcastItemsToBeDownloaded() (*[]PodcastItem, error) {
var podcastItems []PodcastItem
@ -87,6 +94,16 @@ func GetAllPodcastItemsAlreadyDownloaded() (*[]PodcastItem, error) {
return &podcastItems, result.Error
}
func GetPodcastEpisodeStats() (*[]PodcastItemStatsModel, error) {
var stats []PodcastItemStatsModel
result := DB.Model(&PodcastItem{}).Select("download_status,podcast_id, count(1) as count").Group("podcast_id,download_status").Find(&stats)
return &stats, result.Error
}
func ForceSetLastEpisodeDate(podcastId string) {
DB.Exec("update podcasts set last_episode = (select max(pi.pub_date) from podcast_items pi where pi.podcast_id = @id) where id = @id", sql.Named("id", podcastId))
}
func GetPodcastItemsByPodcastIdAndGUIDs(podcastId string, guids []string) (*[]PodcastItem, error) {
var podcastItems []PodcastItem
result := DB.Preload(clause.Associations).Where(&PodcastItem{PodcastID: podcastId}).Where("guid IN ?", guids).Find(&podcastItems)

@ -17,7 +17,13 @@ type Podcast struct {
URL string
PodcastItems []PodcastItem
LastEpisode *time.Time
PodcastItems []PodcastItem `json:"-"`
DownloadedEpisodesCount int `gorm:"-"`
DownloadingEpisodesCount int `gorm:"-"`
AllEpisodesCount int `gorm:"-"`
}
//PodcastItem is
@ -78,3 +84,9 @@ type JobLock struct {
func (lock *JobLock) IsLocked() bool {
return lock != nil && lock.Date != time.Time{}
}
type PodcastItemStatsModel struct {
PodcastID string
DownloadStatus DownloadStatus
Count int
}

@ -35,6 +35,10 @@ func main() {
funcMap := template.FuncMap{
"formatDate": func(raw time.Time) string {
if raw == (time.Time{}) {
return ""
}
return raw.Format("Jan 2 2006")
},
"naturalDate": func(raw time.Time) string {

@ -42,10 +42,28 @@ func FetchURL(url string) (model.PodcastData, error) {
err = xml.Unmarshal(body, &response)
return response, err
}
func GetAllPodcasts() *[]db.Podcast {
func GetAllPodcasts(sorting string) *[]db.Podcast {
var podcasts []db.Podcast
db.GetAllPodcasts(&podcasts)
return &podcasts
db.GetAllPodcasts(&podcasts, sorting)
stats, _ := db.GetPodcastEpisodeStats()
type Key struct {
PodcastID string
DownloadStatus db.DownloadStatus
}
statsMap := make(map[Key]int)
for _, stat := range *stats {
statsMap[Key{stat.PodcastID, stat.DownloadStatus}] = stat.Count
}
var toReturn []db.Podcast
for _, podcast := range podcasts {
podcast.DownloadedEpisodesCount = statsMap[Key{podcast.ID, db.Downloaded}]
podcast.DownloadingEpisodesCount = statsMap[Key{podcast.ID, db.NotDownloaded}]
podcast.AllEpisodesCount = podcast.DownloadedEpisodesCount + podcast.DownloadingEpisodesCount + statsMap[Key{podcast.ID, db.Deleted}]
toReturn = append(toReturn, podcast)
}
return &toReturn
}
func AddOpml(content string) error {
@ -84,7 +102,7 @@ func AddOpml(content string) error {
}
func ExportOmpl() (model.OpmlModel, error) {
podcasts := GetAllPodcasts()
podcasts := GetAllPodcasts("")
var outlines []model.OpmlOutline
for _, podcast := range *podcasts {
toAdd := model.OpmlOutline{
@ -160,6 +178,7 @@ func AddPodcastItems(podcast *db.Podcast) error {
for _, item := range *existingItems {
keyMap[item.GUID] = 1
}
var latestDate = time.Time{}
for i := 0; i < len(data.Channel.Item); i++ {
obj := data.Channel.Item[i]
@ -177,6 +196,10 @@ func AddPodcastItems(podcast *db.Podcast) error {
pubDate, _ = time.Parse(modifiedRFC1123, obj.PubDate)
}
if latestDate.Before(pubDate) {
latestDate = pubDate
}
var downloadStatus db.DownloadStatus
if setting.AutoDownload {
if i < limit {
@ -202,9 +225,23 @@ func AddPodcastItems(podcast *db.Podcast) error {
db.CreatePodcastItem(&podcastItem)
}
}
if (latestDate != time.Time{}) {
db.UpdateLastEpisodeDateForPodcast(podcast.ID, latestDate)
}
return err
}
func SetPodcastItemAsQueuedForDownload(id string) error {
var podcastItem db.PodcastItem
err := db.GetPodcastItemById(id, &podcastItem)
if err != nil {
return err
}
podcastItem.DownloadStatus = db.NotDownloaded
return db.UpdatePodcastItem(&podcastItem)
}
func SetPodcastItemAsDownloaded(id string, location string) error {
var podcastItem db.PodcastItem
err := db.GetPodcastItemById(id, &podcastItem)
@ -326,6 +363,7 @@ func DownloadSingleEpisode(podcastItemId string) error {
}
setting := db.GetOrCreateSetting()
SetPodcastItemAsQueuedForDownload(podcastItemId)
url, err := Download(podcastItem.FileURL, podcastItem.Title, podcastItem.Podcast.Title, GetPodcastPrefix(&podcastItem, setting))
if err != nil {
@ -336,14 +374,17 @@ func DownloadSingleEpisode(podcastItemId string) error {
func RefreshEpisodes() error {
var data []db.Podcast
err := db.GetAllPodcasts(&data)
err := db.GetAllPodcasts(&data, "")
if err != nil {
return err
}
for _, item := range data {
if item.LastEpisode == nil {
fmt.Println(item.Title)
db.ForceSetLastEpisodeDate(item.ID)
}
AddPodcastItems(&item)
}
setting := db.GetOrCreateSetting()
if setting.AutoDownload {

Loading…
Cancel
Save