Merge pull request #2 from akhilrex/master

Rebase from akhilrex
pull/279/head
kucksdorfs 4 years ago committed by GitHub
commit 3cec3c8113
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -14,7 +14,7 @@
</a> -->
<h1 align="center" style="margin-bottom:0px">Podgrab</h1>
<p align="center">Current Version - 2021.06.20</p>
<p align="center">Current Version -2021.08.02</p>
<p align="center">
A self-hosted podcast manager to download episodes as soon as they become live

@ -253,6 +253,11 @@
<option :key="index" v-for="index in filter.totalPages" >${index}</option>
</select>
<select name="count" id="countDdl" v-model="filter.count" >
<option :key="index" v-for="index in countOptions" >${index}</option>
</select>
<a
v-if="filter.nextPage"
class="button"
@ -291,8 +296,14 @@ var app = new Vue({
return this.filter.count;
}
},
watch:{
count(newValue,oldValue){
if(newValue===oldValue){
return;
}
this.getData();
},
page(newPage,oldPage){
if(newPage==oldPage){
return;
@ -310,9 +321,6 @@ var app = new Vue({
this.getData()
},
count(current,old){
this.getData()
},
showFilters(current,old){
if(localStorage){
@ -355,6 +363,7 @@ var app = new Vue({
mounted(){
if(localStorage && localStorage.episodesFilter){
this.filter=JSON.parse(localStorage.episodesFilter);
}
if(localStorage && localStorage.showFilters){
this.showFilters=JSON.parse(localStorage.showFilters);
@ -401,7 +410,7 @@ var app = new Vue({
this.selectedPlayedStatus=this.playedStatusOptions[i]
}
}
this.filter.page=1;
this.getData()
@ -560,6 +569,7 @@ var app = new Vue({
selectedTags:[],
selectedDownloadStatus:"",
selectedPlayedStatus:"",
countOptions:[10,20,30,40,50,100],
showFilters:localStorage && localStorage.showFilters && JSON.parse(localStorage.showFilters),
{{ $len := len .podcastItems}}

@ -115,6 +115,10 @@
.list .u-full-width{
width: 80%;
}
.paused{
opacity: 50%;
}
</style>
</head>
<body>
@ -172,11 +176,12 @@
/>
</a>
</div>
<div class="columns" v-bind:class="{ten:layout=='list', twelve:layout=='grid'}">
<div class="columns" v-bind:class="{ten:layout=='list', twelve:layout=='grid',paused:podcast.IsPaused}">
<div class="titleContainer">
<a style="text-decoration: none" :href="'/podcasts/'+podcast.ID+'/view'">
<h3 v-if="layout=='list'">${podcast.Title}</h3>
<h5 v-if="layout=='grid'">${podcast.Title}</h5>
<h5 v-if="layout=='grid'">${podcast.Title} </h5>
</a>
</div>
<div class="contentContainer">
@ -250,6 +255,30 @@
>
<i class="fas fa-plus"></i>
</button>
<button
class="button"
title="New episodes for this podcast are not being downloaded automatially. Click to resume download."
v-if="podcast.IsPaused"
@click="togglePause(podcast,false)"
>
<i style="color: greenyellow;" class="fas fa-dot-circle"></i>
</button>
<button
class="button"
title="Click to pause automatic downloading for this podcast."
v-if="!podcast.IsPaused"
@click="togglePause(podcast,true)"
>
<i style="color: red;" class="fas fa-dot-circle"></i>
</button>
<button
class="button"
title="Click to see details."
@click="showDetails(podcast)"
>
<i class="fas fa-info"></i>
</button>
</div>
</div>
</div>
@ -284,14 +313,52 @@
Please feel free to report any issues or request any features on our github page <a target="_blank" href="https://github.com/akhilrex/podgrab">here</a>
</p>
</div>
</template>
<Modal v-model="showDetail">
<table class="table" v-if="detailPodcast">
<tr>
<td>Title</td>
<td>${detailPodcast.Title}</td>
</tr>
<tr>
<td>Author</td>
<td>${ detailPodcast.Author }</td>
</tr>
<tr>
<td>Url</td>
<td> <a target="_blank" :href="detailPodcast.URL">Link</a></td>
</tr>
<tr>
<td>Summary</td>
<td style="word-wrap: break-word;">${ detailPodcast.Summary }</td>
</tr>
<tr>
<td>Added On</td>
<td>${ getFormattedDate(detailPodcast.CreatedAt)}</td>
</tr>
<tr>
<td>Last Episode</td>
<td>${ getFormattedLastEpisodeDate(detailPodcast)}</td>
</tr>
<tr>
<td>Paused</td>
<td> ${ detailPodcast.IsPaused?'Yes':'No' }</td>
</tr>
</table>
</Modal>
</div>
</div>
{{template "scripts"}}
<script src="/webassets/popper.min.js"></script>
<script src="/webassets/tippy-bundle.umd.min.js"></script>
<script src="/webassets/stopword.js"></script>
<script src="/webassets/modal/vue-modal.umd.min.js"></script>
<link rel="stylesheet" href="/webassets/modal/vue-modal.css">
<template id="editTags">
<div class="tags">
<div @click="editTags" style="cursor: pointer;">
@ -317,6 +384,8 @@
</div>
</template>
<script>
Vue.component('Modal', VueModal)
Vue.component('tagger',{
delimiters: ["${", "}"],
data:function(){
@ -456,6 +525,10 @@
},
methods:{
showDetails(podcast){
this.detailPodcast=podcast;
this.showDetail=true;
},
getPodcastImage(item){
return "/podcasts/"+item.ID+"/image"
},
@ -469,6 +542,27 @@
}
this.socket.send(getWebsocketMessage("Enqueue",`{"podcastId":"${id}"}`))
},
togglePause(item,isPaused){
var self=this;
var url= isPaused?`/podcasts/${item.ID}/pause`:`/podcasts/${item.ID}/unpause`;
axios
.get(url)
.then(function (response) {
item.IsPaused=isPaused;
})
.catch(function (error) {
if (error.response && error.response.data && error.response.data.message) {
Vue.toasted.show(error.response.data.message, {
theme: "bubble",
type: "error",
position: "top-right",
duration: 5000,
});
}
})
},
filterPodcasts(){
if(this.filterTag===""){
this.podcasts=this.allPodcasts;
@ -566,6 +660,12 @@
var dt=new Date(Date.parse(podcast.LastEpisode.substr(0,10)));
return dt.toDateString()
},
getFormattedDate(date){
const options={month:"short", day:"numeric", year:"numeric"}
//todo: this is a really dirty hack which needs to be fixed when we work on the episode page
var dt=new Date(Date.parse(date.substr(0,10)));
return dt.toDateString()
},
downloadAllEpisodes(id) { downloadAllEpisodes(id);},
deletePodcast(id){ deletePodcast(id,()=>{
@ -660,6 +760,8 @@
},
data: {
socket:null,
detailPodcast:null,
showDetail:false,
playerExists:false,
isMobile:false,
layoutOptions:["list","grid"],

@ -93,6 +93,10 @@
<input type="checkbox" name="generateNFOFile" v-model="generateNFOFile">
<span class="label-body">Generate NFO files for Podcasts</span>
</label>
<label for="dontDownloadDeletedFromDisk">
<input type="checkbox" name="dontDownloadDeletedFromDisk" v-model="dontDownloadDeletedFromDisk">
<span class="label-body">Don't re-download files deleted from disk.</span>
</label>
<input type="submit" value="Save" class="button">
@ -124,7 +128,7 @@
<table>
<tr>
<td>Current Version</td>
<td> 2021.06.20</td>
<td> 2021.08.02</td>
</tr>
<tr>
<td>Website</td>
@ -140,7 +144,7 @@
</tr>
<tr>
<td>Support the developer</td>
<td><a href="https://www.buymeacoffee.com/akhilrex" target="_blank" rel="noopener noreferrer">Support here</a></td>
<td><a href="https://www.buymeacoffee.com/akhilrex" target="_blank" rel="noopener noreferrer">Buy him a beer!!</a></td>
</tr>
</table>
@ -168,7 +172,8 @@ var app = new Vue({
appendEpisodeNumberToFileName:self.appendEpisodeNumberToFileName,
darkMode:self.darkMode,
downloadEpisodeImages:self.downloadEpisodeImages,
generateNFOFile:self.generateNFOFile
generateNFOFile:self.generateNFOFile,
dontDownloadDeletedFromDisk:self.dontDownloadDeletedFromDisk
})
.then(function(response){
Vue.toasted.show('Settings saved successfully.' ,{
@ -210,7 +215,8 @@ var app = new Vue({
darkMode:{{ .setting.DarkMode }},
originalThemeSetting:{{ .setting.DarkMode }},
downloadEpisodeImages:{{.setting.DownloadEpisodeImages }},
generateNFOFile:{{.setting.GenerateNFOFile }},
generateNFOFile:{{ .setting.GenerateNFOFile }},
dontDownloadDeletedFromDisk:{{ .setting.DontDownloadDeletedFromDisk }},
},
})

@ -29,6 +29,7 @@ type SettingModel struct {
DarkMode bool `form:"darkMode" json:"darkMode" query:"darkMode"`
DownloadEpisodeImages bool `form:"downloadEpisodeImages" json:"downloadEpisodeImages" query:"downloadEpisodeImages"`
GenerateNFOFile bool `form:"generateNFOFile" json:"generateNFOFile" query:"generateNFOFile"`
DontDownloadDeletedFromDisk bool `form:"dontDownloadDeletedFromDisk" json:"dontDownloadDeletedFromDisk" query:"dontDownloadDeletedFromDisk"`
}
var searchOptions = map[string]string{

@ -95,6 +95,35 @@ func GetPodcastById(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
}
}
func PausePodcastById(c *gin.Context) {
var searchByIdQuery SearchByIdQuery
if c.ShouldBindUri(&searchByIdQuery) == nil {
err := service.TogglePodcastPause(searchByIdQuery.Id, true)
if err != nil {
c.JSON(http.StatusBadRequest, err)
return
}
c.JSON(200, gin.H{})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
}
}
func UnpausePodcastById(c *gin.Context) {
var searchByIdQuery SearchByIdQuery
if c.ShouldBindUri(&searchByIdQuery) == nil {
err := service.TogglePodcastPause(searchByIdQuery.Id, false)
if err != nil {
c.JSON(http.StatusBadRequest, err)
return
}
c.JSON(200, gin.H{})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
}
}
func DeletePodcastById(c *gin.Context) {
var searchByIdQuery SearchByIdQuery
@ -417,6 +446,7 @@ func createRss(items []db.PodcastItem, title, description string, c *gin.Context
Enclosure: model.RssItemEnclosure{
URL: fmt.Sprintf("%s://%s/podcastitems/%s/file", url.Scheme, url.Host, item.ID),
Length: fmt.Sprint(item.FileSize),
Type: "audio/mpeg",
},
PubDate: item.PubDate.Format("Mon, 02 Jan 2006 15:04:05 -0700"),
Guid: model.RssItemGuid{
@ -441,7 +471,9 @@ func createRss(items []db.PodcastItem, title, description string, c *gin.Context
Title: title,
Description: description,
Summary: description,
Author: "Podgrab Aggregation",
Link: fmt.Sprintf("%s://%s/allTags", url.Scheme, url.Host),
Image: model.RssItemImage{Text: title, Href: fmt.Sprintf("%s://%s/webassets/blank.png", url.Scheme, url.Host)},
},
}
}
@ -546,7 +578,7 @@ func UpdateSetting(c *gin.Context) {
err = service.UpdateSettings(model.DownloadOnAdd, model.InitialDownloadCount,
model.AutoDownload, model.AppendDateToFileName, model.AppendEpisodeNumberToFileName,
model.DarkMode, model.DownloadEpisodeImages, model.GenerateNFOFile)
model.DarkMode, model.DownloadEpisodeImages, model.GenerateNFOFile, model.DontDownloadDeletedFromDisk)
if err == nil {
c.JSON(200, gin.H{"message": "Success"})

@ -272,6 +272,12 @@ 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 TogglePodcastPauseStatus(podcastId string, isPaused bool) error {
tx := DB.Debug().Exec("update podcasts set is_paused = @isPaused where id = @id", sql.Named("id", podcastId), sql.Named("isPaused", isPaused))
return tx.Error
}
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)
@ -297,6 +303,11 @@ func CreatePodcastItem(podcastItem *PodcastItem) error {
tx := DB.Omit("Podcast").Create(&podcastItem)
return tx.Error
}
func UpdatePodcast(podcast *Podcast) error {
tx := DB.Save(&podcast)
return tx.Error
}
func UpdatePodcastItem(podcastItem *PodcastItem) error {
tx := DB.Omit("Podcast").Save(&podcastItem)
return tx.Error

@ -30,6 +30,8 @@ type Podcast struct {
DownloadedEpisodesSize int64 `gorm:"-"`
DownloadingEpisodesSize int64 `gorm:"-"`
AllEpisodesSize int64 `gorm:"-"`
IsPaused bool `gorm:"default:false"`
}
//PodcastItem is
@ -83,6 +85,7 @@ type Setting struct {
DarkMode bool `gorm:"default:false"`
DownloadEpisodeImages bool `gorm:"default:false"`
GenerateNFOFile bool `gorm:"default:false"`
DontDownloadDeletedFromDisk bool `gorm:"default:false"`
}
type Migration struct {
Base

@ -5,20 +5,22 @@ go 1.15
require (
github.com/TheHippo/podcastindex v1.0.0
github.com/antchfx/xmlquery v1.3.3
github.com/chris-ramon/douceur v0.2.0 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/gin-contrib/location v0.0.2
github.com/gin-gonic/gin v1.6.3
github.com/gin-gonic/gin v1.7.2
github.com/gobeam/stringy v0.0.0-20200717095810-8a3637503f62
github.com/gorilla/websocket v1.4.2
github.com/grokify/html-strip-tags-go v0.0.0-20200923094847-079d207a09f1
github.com/jasonlvhit/gocron v0.0.1
github.com/joho/godotenv v1.3.0
github.com/microcosm-cc/bluemonday v1.0.4
github.com/microcosm-cc/bluemonday v1.0.15
github.com/satori/go.uuid v1.2.0
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.16.0
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c
golang.org/x/net v0.0.0-20210614182718-04defd469f4e
golang.org/x/text v0.3.6 // indirect
gorm.io/driver/sqlite v1.1.3
gorm.io/gorm v1.20.2
)

@ -7,6 +7,7 @@ github.com/antchfx/xmlquery v1.3.3 h1:HYmadPG0uz8CySdL68rB4DCLKXz2PurCjS3mnkVF4C
github.com/antchfx/xmlquery v1.3.3/go.mod h1:64w0Xesg2sTaawIdNqMB+7qaW/bSqkQm+ssPaCMWNnc=
github.com/antchfx/xpath v1.1.10 h1:cJ0pOvEdN/WvYXxvRrzQH9x5QWKpzHacYO8qzCcDYAg=
github.com/antchfx/xpath v1.1.10/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU=
@ -25,6 +26,8 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA=
github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
@ -32,6 +35,8 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-redis/redis v6.15.5+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/gobeam/stringy v0.0.0-20200717095810-8a3637503f62 h1:5yOhT/D6x5qqfcRnR98bvpGlduR4Shkj8Jat+SalYpQ=
@ -79,6 +84,8 @@ github.com/mattn/go-sqlite3 v1.14.3 h1:j7a/xn1U6TKA/PHHxqZuzh64CdtRc7rU9M+AvkOl5
github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
github.com/microcosm-cc/bluemonday v1.0.4 h1:p0L+CTpo/PLFdkoPcJemLXG+fpMD7pYOoDEq1axMbGg=
github.com/microcosm-cc/bluemonday v1.0.4/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w=
github.com/microcosm-cc/bluemonday v1.0.15 h1:J4uN+qPng9rvkBZBoBb8YGR+ijuklIMpSOZZLjYpbeY=
github.com/microcosm-cc/bluemonday v1.0.15/go.mod h1:ZLvAzeakRwrGnzQEvstVzVt3ZpqOF2+sdFr0Om+ce30=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
@ -131,6 +138,8 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c h1:dk0ukUIHmGHqASjP0iue2261isepFCC6XRCSd1nHgDw=
golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c/go.mod h1:iQL9McJNjoIa5mjH6nYTCTZXUN6RP+XW3eib7Ya3XcI=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -142,9 +151,14 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20u
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=

@ -5,6 +5,7 @@ import (
"html/template"
"log"
"os"
"path"
"strconv"
"time"
@ -142,8 +143,11 @@ func main() {
}
dataPath := os.Getenv("DATA")
backupPath := path.Join(os.Getenv("CONFIG"), "backups")
router.Static("/webassets", "./webassets")
router.Static("/assets", dataPath)
router.Static(backupPath, backupPath)
router.POST("/podcasts", controllers.AddPodcast)
router.GET("/podcasts", controllers.GetAllPodcasts)
router.GET("/podcasts/:id", controllers.GetPodcastById)
@ -153,6 +157,8 @@ func main() {
router.GET("/podcasts/:id/download", controllers.DownloadAllEpisodesByPodcastId)
router.DELETE("/podcasts/:id/items", controllers.DeletePodcastEpisodesById)
router.DELETE("/podcasts/:id/podcast", controllers.DeleteOnlyPodcastById)
router.GET("/podcasts/:id/pause", controllers.PausePodcastById)
router.GET("/podcasts/:id/unpause", controllers.UnpausePodcastById)
router.GET("/podcastitems", controllers.GetAllPodcastItems)
router.GET("/podcastitems/:id", controllers.GetPodcastItemById)

@ -18,14 +18,16 @@ type RssPodcastData struct {
Channel RssChannel `xml:"channel"`
}
type RssChannel struct {
Text string `xml:",chardata"`
Language string `xml:"language"`
Link string `xml:"link"`
Title string `xml:"title"`
Description string `xml:"description"`
Type string `xml:"type"`
Summary string `xml:"summary"`
Item []RssItem `xml:"item"`
Text string `xml:",chardata"`
Language string `xml:"language"`
Link string `xml:"link"`
Title string `xml:"title"`
Description string `xml:"description"`
Type string `xml:"type"`
Summary string `xml:"summary"`
Image RssItemImage `xml:"image"`
Item []RssItem `xml:"item"`
Author string `xml:"author"`
}
type RssItem struct {
Text string `xml:",chardata"`

@ -295,10 +295,14 @@ func AddPodcastItems(podcast *db.Podcast, newPodcast bool) error {
var downloadStatus db.DownloadStatus
if setting.AutoDownload {
if i < limit {
if !newPodcast {
downloadStatus = db.NotDownloaded
} else {
downloadStatus = db.Deleted
if i < limit {
downloadStatus = db.NotDownloaded
} else {
downloadStatus = db.Deleted
}
}
} else {
downloadStatus = db.Deleted
@ -308,6 +312,10 @@ func AddPodcastItems(podcast *db.Podcast, newPodcast bool) error {
downloadStatus = db.Deleted
}
if podcast.IsPaused {
downloadStatus = db.Deleted
}
summary := strip.StripTags(obj.Summary)
if summary == "" {
summary = strip.StripTags(obj.Description)
@ -528,6 +536,7 @@ func DownloadMissingEpisodes() error {
}
func CheckMissingFiles() error {
data, err := db.GetAllPodcastItemsAlreadyDownloaded()
setting := db.GetOrCreateSetting()
//fmt.Println("Processing episodes: ", strconv.Itoa(len(*data)))
if err != nil {
@ -536,7 +545,11 @@ func CheckMissingFiles() error {
for _, item := range *data {
fileExists := FileExists(item.DownloadPath)
if !fileExists {
SetPodcastItemAsNotDownloaded(item.ID, db.NotDownloaded)
if setting.DontDownloadDeletedFromDisk {
SetPodcastItemAsNotDownloaded(item.ID, db.Deleted)
} else {
SetPodcastItemAsNotDownloaded(item.ID, db.NotDownloaded)
}
}
}
return nil
@ -732,7 +745,7 @@ func GetSearchFromPodcastIndex(pod *podcastindex.Podcast) *model.CommonSearchRes
return p
}
func UpdateSettings(downloadOnAdd bool, initialDownloadCount int, autoDownload bool, appendDateToFileName bool, appendEpisodeNumberToFileName bool, darkMode bool, downloadEpisodeImages bool, generateNFOFile bool) error {
func UpdateSettings(downloadOnAdd bool, initialDownloadCount int, autoDownload bool, appendDateToFileName bool, appendEpisodeNumberToFileName bool, darkMode bool, downloadEpisodeImages bool, generateNFOFile bool, dontDownloadDeletedFromDisk bool) error {
setting := db.GetOrCreateSetting()
setting.AutoDownload = autoDownload
@ -743,6 +756,7 @@ func UpdateSettings(downloadOnAdd bool, initialDownloadCount int, autoDownload b
setting.DarkMode = darkMode
setting.DownloadEpisodeImages = downloadEpisodeImages
setting.GenerateNFOFile = generateNFOFile
setting.DontDownloadDeletedFromDisk = dontDownloadDeletedFromDisk
return db.UpdateSettings(setting)
}
@ -769,3 +783,13 @@ func AddTag(label, description string) (db.Tag, error) {
return *tag, &model.TagAlreadyExistsError{Label: label}
}
func TogglePodcastPause(id string, isPaused bool) error {
var podcast db.Podcast
err := db.GetPodcastById(id, &podcast)
if err != nil {
return err
}
return db.TogglePodcastPauseStatus(id, isPaused)
}

@ -0,0 +1 @@
.vm-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background-color:rgba(0,0,0,0.5)}.vm-wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow-x:hidden;overflow-y:auto;outline:0}.vm{position:relative;margin:0px auto;width:calc(100% - 20px);min-width:110px;max-width:500px;background-color:#fff;top:30px;cursor:default;box-shadow:0 5px 15px rgba(0,0,0,0.5)}.vm-titlebar{padding:10px 15px 10px 15px;overflow:auto;border-bottom:1px solid #e5e5e5}.vm-title{margin-top:2px;margin-bottom:0px;display:inline-block;font-size:18px;font-weight:normal}.vm-btn-close{color:#ccc;padding:0px;cursor:pointer;background:0 0;border:0;float:right;font-size:24px;line-height:1em}.vm-btn-close:before{content:'×';font-family:Arial}.vm-btn-close:hover,.vm-btn-close:focus,.vm-btn-close:focus:hover{color:#bbb;border-color:transparent;background-color:transparent}.vm-content{padding:10px 15px 15px 15px}.vm-content .full-hr{width:auto;border:0;border-top:1px solid #e5e5e5;margin-top:15px;margin-bottom:15px;margin-left:-14px;margin-right:-14px}.vm-fadeIn{animation-name:vm-fadeIn}@keyframes vm-fadeIn{0%{opacity:0}100%{opacity:1}}.vm-fadeOut{animation-name:vm-fadeOut}@keyframes vm-fadeOut{0%{opacity:1}100%{opacity:0}}.vm-fadeIn,.vm-fadeOut{animation-duration:0.25s;animation-fill-mode:both}

File diff suppressed because one or more lines are too long

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