first commit

pull/24/head
Akhil Gupta 4 years ago
commit 2d8f34ace2

18
.gitignore vendored

@ -0,0 +1,18 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
*.db
# Dependency directories (remove the comment below to include it)
# vendor/
assets/*
keys/*

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PodGrab</title>
</head>
<body>
<h1>{{ .title }}</h1>
<ol>
{{range .podcasts}}
<li>{{.Title}}
</li> {{end}}
</ol>
</body>
</html>

@ -0,0 +1,95 @@
package controllers
import (
"fmt"
"net/http"
"github.com/akhilrex/podgrab/service"
"github.com/akhilrex/podgrab/db"
"github.com/gin-gonic/gin"
)
type SearchQuery struct {
Q string `binding:"required" form:"q"`
Type string `form:"type"`
}
type SearchByIdQuery struct {
Id string `binding:"required" uri:"id" json:"id" form:"id"`
}
type AddPodcastData struct {
url string `binding:"required" form:"url" json:"url"`
}
func GetAllPodcasts(c *gin.Context) {
var podcasts []db.Podcast
db.GetAllPodcasts(&podcasts)
c.JSON(200, podcasts)
}
func GetPodcastById(c *gin.Context) {
var searchByIdQuery SearchByIdQuery
if c.ShouldBindUri(&searchByIdQuery) == nil {
var podcast db.Podcast
err := db.GetPodcastById(searchByIdQuery.Id, &podcast)
fmt.Println(err)
c.JSON(200, podcast)
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
}
}
func GetPodcastItemsByPodcastId(c *gin.Context) {
var searchByIdQuery SearchByIdQuery
if c.ShouldBindUri(&searchByIdQuery) == nil {
var podcastItems []db.PodcastItem
err := db.GetAllPodcastItemsByPodcastId(searchByIdQuery.Id, &podcastItems)
fmt.Println(err)
c.JSON(200, podcastItems)
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
}
}
func GetAllPodcastItems(c *gin.Context) {
var podcasts []db.PodcastItem
db.GetAllPodcastItems(&podcasts)
c.JSON(200, podcasts)
}
func GetPodcastItemById(c *gin.Context) {
var searchByIdQuery SearchByIdQuery
if c.ShouldBindUri(&searchByIdQuery) == nil {
var podcast db.PodcastItem
err := db.GetPodcastItemById(searchByIdQuery.Id, &podcast)
fmt.Println(err)
c.JSON(200, podcast)
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
}
}
func AddPodcast(c *gin.Context) {
var addPodcastData AddPodcastData
err := c.ShouldBindJSON(&addPodcastData)
if err == nil {
service.AddPodcast(addPodcastData.url)
// fmt.Println(time.Unix(addPodcastData.StartDate, 0))
c.JSON(200, addPodcastData)
} else {
fmt.Println(err.Error())
c.JSON(http.StatusBadRequest, err)
}
}

@ -0,0 +1,22 @@
package db
import (
"time"
uuid "github.com/satori/go.uuid"
"gorm.io/gorm"
)
//Base is
type Base struct {
ID string `sql:"type:uuid;primary_key"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time `gorm:"index"`
}
//BeforeCreate
func (base *Base) BeforeCreate(tx *gorm.DB) error {
tx.Statement.SetColumn("ID", uuid.NewV4().String())
return nil
}

@ -0,0 +1,39 @@
package db
import (
"fmt"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
//DB is
var DB *gorm.DB
//Init is used to Initialize Database
func Init() (*gorm.DB, error) {
// github.com/mattn/go-sqlite3
db, err := gorm.Open(sqlite.Open("podgrab.db"), &gorm.Config{})
if err != nil {
fmt.Println("db err: ", err)
return nil, err
}
localDB, _ := db.DB()
localDB.SetMaxIdleConns(10)
//db.LogMode(true)
DB = db
return DB, nil
}
//Migrate Database
func Migrate() {
DB.AutoMigrate(&Podcast{}, &PodcastItem{})
}
// Using this function to get a connection, you can create your connection pool here.
func GetDB() *gorm.DB {
return DB
}

@ -0,0 +1,70 @@
package db
import (
"time"
"gorm.io/gorm/clause"
)
func GetPodcastByURL(url string, podcast *Podcast) error {
result := DB.Preload(clause.Associations).Where(&Podcast{URL: url}).First(&podcast)
return result.Error
}
func GetAllPodcasts(podcasts *[]Podcast) error {
result := DB.Preload("PodcastItems").Find(&podcasts)
return result.Error
}
func GetAllPodcastItems(podcasts *[]PodcastItem) error {
result := DB.Preload("Podcast").Find(&podcasts)
return result.Error
}
func GetPodcastById(id string, podcast *Podcast) error {
result := DB.Preload(clause.Associations).First(&podcast, "id=?", id)
return result.Error
}
func GetPodcastItemById(id string, podcastItem *PodcastItem) error {
result := DB.Preload(clause.Associations).First(&podcastItem, "id=?", id)
return result.Error
}
func GetAllPodcastItemsByPodcastId(podcastId string, podcasts *[]PodcastItem) error {
result := DB.Preload(clause.Associations).Where(&PodcastItem{PodcastID: podcastId}).Find(&podcasts)
return result.Error
}
func GetAllPodcastItemsToBeDownloaded() (*[]PodcastItem, error) {
var podcastItems []PodcastItem
result := DB.Preload(clause.Associations).Where(&PodcastItem{DownloadDate: time.Time{}}).Find(&podcastItems)
return &podcastItems, result.Error
}
func GetPodcastItemByPodcastIdAndGUID(podcastId string, guid string, podcastItem *PodcastItem) error {
result := DB.Preload(clause.Associations).Where(&PodcastItem{PodcastID: podcastId, GUID: guid}).First(&podcastItem)
return result.Error
}
func GetPodcastByTitleAndAuthor(title string, author string, podcast *Podcast) error {
result := DB.Preload(clause.Associations).Where(&Podcast{Title: title, Author: author}).First(&podcast)
return result.Error
}
func CreatePodcast(podcast *Podcast) error {
tx := DB.Create(&podcast)
return tx.Error
}
func CreatePodcastItem(podcastItem *PodcastItem) error {
tx := DB.Create(&podcastItem)
return tx.Error
}
func UpdatePodcastItem(podcastItem *PodcastItem) error {
tx := DB.Save(&podcastItem)
return tx.Error
}

@ -0,0 +1,43 @@
package db
import (
"time"
)
//Podcast is
type Podcast struct {
Base
Title string
Summary string `gorm:"type:text"`
Author string
Image string
URL string
PodcastItems []PodcastItem
}
//PodcastItem is
type PodcastItem struct {
Base
PodcastID string
Podcast Podcast
Title string
Summary string `gorm:"type:text"`
EpisodeType string
Duration int
PubDate time.Time
FileURL string
GUID string
DownloadDate time.Time
DownloadPath string
}

@ -0,0 +1,14 @@
module github.com/akhilrex/podgrab
go 1.15
require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/gin-gonic/gin v1.6.3
github.com/gobeam/stringy v0.0.0-20200717095810-8a3637503f62
github.com/jasonlvhit/gocron v0.0.1
github.com/satori/go.uuid v1.2.0
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
gorm.io/driver/sqlite v1.1.3
gorm.io/gorm v1.20.2
)

102
go.sum

@ -0,0 +1,102 @@
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgrijalva/jwt-go v1.0.2 h1:KPldsxuKGsS2FPWsNeg9ZO18aCrGKujPoWXn2yo+KQM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
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/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=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
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-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=
github.com/gobeam/stringy v0.0.0-20200717095810-8a3637503f62/go.mod h1:W3620X9dJHf2FSZF5fRnWekHcHQjwmCz8ZQ2d1qloqE=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jasonlvhit/gocron v0.0.1 h1:qTt5qF3b3srDjeOIR4Le1LfeyvoYzJlYpqvG7tJX5YU=
github.com/jasonlvhit/gocron v0.0.1/go.mod h1:k9a3TV8VcU73XZxfVHCHWMWF9SOqgoku0/QlY2yvlA4=
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/mattn/go-sqlite3 v1.14.3 h1:j7a/xn1U6TKA/PHHxqZuzh64CdtRc7rU9M+AvkOl5bA=
github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
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=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gorm.io/driver/sqlite v1.1.3 h1:BYfdVuZB5He/u9dt4qDpZqiqDJ6KhPqs5QUqsr/Eeuc=
gorm.io/driver/sqlite v1.1.3/go.mod h1:AKDgRWk8lcSQSw+9kxCJnX/yySj8G3rdwYlU57cB45c=
gorm.io/gorm v1.20.1/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.20.2 h1:bZzSEnq7NDGsrd+n3evOOedDrY5oLM5QPlCjZJUK2ro=
gorm.io/gorm v1.20.2/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=

@ -0,0 +1,80 @@
package main
import (
"fmt"
"net/http"
"github.com/akhilrex/podgrab/controllers"
"github.com/akhilrex/podgrab/db"
"github.com/akhilrex/podgrab/service"
"github.com/gin-gonic/gin"
"github.com/jasonlvhit/gocron"
)
func main() {
// os.Remove("./podgrab.db")
var err error
db.DB, err = db.Init()
if err != nil {
fmt.Println("statuse: ", err)
}
db.Migrate()
r := gin.Default()
r.Static("/assets", "./assets")
r.LoadHTMLGlob("client/*")
r.GET("/podcasts", controllers.AddPodcast)
r.POST("/podcasts", controllers.GetAllPodcasts)
r.GET("/podcasts/:id", controllers.GetPodcastById)
r.GET("/podcasts/:id/items", controllers.GetPodcastItemsByPodcastId)
r.GET("/podcastitems", controllers.GetAllPodcastItems)
r.GET("/podcastitems/:id", controllers.GetPodcastItemById)
r.GET("/ping", func(c *gin.Context) {
data, err := service.AddPodcast(c.Query("url"))
go service.AddPodcastItems(&data)
//data, err := db.GetAllPodcastItemsToBeDownloaded()
if err == nil {
c.JSON(200, data)
} else {
c.JSON(http.StatusInternalServerError, err.Error())
}
})
r.GET("/pong", func(c *gin.Context) {
data, err := db.GetAllPodcastItemsToBeDownloaded()
for _, item := range *data {
url, _ := service.Download(item.FileURL, item.Title, item.Podcast.Title)
service.SetPodcastItemAsDownloaded(item.ID, url)
}
if err == nil {
c.JSON(200, data)
} else {
c.JSON(http.StatusInternalServerError, err.Error())
}
})
r.GET("/", func(c *gin.Context) {
//var podcasts []db.Podcast
podcasts := service.GetAllPodcasts()
c.HTML(http.StatusOK, "index.html", gin.H{"title": "Main website", "podcasts": podcasts})
})
go intiCron()
r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
func intiCron() {
gocron.Every(20).Minutes().Do(service.DownloadMissingEpisodes)
gocron.Every(20).Minutes().Do(service.RefreshEpisodes)
<-gocron.Start()
}

@ -0,0 +1,79 @@
package service
import (
"io"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
stringy "github.com/gobeam/stringy"
)
func Download(link string, episodeTitle string, podcastName string) (string, error) {
client := httpClient()
resp, err := client.Get(link)
if err != nil {
return "", err
}
fileName := getFileName(link, episodeTitle, ".mp3")
folder := createIfFoldeDoesntExist(podcastName)
finalPath := path.Join(folder, fileName)
file, err := os.Create(finalPath)
if err != nil {
return "", err
}
defer resp.Body.Close()
_, erra := io.Copy(file, resp.Body)
//fmt.Println(size)
defer file.Close()
if erra != nil {
return "", erra
}
return finalPath, nil
}
func httpClient() *http.Client {
client := http.Client{
CheckRedirect: func(r *http.Request, via []*http.Request) error {
r.URL.Opaque = r.URL.Path
return nil
},
}
return &client
}
func createIfFoldeDoesntExist(folder string) string {
str := stringy.New(folder)
folder = str.RemoveSpecialCharacter()
folderPath := path.Join("./assets/", folder)
if _, err := os.Stat(folderPath); os.IsNotExist(err) {
os.MkdirAll(folderPath, 0755)
}
return folderPath
}
func getFileName(link string, title string, defaultExtension string) string {
fileUrl, err := url.Parse(link)
checkError(err)
parsed := fileUrl.Path
ext := filepath.Ext(parsed)
if len(ext) == 0 {
ext = defaultExtension
}
str := stringy.New(title)
str = stringy.New(str.RemoveSpecialCharacter())
return str.KebabCase().Get() + ext
}
func checkError(err error) {
if err != nil {
panic(err)
}
}

@ -0,0 +1,93 @@
package service
import "encoding/xml"
//PodcastData is
type PodcastData struct {
XMLName xml.Name `xml:"rss"`
Text string `xml:",chardata"`
Itunes string `xml:"itunes,attr"`
Atom string `xml:"atom,attr"`
Media string `xml:"media,attr"`
Psc string `xml:"psc,attr"`
Omny string `xml:"omny,attr"`
Content string `xml:"content,attr"`
Googleplay string `xml:"googleplay,attr"`
Acast string `xml:"acast,attr"`
Version string `xml:"version,attr"`
Channel struct {
Text string `xml:",chardata"`
Language string `xml:"language"`
Link []struct {
Text string `xml:",chardata"`
Rel string `xml:"rel,attr"`
Type string `xml:"type,attr"`
Href string `xml:"href,attr"`
} `xml:"link"`
Title string `xml:"title"`
Description string `xml:"description"`
Type string `xml:"type"`
Summary string `xml:"summary"`
Owner struct {
Text string `xml:",chardata"`
Name string `xml:"name"`
Email string `xml:"email"`
} `xml:"owner"`
Author string `xml:"author"`
Copyright string `xml:"copyright"`
Explicit string `xml:"explicit"`
Category struct {
Text string `xml:",chardata"`
AttrText string `xml:"text,attr"`
Category struct {
Text string `xml:",chardata"`
AttrText string `xml:"text,attr"`
} `xml:"category"`
} `xml:"category"`
Image struct {
Text string `xml:",chardata"`
Href string `xml:"href,attr"`
URL string `xml:"url"`
Title string `xml:"title"`
Link string `xml:"link"`
} `xml:"image"`
Item []struct {
Text string `xml:",chardata"`
Title string `xml:"title"`
Description string `xml:"description"`
Encoded string `xml:"encoded"`
Summary string `xml:"summary"`
EpisodeType string `xml:"episodeType"`
Author string `xml:"author"`
Image struct {
Text string `xml:",chardata"`
Href string `xml:"href,attr"`
} `xml:"image"`
Content []struct {
Text string `xml:",chardata"`
URL string `xml:"url,attr"`
Type string `xml:"type,attr"`
Player struct {
Text string `xml:",chardata"`
URL string `xml:"url,attr"`
} `xml:"player"`
} `xml:"content"`
Guid struct {
Text string `xml:",chardata"`
IsPermaLink string `xml:"isPermaLink,attr"`
} `xml:"guid"`
ClipId string `xml:"clipId"`
PubDate string `xml:"pubDate"`
Duration string `xml:"duration"`
Enclosure struct {
Text string `xml:",chardata"`
URL string `xml:"url,attr"`
Length string `xml:"length,attr"`
Type string `xml:"type,attr"`
} `xml:"enclosure"`
Link string `xml:"link"`
StitcherId string `xml:"stitcherId"`
Episode string `xml:"episode"`
} `xml:"item"`
} `xml:"channel"`
}

@ -0,0 +1,143 @@
package service
import (
"encoding/xml"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"strconv"
"time"
"github.com/akhilrex/podgrab/db"
"gorm.io/gorm"
)
//Fetch is
func FetchURL(url string) (PodcastData, error) {
body := makeQuery(url)
var response PodcastData
err := xml.Unmarshal(body, &response)
return response, err
}
func GetAllPodcasts() *[]db.Podcast {
var podcasts []db.Podcast
db.GetAllPodcasts(&podcasts)
return &podcasts
}
func AddPodcast(url string) (db.Podcast, error) {
data, err := FetchURL(url)
if err != nil {
fmt.Println("Error")
log.Fatal(err)
return db.Podcast{}, err
}
var podcast db.Podcast
err = db.GetPodcastByTitleAndAuthor(data.Channel.Title, data.Channel.Author, &podcast)
if errors.Is(err, gorm.ErrRecordNotFound) {
podcast := db.Podcast{
Title: data.Channel.Title,
Summary: data.Channel.Summary,
Author: data.Channel.Author,
Image: data.Channel.Image.URL,
URL: url,
}
err = db.CreatePodcast(&podcast)
return podcast, err
}
return podcast, err
}
func AddPodcastItems(podcast *db.Podcast) error {
fmt.Println("Creating: " + podcast.ID)
data, err := FetchURL(podcast.URL)
if err != nil {
log.Fatal(err)
return err
}
for i := 0; i < 5; i++ {
obj := data.Channel.Item[i]
var podcastItem db.PodcastItem
err := db.GetPodcastItemByPodcastIdAndGUID(podcast.ID, obj.Guid.Text, &podcastItem)
if errors.Is(err, gorm.ErrRecordNotFound) {
duration, _ := strconv.Atoi(obj.Duration)
pubDate, _ := time.Parse(time.RFC1123Z, obj.PubDate)
podcastItem = db.PodcastItem{
PodcastID: podcast.ID,
Title: obj.Title,
Summary: obj.Summary,
EpisodeType: obj.EpisodeType,
Duration: duration,
PubDate: pubDate,
FileURL: obj.Enclosure.URL,
GUID: obj.Guid.Text,
}
db.CreatePodcastItem(&podcastItem)
}
}
return err
}
func SetPodcastItemAsDownloaded(id string, location string) {
var podcastItem db.PodcastItem
db.GetPodcastItemById(id, &podcastItem)
podcastItem.DownloadDate = time.Now()
podcastItem.DownloadPath = location
db.UpdatePodcastItem(&podcastItem)
}
func DownloadMissingEpisodes() error {
data, err := db.GetAllPodcastItemsToBeDownloaded()
fmt.Println("Processing episodes: %d", len(*data))
if err != nil {
return err
}
for _, item := range *data {
url, _ := Download(item.FileURL, item.Title, item.Podcast.Title)
SetPodcastItemAsDownloaded(item.ID, url)
}
return nil
}
func RefreshEpisodes() error {
var data []db.Podcast
err := db.GetAllPodcasts(&data)
if err != nil {
return err
}
for _, item := range data {
AddPodcastItems(&item)
}
return nil
}
func makeQuery(url string) []byte {
//link := "https://www.goodreads.com/search/index.xml?q=Good%27s+Omens&key=" + "jCmNlIXjz29GoB8wYsrd0w"
//link := "https://www.goodreads.com/search/index.xml?key=jCmNlIXjz29GoB8wYsrd0w&q=Ender%27s+Game"
//fmt.Println(url)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Fatal(err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
fmt.Println("Response status:", resp.Status)
body, err := ioutil.ReadAll(resp.Body)
return body
}
Loading…
Cancel
Save