implemented scrobbling of movies

This commit is contained in:
James Ravenscroft 2022-02-19 22:00:56 +00:00
parent 3b7d937df5
commit 781c003bad
7 changed files with 142 additions and 53 deletions

View File

@ -42,6 +42,8 @@ func NewRouter(db *gorm.DB) *gin.Engine {
authed.POST("/scrobble/preview", scrobbleController.PreviewScrobble)
authed.POST("/scrobble/do", scrobbleController.DoScrobble)
// v1 := router.Group("v1")
// {
// userGroup := v1.Group("user")

View File

@ -29,8 +29,7 @@ func Init() {
log.Fatalf("%v\n", err)
}
db.AutoMigrate(&models.User{})
db.AutoMigrate(&models.Post{})
db.AutoMigrate(&models.User{}, &models.Post{}, &models.MediaItem{})
r := NewRouter(db)
r.LoadHTMLGlob("templates/*.tmpl")

View File

@ -159,64 +159,27 @@ func (m *MicropubDiscoveryService) Discover(me string, authToken string) (*Micro
}
/* Send micropub to endpoint */
func (m *MicropubDiscoveryService) SubmitScrobble(currentUser *models.BaseUser, post *models.Post) (error) {
func (m *MicropubDiscoveryService) SubmitMicropub(currentUser *models.BaseUser, payload []byte) (*http.Response, error) {
endpoint, err := m.findMicropubEndpoint(currentUser.Me)
if err != nil{
return err
return nil, err
}
postObj := make(map[string]interface{})
postObj["type"] = []string{"h-entry"}
postObj["visibility"] = []string{"public"}
properties := make(map[string]interface{})
properties["media-type"] = []string{post.PostType}
properties["media-item-id"] = []string{post.MediaItem.MediaID}
properties["media-item-url"] = []string{post.MediaItem.CanonicalURL.String}
properties["indiescrobble-id"] = post.MediaItem.ID
if post.MediaItem.ThumbnailURL.Valid{
properties["photo"] = []string{post.MediaItem.ThumbnailURL.String}
}
if post.Content.Valid{
postObj["content"] = post.Content.String
}
postObj["properties"] = properties
bodyBytes, err := json.Marshal(postObj)
if err != nil{
return err
}
body := bytes.NewReader(bodyBytes)
body := bytes.NewReader(payload)
req, err := http.NewRequest("POST", endpoint, body)
if err != nil{
return err
return nil, err
}
req.Header.Add("User-Agent", USER_AGENT_STRING)
req.Header.Add("Authorization", fmt.Sprintf("Bearer %v", currentUser.Token))
req.Header.Add("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
return http.DefaultClient.Do(req)
if err != nil{
return err
}
loc, err := resp.Location()
if err != nil{
return err
}
post.URL = loc.String()
return nil
}

View File

@ -1,9 +1,13 @@
package scrobble
import (
"database/sql"
"encoding/json"
"fmt"
"net/url"
"time"
"git.jamesravey.me/ravenscroftj/indiescrobble/config"
"git.jamesravey.me/ravenscroftj/indiescrobble/models"
"git.jamesravey.me/ravenscroftj/indiescrobble/services/micropub"
"gorm.io/gorm"
@ -21,7 +25,7 @@ func (s *Scrobbler) ValidateType(form *url.Values) error {
scrobbleType := form.Get("type")
if _, ok := ScrobbleTypeNames[scrobbleType]; !ok{
return fmt.Errorf("Unknown/invalid scrobble type %v", scrobbleType)
return fmt.Errorf("unknown/invalid scrobble type %v", scrobbleType)
}
return nil
@ -63,6 +67,47 @@ func (s *Scrobbler) GetSearchEngineNameForType(scrobbleType string) string {
return NewSearchProvider(scrobbleType, s.db).SearchProvider.GetName()
}
func (s *Scrobbler) buildMicroPubPayload(post *models.Post) ([]byte, error) {
postObj := make(map[string]interface{})
postObj["type"] = []string{"h-entry"}
postObj["visibility"] = []string{"public"}
properties := make(map[string]interface{})
if post.MediaItem.ThumbnailURL.Valid{
properties["photo"] = []string{post.MediaItem.ThumbnailURL.String}
}
if post.Rating.Valid{
properties["rating"] = []string{post.Rating.String}
}
properties["summary"] = fmt.Sprintf("%v %v and gave it %v/5", ScrobbleTypeVerbs[post.PostType], post.MediaItem.DisplayName.String, post.Rating.String)
citationProps := make(map[string]interface{})
citationProps["name"] = []string{post.MediaItem.DisplayName.String}
citationProps["uid"] = []string{post.MediaItem.MediaID}
citationProps["url"] = []string{post.MediaItem.CanonicalURL.String}
citationProps["indiescrobble-id"] = post.MediaItem.ID
citation := make(map[string]interface{})
citation["type"] = []string{"h-cite"}
citation["properties"] = citationProps
// use the appropriate citation property e.g. read-of or watch-of
properties[ScrobbleCitationProperties[post.PostType]] = citation
if post.Content.Valid{
properties["content"] = []string{post.Content.String}
}
postObj["properties"] = properties
return json.Marshal(postObj)
}
func (s *Scrobbler) Scrobble(form *url.Values, currentUser *models.BaseUser) (*models.Post, error) {
if err := s.ValidateType(form); err != nil{
@ -79,12 +124,53 @@ func (s *Scrobbler) Scrobble(form *url.Values, currentUser *models.BaseUser) (*m
discovery := micropub.MicropubDiscoveryService{}
post := models.Post{
MediaItem: item,
User: *currentUser.UserRecord,
PostType: form.Get("type"),
Content: sql.NullString{String: form.Get("content"), Valid: true},
Rating: sql.NullString{String: form.Get("rating"), Valid: true},
}
mediaItem := models.MediaItem{}
post := models.Post{MediaItem: mediaItem, User: *currentUser.UserRecord, PostType: form.Get("type") }
time, err := time.Parse(config.BROWSER_TIME_FORMAT, form.Get("when"))
discovery.SubmitScrobble(currentUser, &post)
if err == nil{
post.ScrobbledAt = sql.NullTime{Time: time, Valid: true}
}else{
fmt.Errorf("Failed to parse time %v because %v",form.Get("when"), err )
}
postBody, err := s.buildMicroPubPayload(&post)
fmt.Printf("Post body: %v\n", string(postBody))
if err != nil{
return nil, err
}
resp, err := discovery.SubmitMicropub(currentUser, postBody)
if err != nil{
return nil, err
}
loc, err := resp.Location()
if err != nil{
return nil, err
}
post.URL = loc.String()
result = s.db.Create(&post)
if result.Error != nil{
return nil, result.Error
}
return &post, nil
}

View File

@ -14,6 +14,13 @@ var ScrobbleTypeNames = map[string]string {
"read": "📖 Read",
};
var ScrobbleTypeVerbs = map[string]string {
"scrobble" : "listened to",
"tv" : "watched",
"movie": "watched",
"read": "read",
};
var ScrobblePlaceholders = map[string]string {
"scrobble" : "Jump Van Halen",
"tv" : "Schitt's Creek",
@ -21,6 +28,13 @@ var ScrobblePlaceholders = map[string]string {
"read": "Three Body Problem Cixin Liu",
};
var ScrobbleCitationProperties = map[string]string {
"scrobble" : "listen-of",
"tv" : "watch-of",
"movie": "watch-of",
"read": "read-of",
};
type ScrobbleMetaRecord interface{
GetID() string

View File

@ -13,7 +13,7 @@
{{end}}
<form method="POST" action="/scrobble/preview">
<form method="POST" action="/scrobble/do">
<p><a href="/">Add A Post</a> &gt; <a href="/scrobble?type={{ .scrobbleType }}">Add {{ .scrobbleTypeName }}</a> &gt; {{.item.GetDisplayName}}</p>
@ -50,6 +50,7 @@
</div>
<input type="hidden" name="item" value="{{.item.GetID}}"/>
<input type="hidden" name="type" value="{{ .scrobbleType }}"/>
</form>

24
templates/scrobbled.tmpl Normal file
View File

@ -0,0 +1,24 @@
{{ define "scrobbled.tmpl" }}
<!DOCTYPE html>
<html lang="en">
{{ template "head.tmpl" . }}
<body>
{{ template "header.tmpl" . }}
<main>
{{ $scrobbleType := .scrobbleType }}
{{ if .user }}
Logged in as {{.user.Me}} <a href="/logout"><button>Log Out</button></a>
{{end}}
<p><a href="/">Add A Post</a> &gt; <a href="/scrobble?type={{ .scrobbleType }}">Add {{ .scrobbleTypeName }}</a> &gt; {{.post.MediaItem.DisplayName.String}}</p>
<h3>Post Complete: <a href="{{.post.URL}}">{{.post.URL}}</a></h3>
</main>
{{ template "footer.tmpl" . }}
</body>
</html>
{{end}}