0.2.58 - Requests module
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// MediaRequest is one viewer's ask, as recorded. It carries no status: see the schema
|
||||
// comment on media_requests for why the state is derived per read rather than stored.
|
||||
type MediaRequest struct {
|
||||
MediaType string `json:"mediaType"`
|
||||
ForeignID int `json:"foreignId"`
|
||||
Title string `json:"title"`
|
||||
Year int `json:"year,omitempty"`
|
||||
PosterURL string `json:"posterUrl,omitempty"`
|
||||
RequestedAt time.Time `json:"requestedAt"`
|
||||
}
|
||||
|
||||
// MediaRequestLimit caps what one viewer's page will read back. A household that has been
|
||||
// asking for things for two years should not turn the page into an unbounded query, and
|
||||
// nobody scrolls past the most recent hundred by remote.
|
||||
const MediaRequestLimit = 100
|
||||
|
||||
// SaveMediaRequest records an ask, or refreshes one already held.
|
||||
//
|
||||
// The repeat is deliberately an update rather than a no-op: asking again is how somebody
|
||||
// says they still want it, and the page is ordered by when they asked.
|
||||
func (s *Store) SaveMediaRequest(ctx context.Context, userID string, req MediaRequest) error {
|
||||
userID = strings.TrimSpace(userID)
|
||||
if userID == "" || req.ForeignID <= 0 {
|
||||
return fmt.Errorf("store: media request needs a user and a foreign id")
|
||||
}
|
||||
_, err := s.pool.Exec(ctx, `
|
||||
INSERT INTO media_requests
|
||||
(emby_user_id, media_type, foreign_id, title, year, poster_url, requested_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, now())
|
||||
ON CONFLICT (emby_user_id, media_type, foreign_id) DO UPDATE
|
||||
SET title = EXCLUDED.title,
|
||||
year = EXCLUDED.year,
|
||||
poster_url = EXCLUDED.poster_url,
|
||||
requested_at = now()`,
|
||||
userID, req.MediaType, req.ForeignID, req.Title, req.Year, req.PosterURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("store: save media request: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MediaRequests returns one viewer's asks, most recent first.
|
||||
func (s *Store) MediaRequests(ctx context.Context, userID string) ([]MediaRequest, error) {
|
||||
rows, err := s.pool.Query(ctx, `
|
||||
SELECT media_type, foreign_id, title, year, poster_url, requested_at
|
||||
FROM media_requests
|
||||
WHERE emby_user_id = $1
|
||||
ORDER BY requested_at DESC
|
||||
LIMIT $2`, strings.TrimSpace(userID), MediaRequestLimit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("store: read media requests: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
requests := []MediaRequest{}
|
||||
for rows.Next() {
|
||||
var req MediaRequest
|
||||
if err := rows.Scan(
|
||||
&req.MediaType, &req.ForeignID, &req.Title, &req.Year, &req.PosterURL, &req.RequestedAt,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("store: scan media request: %w", err)
|
||||
}
|
||||
requests = append(requests, req)
|
||||
}
|
||||
return requests, rows.Err()
|
||||
}
|
||||
|
||||
// DeleteMediaRequest removes a viewer's ask from their own page.
|
||||
//
|
||||
// It deliberately does not touch Radarr or Sonarr. The title may well have been downloaded
|
||||
// by now, and other people may have asked for it too — this only says the viewer no longer
|
||||
// wants it listed among theirs.
|
||||
func (s *Store) DeleteMediaRequest(
|
||||
ctx context.Context, userID, mediaType string, foreignID int,
|
||||
) error {
|
||||
_, err := s.pool.Exec(ctx, `
|
||||
DELETE FROM media_requests
|
||||
WHERE emby_user_id = $1 AND media_type = $2 AND foreign_id = $3`,
|
||||
strings.TrimSpace(userID), mediaType, foreignID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("store: delete media request: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user