Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
RoyXiang committed Mar 10, 2022
2 parents a6d4d37 + 5d769e3 commit f6925be
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 81 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ require (
github.com/google/uuid v1.3.0 // indirect
)

replace github.com/jrudio/go-plex-client v0.0.0-20220106065909-9e1d590b99aa => github.com/RoyXiang/go-plex-client v0.0.0-20220305043318-06cfadcf82d7
replace github.com/jrudio/go-plex-client v0.0.0-20220106065909-9e1d590b99aa => github.com/RoyXiang/go-plex-client v0.0.0-20220310030059-ef5991e7e4e2
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/RoyXiang/go-plex-client v0.0.0-20220305043318-06cfadcf82d7 h1:UirnG494f6HbVpTONQeAh3UtG8OWGuaCz6H6ezVkIHE=
github.com/RoyXiang/go-plex-client v0.0.0-20220305043318-06cfadcf82d7/go.mod h1:twidbPLE4eUk3CgDno5uCzpnPRboBTElH+iJrQO7S4w=
github.com/RoyXiang/go-plex-client v0.0.0-20220310030059-ef5991e7e4e2 h1:CV52ZCM7Xjtk3524V31RoX3mRvBHa2PZL6YZDOVb87U=
github.com/RoyXiang/go-plex-client v0.0.0-20220310030059-ef5991e7e4e2/go.mod h1:twidbPLE4eUk3CgDno5uCzpnPRboBTElH+iJrQO7S4w=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
Expand Down
2 changes: 2 additions & 0 deletions handler/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,7 @@ const (
const (
sessionUnplayed sessionStatus = iota
sessionPlaying
sessionPaused
sessionStopped
sessionWatched
)
168 changes: 97 additions & 71 deletions handler/plex.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"time"

"github.com/RoyXiang/plexproxy/common"
"github.com/go-chi/chi/v5/middleware"
"github.com/jrudio/go-plex-client"
"github.com/xanderstrike/plexhooks"
)
Expand Down Expand Up @@ -102,31 +101,52 @@ func (u *plexUser) UnmarshalBinary(data []byte) error {
return json.Unmarshal(data, u)
}

