niczoom 0 Posted January 2, 2018 Posted January 2, 2018 I'm using Autohotkey to automate my HTPC and would like to know if there is a way to detect if a user is logged into emby server and/or currently streaming video/tv? Possibly with a simple HTTP request? Thanks, Nic.
Luke 42081 Posted January 2, 2018 Posted January 2, 2018 Hi, yes, you can check out our wiki here to learn how to use the API: https://github.com/MediaBrowser/Emby/wiki You'll probably want to view the remote control section. Thanks.
niczoom 0 Posted January 2, 2018 Author Posted January 2, 2018 (edited) Hi Luke, I tried using: http://127.0.0.1:8096/emby/Sessions It returned Access token is required? I need an access token? Where do I get this and how do I include it in the http request above? Looks like once this is working 'Sessions' will include 'NowViewingItem' and 'PlayState' which should be enough data for what im after. Thanks, Nic. Edited January 2, 2018 by niczoom
Luke 42081 Posted January 2, 2018 Posted January 2, 2018 Hi, you're going to have to start at the beginning of the wiki and learn how to use the api, and that includes going through the authentication section. Please let us know if this helps. Thanks.
niczoom 0 Posted January 2, 2018 Author Posted January 2, 2018 Its beginning to look like more work than I expected. I've read through the wiki here https://github.com/MediaBrowser/Emby/wiki/Authentication but with no examples I was still in the dark. I then stumbled on a post here which I believe is what I need to do, although it's in PHP I could translate into Autohotkey. Is all this coding needed to perform what I need? My Autohotkey script will be running locally on the PC which Emby Server is running on so why do I need all this authentication code with a returned X-MediaBrowser-Token just to get the data returned from a call to /Sessions? Is their no simple 1 liner with a username and password to get what I need? Thanks, Nic.
Luke 42081 Posted January 2, 2018 Posted January 2, 2018 Is all this coding needed to perform what I need? Yes, because if it wasn't required, then there'd be no security and that would create it's own set of problems.
niczoom 0 Posted January 4, 2018 Author Posted January 4, 2018 (edited) Ok, I have a valid token returned! Now when I try to access http://127.0.0.1:8096/emby/Users/Sessions using the new token in a header http.SetRequestHeader("X-MediaBrowser-Token", accessToken), I get the following response: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) In my 'Authorization Request Header' as per github, I'm using UserID="515753215976426ca68b47dd986f36b2", Ive also tried using Guid="51575321-5976-426c-a68b-47dd986f36b2" with the same result. My whole Authorization header is: MediaBrowser Client="PC", Device="LoungePC", DeviceId="1", Version="1", UserID="515753215976426ca68b47dd986f36b2" The code: http.Open("POST", "http://127.0.0.1:8096/emby/Users/Sessions", true) http.SetRequestHeader("Content-Type", "application/json") http.SetRequestHeader("Authorization", authString) http.SetRequestHeader("X-MediaBrowser-Token", accessToken) http.Send(data) http.WaitForResponse() response := http.ResponseText Any ideas? Thanks, Nic. Edited January 4, 2018 by niczoom
niczoom 0 Posted January 4, 2018 Author Posted January 4, 2018 (edited) Ok, got it working, had the wrong HTTP address, and also removed the 'data' variable from the http.send command (contains the passwords from the previous AuthenticateByName request). The following works for me and returns the current session: http.Open("POST", "http://127.0.0.1:8096/emby/Sessions", true) http.SetRequestHeader("Content-Type", "application/json") http.SetRequestHeader("Authorization", authString) http.SetRequestHeader("X-MediaBrowser-Token", accessToken) http.Send() http.WaitForResponse() ; Using 'true' above and this call allows the script to remain responsive. response := http.ResponseText Using AutoHotkey BTW. Edited January 4, 2018 by niczoom
xyz 3 Posted January 4, 2018 Posted January 4, 2018 (edited) Why are you requesting /Users/Sessions? I don't see that documented. Think you want /Sessions. Edit: You beat me to it Edited January 4, 2018 by xyz
niczoom 0 Posted January 4, 2018 Author Posted January 4, 2018 I have my code looping through users in the current session. When I return 'LastActivityDate' it has never changed from when I started testing, at the moment it shows activity from like 6 hours ago, but I've logged in/out and played a few different movies in between time but the date/time in LastActivityDate does not change? Any ideas why? When logging into the dashboard (http://localhost:8096/web/dashboard.html) under Active Devices it shows all current active devices with correct times, as in 'Last seen X minutes ago'. Where does it get this info from? Cheers Nic.
Luke 42081 Posted January 4, 2018 Posted January 4, 2018 the session object has a LastActivityDate as well.
niczoom 0 Posted January 4, 2018 Author Posted January 4, 2018 (edited) the session object has a LastActivityDate as well. What do you mean Luke? I made a call to 'http.Open("GET", "http://127.0.0.1:8096/emby/Sessions",true)' and it returns (im assuming) a session object. Ive written some code to loop through this 'session data' and extract some data for each user including the ' LastActivityDate'. As I mentioned above the 'LastActivityDate' does not seem to update with the users latest activity. For example I just pulled out my phone now 2018-01-05T06:08:00 and logged into emby through the android app and check the sessions 'LastActivityDate' and it reported 2018-01-04T19:37:23, which is last night? If I then log into the dashboard (http://localhost:809.../dashboard.html) under Active Devices it shows my android phone 'SMG930F Emby for Android Mobile 2.9.76, Last seen 5 minutes ago'. Any ideas why the LastActivityDate is not current? And where does the dashboard gets its data from? Thanks, Nic. Edited January 4, 2018 by niczoom
Luke 42081 Posted January 4, 2018 Posted January 4, 2018 That endpoint gives you a list of sessions, and each session has a LastActivityDate property attached to it. That is what the dashboard is using.
niczoom 0 Posted January 4, 2018 Author Posted January 4, 2018 (edited) Ok, I've only just noticed that the 'LastActivityDate' does not seem to be set to the device that its used on, its behind by 630 minutes. For example when I got up this morning the 'LastActivityDate' was set to: 06:07:26.255 Fri, 05 Jan 2018 :: LastActivityDate: 2018-01-04T19:37:26.2236542Z Now ive just returned home and checked the 'LastActivityDate' again and it was: 07:39:39.346 Fri, 05 Jan 2018 :: LastActivityDate: 2018-01-04T21:09:39.3119501Z As you can see, my log shows the actual date/time on the left. Why is the 'LastActivityDate' returned from emby 630 minutes behind the actual date/time? Thanks, Nic. Edited January 4, 2018 by niczoom
niczoom 0 Posted January 4, 2018 Author Posted January 4, 2018 I now figured out that whatever time emby uses for the LastActivityDate parameter its 630 minutes behind the actual time on my PC where emby is running. So I'll work with that offset. Is emby hardcoded to use a particular date/time for the LastActivityDate parameter? If so why can't it just use my PCs current date/time where it's running on?
niczoom 0 Posted January 7, 2018 Author Posted January 7, 2018 (edited) Got it sorted now. I'll post my code below in case anyone is interested, it's using AutoHotkey. EMBY_State(z:=0) { debug := 0 log_global ? debug ? log(tab(z) A_ThisFunc "()") returnString := "" authString = MediaBrowser Client="PC", Device="LoungePC", DeviceId="1", Version="1", UserID="515753215976426ca68b47dd986f36b2" ; pw - password in plain text, password - password in Sha1, passwordMd5 - password in MD5 data = {"Username":"_YOUR_USERNAME_", "pw":"_PASSWORD_", "password":"_PASSWORD_", "passwordMd5":"_PASSWORD_"} ; Example: Download file over http into a variable: http := ComObjCreate("WinHttp.WinHttpRequest.5.1") http.Open("POST", "http://127.0.0.1:8096/emby/Users/AuthenticateByName", true) ;http.Open("POST", "http://127.0.0.1:8096/emby/Sessions", true) http.SetRequestHeader("Content-Type", "application/json") http.SetRequestHeader("Authorization", authString) http.Send(data) ; Using 'true' above and this call allows the script to remain responsive. http.WaitForResponse() response := http.ResponseText log_global ? debug ? log(tab(z+1) "response: " response) ; Check for a valid 'AccessToken' Try { accessToken := jsonGet(response,"AccessToken") log_global ? debug ? log(tab(z+1) "AccessToken : " accessToken) } catch { returnString := response return returnString } ; Return current session data http.Open("GET", "http://127.0.0.1:8096/emby/Sessions", true) http.SetRequestHeader("Content-Type", "application/json") http.SetRequestHeader("Authorization", authString) http.SetRequestHeader("X-MediaBrowser-Token", accessToken) http.Send() http.WaitForResponse() ; Using 'true' above and this call allows the script to remain responsive. response := http.ResponseText log_global ? debug ? log(tab(z+1) "Session Data : " response) sessionData := jsonAHK(response) ; The returned json session data can be formatted at : https://www.freeformatter.com/json-formatter.html ; Loop through all users logged into the current session. ; 10 is an arbitary number as I will never have 10 users connected at once. ; 'Loop 0' (A_Index=1) is skipped as this is the authenticated user session which uses the 'AccessToken' to gain authorized access to the emby api. ; -> Using the above Authorization string 'authString' OverTime := false ;Reset EmbyIdle := false ;Reset EmbyTimeOffset := 630 ;Minutes. Emby uses UTC time, this is the offset in minutes compared to my local time. MaxIdleEmbyUserTime := 5 Loop 10 { try { log_global ? debug ? log(tab(z+1) "Loop " A_Index) log_global ? debug ? log(tab(z+2) "`tUserName:" sessionData[A_Index].UserName . " Client:" sessionData[A_Index].Client . " DeviceName:" sessionData[A_Index].DeviceName) data1 := sessionData[A_Index].LastActivityDate log_global ? debug ? log(tab(z+2) "`tLastActivityDate:`t`t" data1) StringSplit SplitDate,data1,. ; Only keep left of colon (emby date 2018-01-04T09:11:25.7169690Z) log_global ? debug ? log(tab(z+2) "`tSplitDate:`t`t`t`t" SplitDate1) CleanDate := RegExReplace(SplitDate1, "(-|:|T)") ;Strip emby date back to AHK friendly type (2018-01-04T09:11:25.7169690Z) log_global ? debug ? log(tab(z+2) "`tCleanDate:`t`t`t`t" CleanDate) CleanDate += EmbyTimeOffset, Min ;Add offset to CleanDate log_global ? debug ? log(tab(z+2) "`tCleanDate+Offset:`t`t" CleanDate) TimeSinceLastActivity = ;Reset variable, make blank. TimeSinceLastActivity -= CleanDate, Min ; Time difference between 'startTime' and A_Now, using EnvSub. log_global ? debug ? log(tab(z+2) "`tTimeSinceLastActivity:`t" TimeSinceLastActivity " min") ; If LastActivityTime > MaxIdleEmbyUserTime then set OverTime=True if(TimeSinceLastActivity >= MaxIdleEmbyUserTime) { log_global ? debug ? log(tab(z+2) "`tOverTime:`t`t`t`tTrue") OverTime := true } ; Check 'NowPlayingItem' seperatly try { ; Streaming media IS detected for current user session. EmbyIdle := false NowPlaying := sessionData[A_Index].NowPlayingItem.Name log_global ? debug ? log(tab(z+2) "`tNowPlayingItem.Name:`t" NowPlaying " (EmbyIdle=False)") returnString := "Streaming: " NowPlaying } catch { ; NO streaming media detected for current user session. ; If OverTime=True then set EmbyIdle=True if(OverTime) { EmbyIdle := true log_global ? debug ? log(tab(z+2) "`tNo streaming detected. Max user idle time exceeded. Setting 'EmbyIdle=True'") } else { timeRemain := (MaxIdleEmbyUserTime-TimeSinceLastActivity) log_global ? debug ? log(tab(z+2) "`ttimeRemain:`t`t`t`t" timeRemain) timeRemainString := (timeRemain=1)?("< 1 minute"):(timeRemain " minutes") returnString := "User logged in, no streaming detected. (" timeRemainString " until max idle time is exceeded)" } } } catch { ; if no data is detected in the first loop then no users were detected therefore set EmbyIdle=True log_global ? debug ? log(tab(z+2) "A_Index:"A_Index) if(A_Index=1) { EmbyIdle := true break ;out of loop } } } if(EmbyIdle) { log_global ? debug ? log(tab(z+1) "EMBY IS IDLE - Allow Sleep") return "Idle" } else { log_global ? debug ? log(tab(z+1) "returnString="returnString) return returnString } } and a small function to parse JSON: jsonAHK(s){ ; https://autohotkey.com/board/topic/95262-obj-json-obj/ static o:=comobjcreate("scriptcontrol") o.language:="jscript" return o.eval("(" s ")") } Edited January 7, 2018 by niczoom
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now