2022-02-19 15:47:25 +00:00
|
|
|
package scrobble
|
|
|
|
|
|
|
|
import (
|
2022-02-19 22:00:56 +00:00
|
|
|
"database/sql"
|
|
|
|
"encoding/json"
|
2022-02-19 15:47:25 +00:00
|
|
|
"fmt"
|
2022-02-20 15:07:29 +00:00
|
|
|
"log"
|
2022-02-19 15:47:25 +00:00
|
|
|
"net/url"
|
2022-02-19 22:00:56 +00:00
|
|
|
"time"
|
2022-02-19 15:47:25 +00:00
|
|
|
|
2022-02-19 22:00:56 +00:00
|
|
|
"git.jamesravey.me/ravenscroftj/indiescrobble/config"
|
2022-02-19 15:47:25 +00:00
|
|
|
"git.jamesravey.me/ravenscroftj/indiescrobble/models"
|
|
|
|
"git.jamesravey.me/ravenscroftj/indiescrobble/services/micropub"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Scrobbler struct {
|
|
|
|
db *gorm.DB
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewScrobbler(db *gorm.DB) *Scrobbler{
|
|
|
|
return &Scrobbler{db:db}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Scrobbler) ValidateType(form *url.Values) error {
|
|
|
|
|
|
|
|
scrobbleType := form.Get("type")
|
|
|
|
if _, ok := ScrobbleTypeNames[scrobbleType]; !ok{
|
2022-02-19 22:00:56 +00:00
|
|
|
return fmt.Errorf("unknown/invalid scrobble type %v", scrobbleType)
|
2022-02-19 15:47:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Scrobbler) GetItemByID(form *url.Values) (ScrobbleMetaRecord, error) {
|
|
|
|
|
|
|
|
if err := s.ValidateType(form); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
searchEngine := NewSearchProvider(form.Get("type"), s.db)
|
|
|
|
|
|
|
|
item, err := searchEngine.SearchProvider.GetItem(form.Get("item"))
|
|
|
|
|
|
|
|
if err != nil{
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return item, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Scrobbler) Search(form *url.Values) ([]ScrobbleMetaRecord, error) {
|
|
|
|
|
|
|
|
if err := s.ValidateType(form); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
searchEngine := NewSearchProvider(form.Get("type"), s.db)
|
|
|
|
|
|
|
|
query := form.Get("q")
|
|
|
|
|
|
|
|
return searchEngine.SearchProvider.Search(query)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Scrobbler) GetSearchEngineNameForType(scrobbleType string) string {
|
|
|
|
return NewSearchProvider(scrobbleType, s.db).SearchProvider.GetName()
|
|
|
|
}
|
|
|
|
|
2022-02-20 15:07:29 +00:00
|
|
|
func (s *Scrobbler) BuildMicroPubPayload(post *models.Post) ([]byte, error) {
|
2022-02-19 22:00:56 +00:00
|
|
|
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}
|
|
|
|
}
|
|
|
|
|
2022-02-20 15:07:29 +00:00
|
|
|
properties["summary"] = []string{s.GenerateSummary(post)}
|
2022-02-19 22:00:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
2022-02-20 15:07:29 +00:00
|
|
|
return json.MarshalIndent(postObj, ""," ")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Scrobbler) GenerateSummary(post *models.Post) string{
|
|
|
|
return fmt.Sprintf("%v %v %v and gave it %v/5",
|
|
|
|
ScrobbleTypeEmojis[post.PostType],
|
|
|
|
ScrobbleTypeVerbs[post.PostType],
|
|
|
|
post.MediaItem.DisplayName.String,
|
|
|
|
post.Rating.String)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Scrobbler) Preview(form *url.Values) (*models.Post, error) {
|
|
|
|
|
|
|
|
if err := s.ValidateType(form); err != nil{
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
item := models.MediaItem{}
|
|
|
|
result := s.db.Where(&models.MediaItem{MediaID: form.Get("item")}).First(&item)
|
|
|
|
|
|
|
|
if result.Error != nil{
|
|
|
|
return nil, result.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
post := models.Post{
|
|
|
|
MediaItem: item,
|
|
|
|
PostType: form.Get("type"),
|
|
|
|
Content: sql.NullString{String: form.Get("content"), Valid: true},
|
|
|
|
Rating: sql.NullString{String: form.Get("rating"), Valid: true},
|
|
|
|
}
|
|
|
|
|
|
|
|
time, err := time.Parse(config.BROWSER_TIME_FORMAT, form.Get("when"))
|
|
|
|
|
|
|
|
if err == nil{
|
|
|
|
post.ScrobbledAt = sql.NullTime{Time: time, Valid: true}
|
|
|
|
}else{
|
|
|
|
log.Printf("Failed to parse time %v because %v",form.Get("when"), err )
|
|
|
|
}
|
|
|
|
|
|
|
|
return &post, nil
|
2022-02-19 22:00:56 +00:00
|
|
|
}
|
|
|
|
|
2022-02-19 15:47:25 +00:00
|
|
|
func (s *Scrobbler) Scrobble(form *url.Values, currentUser *models.BaseUser) (*models.Post, error) {
|
|
|
|
|
|
|
|
if err := s.ValidateType(form); err != nil{
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
item := models.MediaItem{}
|
|
|
|
result := s.db.Where(&models.MediaItem{MediaID: form.Get("item")}).First(&item)
|
|
|
|
|
|
|
|
if result.Error != nil{
|
2022-02-20 15:07:29 +00:00
|
|
|
log.Printf("Error finding media item with ID %v in db: %v\n", form.Get("item"), result.Error)
|
2022-02-19 15:47:25 +00:00
|
|
|
return nil, result.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
discovery := micropub.MicropubDiscoveryService{}
|
|
|
|
|
|
|
|
|
2022-02-19 22:00:56 +00:00
|
|
|
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},
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
time, err := time.Parse(config.BROWSER_TIME_FORMAT, form.Get("when"))
|
|
|
|
|
|
|
|
if err == nil{
|
|
|
|
post.ScrobbledAt = sql.NullTime{Time: time, Valid: true}
|
|
|
|
}else{
|
2022-02-20 15:07:29 +00:00
|
|
|
log.Printf("Failed to parse time %v because %v",form.Get("when"), err )
|
2022-02-19 22:00:56 +00:00
|
|
|
}
|
|
|
|
|
2022-02-20 15:07:29 +00:00
|
|
|
postBody, err := s.BuildMicroPubPayload(&post)
|
2022-02-19 15:47:25 +00:00
|
|
|
|
2022-02-19 22:00:56 +00:00
|
|
|
|
|
|
|
if err != nil{
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-02-20 15:07:29 +00:00
|
|
|
log.Printf("Send post payload to %v\n", currentUser.Me)
|
2022-02-19 22:00:56 +00:00
|
|
|
|
|
|
|
resp, err := discovery.SubmitMicropub(currentUser, postBody)
|
|
|
|
|
|
|
|
if err != nil{
|
2022-02-20 15:07:29 +00:00
|
|
|
log.Printf("Error creating user post: %v\n", err)
|
2022-02-19 22:00:56 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
loc, err := resp.Location()
|
|
|
|
|
|
|
|
if err != nil{
|
2022-02-20 15:07:29 +00:00
|
|
|
log.Printf("Error getting Location header from user micropub endpoint: %v\n", err)
|
2022-02-19 22:00:56 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
post.URL = loc.String()
|
|
|
|
result = s.db.Create(&post)
|
|
|
|
|
|
|
|
if result.Error != nil{
|
2022-02-20 15:07:29 +00:00
|
|
|
log.Printf("Error creating post in database: %v\n", result.Error)
|
2022-02-19 22:00:56 +00:00
|
|
|
return nil, result.Error
|
|
|
|
}
|
2022-02-19 15:47:25 +00:00
|
|
|
|
|
|
|
return &post, nil
|
2022-02-19 22:00:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|