func (c *PlexClient) ServeHTTP(w http.ResponseWriter, r *http.Request) {
path := r.URL.EscapedPath()
switch {
case path == "/video/:/transcode/universal/decision":
if c.disableTranscode {
r = c.disableTranscoding(r)
}
case strings.HasPrefix(path, "/web/"):
if c.redirectWebApp && r.Method == http.MethodGet {
http.Redirect(w, r, "https://app.plex.tv/desktop", http.StatusFound)
return
func (a sessionData) Check(b sessionData) (bool, bool) {
if a.status != b.status {
return true, true
}
if a.progress != b.progress {
if a.status == sessionPlaying {
return true, false
}
return true, true
}
if a.lastEvent != b.lastEvent {
return true, false
}
if len(a.guids) != len(b.guids) {
return true, false
}
return false, false
}

c.proxy.ServeHTTP(w, r)
func (c *PlexClient) ServeHTTP(w http.ResponseWriter, r *http.Request) {
path := r.URL.EscapedPath()
if c.redirectWebApp && strings.HasPrefix(path, "/web/") && r.Method == http.MethodGet {
http.Redirect(w, r, "https://app.plex.tv/desktop", http.StatusFound)
return
}

if w.(middleware.WrapResponseWriter).Status() == http.StatusOK {
query := r.URL.Query()
switch path {
case "/:/scrobble", "/:/unscrobble":
go clearCachedMetadata(query.Get("key"), r.Header.Get(headerToken))
case "/:/timeline":
go c.syncTimelineWithPlaxt(r)
if token := r.Header.Get(headerToken); token != "" {
// If it is an authorized request
if user := c.GetUser(token); user != nil {
switch path {
case "/:/scrobble", "/:/unscrobble":
ratingKey := r.URL.Query().Get("key")
if ratingKey != "" {
go clearCachedMetadata(ratingKey, user.Id)
}
case "/:/timeline":
go c.syncTimelineWithPlaxt(r, user)
case "/video/:/transcode/universal/decision":
if c.disableTranscode {
r = c.disableTranscoding(r)
}
}
}
}

c.proxy.ServeHTTP(w, r)
}

func (c *PlexClient) IsTokenSet() bool {
Expand Down Expand Up @@ -238,22 +258,16 @@ func (c *PlexClient) GetAccountInfo(token string) (user plex.UserPlexTV) {
return
}

func (c *PlexClient) syncTimelineWithPlaxt(r *http.Request) {
func (c *PlexClient) syncTimelineWithPlaxt(r *http.Request, user *plexUser) {
if c.plaxtUrl == "" || !c.IsTokenSet() {
return
}

token := r.Header.Get(headerToken)
clientUuid := r.Header.Get(headerClientIdentity)
ratingKey := r.URL.Query().Get("ratingKey")
playbackTime := r.URL.Query().Get("time")
state := r.URL.Query().Get("state")
if token == "" || clientUuid == "" || ratingKey == "" || playbackTime == "" || state == "" {
return
}

user := c.GetUser(token)
if user == nil {
if clientUuid == "" || ratingKey == "" || playbackTime == "" || state == "" {
return
}

Expand All @@ -274,21 +288,19 @@ func (c *PlexClient) syncTimelineWithPlaxt(r *http.Request) {
return
}
session := c.sessions[sessionKey]
sessionChanged := false

serverIdentifier := c.getServerIdentifier()
if serverIdentifier == "" {
if session.status == sessionWatched {
return
}
var section plex.Directory
sectionId := session.metadata.LibrarySectionID.String()
if c.getLibrarySection(sectionId) {
section = c.sections[sectionId]
if section.Type != "show" && section.Type != "movie" {

progress := int(math.Round(float64(viewOffset) / float64(session.metadata.Duration) * 100.0))
if progress == 0 {
if session.progress >= watchedThreshold {
// time would become 0 once a playback session was finished
progress = 100
viewOffset = session.metadata.Duration
} else if session.status != sessionUnplayed {
return
}
} else {
return
}

externalGuids := make([]plexhooks.ExternalGuid, 0)
Expand All @@ -305,52 +317,65 @@ func (c *PlexClient) syncTimelineWithPlaxt(r *http.Request) {
})
}
session.guids = externalGuids
sessionChanged = true
} else {
externalGuids = session.guids
}

var event string
progress := int(math.Round(float64(viewOffset) / float64(session.metadata.Duration) * 100.0))
var threshold int
switch state {
case "playing":
if session.status == sessionPlaying {
if progress >= 100 {
event = webhookEventScrobble
} else {
event = webhookEventResume
}
} else {
threshold = 100
if session.status == sessionUnplayed || session.status == sessionStopped {
event = webhookEventPlay
}
case "paused":
if progress >= watchedThreshold && session.status == sessionPlaying {
event = webhookEventScrobble
} else {
event = webhookEventPause
event = webhookEventResume
}
case "paused":
threshold = watchedThreshold
event = webhookEventPause
case "stopped":
if progress >= watchedThreshold && session.status == sessionPlaying {
event = webhookEventScrobble
} else {
event = webhookEventStop
}
threshold = watchedThreshold
event = webhookEventStop
}
if event == "" || session.status == sessionWatched {
if event == "" {
return
} else if event == webhookEventScrobble {
session.status = sessionWatched
sessionChanged = true
go clearCachedMetadata(ratingKey, r.Header.Get(headerToken))
} else if event == webhookEventStop {
go clearCachedMetadata(ratingKey, r.Header.Get(headerToken))
} else if session.status == sessionUnplayed {
} else if progress >= threshold {
event = webhookEventScrobble
}
switch event {
case webhookEventPlay, webhookEventResume:
session.status = sessionPlaying
sessionChanged = true
case webhookEventPause:
session.status = sessionPaused
case webhookEventStop:
session.status = sessionStopped
go clearCachedMetadata(ratingKey, user.Id)
case webhookEventScrobble:
session.status = sessionWatched
go clearCachedMetadata(ratingKey, user.Id)
}
if sessionChanged || event != session.lastEvent {
session.lastEvent = event
session.lastEvent = event
session.progress = progress
shouldUpdate, shouldScrobble := session.Check(c.sessions[sessionKey])
if shouldUpdate {
c.sessions[sessionKey] = session
}
if !shouldScrobble {
return
}

serverIdentifier := c.getServerIdentifier()
if serverIdentifier == "" {
return
}
var section plex.Directory
sectionId := session.metadata.LibrarySectionID.String()
if c.getLibrarySection(sectionId) {
section = c.sections[sectionId]
if section.Type != "show" && section.Type != "movie" {
return
}
} else {
return
}
Expand Down Expand Up @@ -391,9 +416,10 @@ func (c *PlexClient) getServerIdentifier() string {
defer c.mu.RUnlock()

identity, err := c.client.GetServerIdentity()
if err == nil {
c.serverIdentifier = &identity.MediaContainer.MachineIdentifier
if err != nil {
return ""
}
c.serverIdentifier = &identity.MediaContainer.MachineIdentifier
}
return *c.serverIdentifier
}
Expand Down
1 change: 1 addition & 0 deletions handler/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type sessionData struct {
guids []plexhooks.ExternalGuid
lastEvent string
status sessionStatus
progress int
}

type plexUser struct {
Expand Down
9 changes: 3 additions & 6 deletions handler/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func writeToCache(key string, resp *http.Response, ttl time.Duration) {
redisClient.Set(context.Background(), key, b, ttl)
}

func clearCachedMetadata(ratingKey, token string) {
func clearCachedMetadata(ratingKey string, userId int) {
if redisClient == nil {
return
}
Expand All @@ -130,11 +130,8 @@ func clearCachedMetadata(ratingKey, token string) {
if ratingKey != "" {
pattern += fmt.Sprintf("/library/metadata/%s", ratingKey)
}
if token != "" {
user := plexClient.GetUser(token)
if user != nil {
pattern += fmt.Sprintf("*%s=%d", headerUserId, user.Id)
}
if userId > 0 {
pattern += fmt.Sprintf("*%s=%d", headerUserId, userId)
}
pattern += "*"

Expand Down
2 changes: 1 addition & 1 deletion handler/websocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,6 @@ func wsOnActivity(n plex.NotificationContainer) {
}
}
if isMetadataChanged {
clearCachedMetadata("", "")
clearCachedMetadata("", 0)
}
}

0 comments on commit f6925be

Please sign in to comment.