Compare commits
44 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d9474cdcc5 | ||
![]() |
e49a34177a | ||
![]() |
67d203e011 | ||
![]() |
0d38b3de16 | ||
![]() |
38116a14f3 | ||
![]() |
b28f0b65f0 | ||
![]() |
13ab4a9363 | ||
![]() |
7cb7783a34 | ||
![]() |
d1a13dad38 | ||
![]() |
b4e06dea99 | ||
![]() |
0f92dc0fdf | ||
![]() |
6a58895d37 | ||
![]() |
1709a2b7df | ||
![]() |
febb3da0c1 | ||
![]() |
552a428985 | ||
![]() |
38e04bd42a | ||
![]() |
8f0ba5ba4f | ||
![]() |
c67aedceb1 | ||
![]() |
b3a7fbd9b5 | ||
![]() |
29522428de | ||
![]() |
77bd52b2ae | ||
![]() |
d8112e7628 | ||
![]() |
ffa208e73f | ||
![]() |
61ead15c38 | ||
![]() |
407e2ae481 | ||
![]() |
5fb16edf43 | ||
![]() |
8eb5c475bb | ||
![]() |
84090310f7 | ||
![]() |
fc98e2f052 | ||
![]() |
bedcfa9520 | ||
![]() |
bb152b590b | ||
![]() |
3623732cf7 | ||
![]() |
05ba89f164 | ||
![]() |
cb5053476d | ||
![]() |
cee656a053 | ||
![]() |
cfc7d529e1 | ||
![]() |
a93dc68e6c | ||
![]() |
2d91cfd3db | ||
![]() |
36e81f44cb | ||
![]() |
cb0e65337f | ||
![]() |
1c627f4649 | ||
![]() |
16cbfed20b | ||
![]() |
f6a3bc57e2 | ||
![]() |
594443d1dc |
194
API.md
194
API.md
@@ -543,6 +543,33 @@ Returns:
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### get_library
|
||||||
|
Get a library's details.
|
||||||
|
|
||||||
|
```
|
||||||
|
Required parameters:
|
||||||
|
section_id (str): The id of the Plex library section
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
None
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
json:
|
||||||
|
{"child_count": null,
|
||||||
|
"count": 887,
|
||||||
|
"do_notify": 1,
|
||||||
|
"do_notify_created": 1,
|
||||||
|
"keep_history": 1,
|
||||||
|
"library_art": "/:/resources/movie-fanart.jpg",
|
||||||
|
"library_thumb": "/:/resources/movie.png",
|
||||||
|
"parent_count": null,
|
||||||
|
"section_id": 1,
|
||||||
|
"section_name": "Movies",
|
||||||
|
"section_type": "movie"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### get_library_media_info
|
### get_library_media_info
|
||||||
Get the data on the PlexPy media info tables.
|
Get the data on the PlexPy media info tables.
|
||||||
|
|
||||||
@@ -619,6 +646,66 @@ Returns:
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### get_library_user_stats
|
||||||
|
Get a library's user statistics.
|
||||||
|
|
||||||
|
```
|
||||||
|
Required parameters:
|
||||||
|
section_id (str): The id of the Plex library section
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
None
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
json:
|
||||||
|
[{"friendly_name": "Jon Snow",
|
||||||
|
"total_plays": 170,
|
||||||
|
"user_id": 133788,
|
||||||
|
"user_thumb": "https://plex.tv/users/k10w42309cynaopq/avatar"
|
||||||
|
},
|
||||||
|
{"platform_type": "DanyKhaleesi69",
|
||||||
|
"total_plays": 42,
|
||||||
|
"user_id": 8008135,
|
||||||
|
"user_thumb": "https://plex.tv/users/568gwwoib5t98a3a/avatar"
|
||||||
|
},
|
||||||
|
{...},
|
||||||
|
{...}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### get_library_watch_time_stats
|
||||||
|
Get a library's watch time statistics.
|
||||||
|
|
||||||
|
```
|
||||||
|
Required parameters:
|
||||||
|
section_id (str): The id of the Plex library section
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
None
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
json:
|
||||||
|
[{"query_days": 1,
|
||||||
|
"total_plays": 0,
|
||||||
|
"total_time": 0
|
||||||
|
},
|
||||||
|
{"query_days": 7,
|
||||||
|
"total_plays": 3,
|
||||||
|
"total_time": 15694
|
||||||
|
},
|
||||||
|
{"query_days": 30,
|
||||||
|
"total_plays": 35,
|
||||||
|
"total_time": 63054
|
||||||
|
},
|
||||||
|
{"query_days": 0,
|
||||||
|
"total_plays": 508,
|
||||||
|
"total_time": 1183080
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### get_logs
|
### get_logs
|
||||||
Get the PlexPy logs.
|
Get the PlexPy logs.
|
||||||
|
|
||||||
@@ -1311,6 +1398,35 @@ Returns:
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### get_user
|
||||||
|
Get a user's details.
|
||||||
|
|
||||||
|
```
|
||||||
|
Required parameters:
|
||||||
|
user_id (str): The id of the Plex user
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
None
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
json:
|
||||||
|
{"allow_guest": 1,
|
||||||
|
"deleted_user": 0,
|
||||||
|
"do_notify": 1,
|
||||||
|
"email": "Jon.Snow.1337@CastleBlack.com",
|
||||||
|
"friendly_name": "Jon Snow",
|
||||||
|
"is_allow_sync": 1,
|
||||||
|
"is_home_user": 1,
|
||||||
|
"is_restricted": 0,
|
||||||
|
"keep_history": 1,
|
||||||
|
"shared_libraries": ["10", "1", "4", "5", "15", "20", "2"],
|
||||||
|
"user_id": 133788,
|
||||||
|
"user_thumb": "https://plex.tv/users/k10w42309cynaopq/avatar",
|
||||||
|
"username": "LordCommanderSnow"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### get_user_ips
|
### get_user_ips
|
||||||
Get the data on PlexPy users IP table.
|
Get the data on PlexPy users IP table.
|
||||||
|
|
||||||
@@ -1415,6 +1531,66 @@ Returns:
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### get_user_player_stats
|
||||||
|
Get a user's player statistics.
|
||||||
|
|
||||||
|
```
|
||||||
|
Required parameters:
|
||||||
|
user_id (str): The id of the Plex user
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
None
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
json:
|
||||||
|
[{"platform_type": "Chrome",
|
||||||
|
"player_name": "Plex Web (Chrome)",
|
||||||
|
"result_id": 1,
|
||||||
|
"total_plays": 170
|
||||||
|
},
|
||||||
|
{"platform_type": "Chromecast",
|
||||||
|
"player_name": "Chromecast",
|
||||||
|
"result_id": 2,
|
||||||
|
"total_plays": 42
|
||||||
|
},
|
||||||
|
{...},
|
||||||
|
{...}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### get_user_watch_time_stats
|
||||||
|
Get a user's watch time statistics.
|
||||||
|
|
||||||
|
```
|
||||||
|
Required parameters:
|
||||||
|
user_id (str): The id of the Plex user
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
None
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
json:
|
||||||
|
[{"query_days": 1,
|
||||||
|
"total_plays": 0,
|
||||||
|
"total_time": 0
|
||||||
|
},
|
||||||
|
{"query_days": 7,
|
||||||
|
"total_plays": 3,
|
||||||
|
"total_time": 15694
|
||||||
|
},
|
||||||
|
{"query_days": 30,
|
||||||
|
"total_plays": 35,
|
||||||
|
"total_time": 63054
|
||||||
|
},
|
||||||
|
{"query_days": 0,
|
||||||
|
"total_plays": 508,
|
||||||
|
"total_time": 1183080
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### get_users
|
### get_users
|
||||||
Get a list of all users that have access to your server.
|
Get a list of all users that have access to your server.
|
||||||
|
|
||||||
@@ -1520,6 +1696,24 @@ Send a notification using PlexPy.
|
|||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
agent_id(str): The id of the notification agent to use
|
agent_id(str): The id of the notification agent to use
|
||||||
|
9 # Boxcar2
|
||||||
|
17 # Browser
|
||||||
|
10 # Email
|
||||||
|
16 # Facebook
|
||||||
|
0 # Growl
|
||||||
|
12 # IFTTT
|
||||||
|
18 # Join
|
||||||
|
4 # NotifyMyAndroid
|
||||||
|
3 # Plex Home Theater
|
||||||
|
1 # Prowl
|
||||||
|
5 # Pushalot
|
||||||
|
6 # Pushbullet
|
||||||
|
7 # Pushover
|
||||||
|
15 # Scripts
|
||||||
|
14 # Slack
|
||||||
|
13 # Telegram
|
||||||
|
11 # Twitter
|
||||||
|
2 # XBMC
|
||||||
subject(str): The subject of the message
|
subject(str): The subject of the message
|
||||||
body(str): The body of the message
|
body(str): The body of the message
|
||||||
|
|
||||||
|
41
CHANGELOG.md
41
CHANGELOG.md
@@ -1,5 +1,46 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v1.4.6 (2016-06-11)
|
||||||
|
|
||||||
|
* New: Added User and Library statistics to the API.
|
||||||
|
* New: Ability to refresh individual poster images without clearing the entire cache. (Thanks @Hellowlol)
|
||||||
|
* New: Added {added_date}, {updated_date}, and {last_viewed_date} to metadata notification options.
|
||||||
|
* New: Log level filter for Plex logs. (Thanks @sanderploegsma)
|
||||||
|
* New: Log level filter for PlexPy logs.
|
||||||
|
* New: Button to download Plex logs directly from the web interface.
|
||||||
|
* New: Advanced setting in the config file to change the number of Plex log lines retrieved.
|
||||||
|
* Fix: FreeBSD and FreeNAS init scripts to reflect the path in the installation guide. (Thanks @nortron)
|
||||||
|
* Fix: Monitoring crashing when failed to retrieve current activity.
|
||||||
|
|
||||||
|
|
||||||
|
## v1.4.5 (2016-05-25)
|
||||||
|
|
||||||
|
* Fix: PlexPy unable to start if failed to get shared libraries for a user.
|
||||||
|
* Fix: Matching port number when retrieving the PMS url.
|
||||||
|
* Fix: Extract mapped IPv4 address in Plexivity import.
|
||||||
|
* Change: Revert back to internal url when retrieving PMS images.
|
||||||
|
|
||||||
|
|
||||||
|
## v1.4.4 (2016-05-24)
|
||||||
|
|
||||||
|
* Fix: Image queries crashing the PMS when playing clips from channels.
|
||||||
|
* Fix: Plexivity import if IP address is missing.
|
||||||
|
* Fix: Tooltips shown behind the datatable headers.
|
||||||
|
* Fix: Current activity instances rendered in a random order causing them to jump around.
|
||||||
|
|
||||||
|
|
||||||
|
## v1.4.3 (2016-05-22)
|
||||||
|
|
||||||
|
* Fix: PlexPy not starting without any authentication method.
|
||||||
|
|
||||||
|
|
||||||
|
## v1.4.2 (2016-05-22)
|
||||||
|
|
||||||
|
* New: Option to use HTTP basic authentication instead of the HTML login form.
|
||||||
|
* Fix: Unable to save settings when enabling the HTTP proxy setting.
|
||||||
|
* Change: Match the PMS port when retrieving the PMS url.
|
||||||
|
|
||||||
|
|
||||||
## v1.4.1 (2016-05-20)
|
## v1.4.1 (2016-05-20)
|
||||||
|
|
||||||
* New: HTTP Proxy checkbox in the settings. Enable this if using an SSL enabled reverse proxy in front of PlexPy.
|
* New: HTTP Proxy checkbox in the settings. Enable this if using an SSL enabled reverse proxy in front of PlexPy.
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
<!---
|
<!---
|
||||||
Reporting Issues:
|
Reporting Issues:
|
||||||
* To ensure that a develpoer has enough information to work with please include all of the information below.
|
* To ensure that a developer has enough information to work with please include all of the information below.
|
||||||
Please provide as much detail as possible. Screenshots can be very useful to see the problem.
|
Please provide as much detail as possible. Screenshots can be very useful to see the problem.
|
||||||
* Use proper markdown syntax to structure your post (i.e. code/log in code blocks).
|
* Use proper markdown syntax to structure your post (i.e. code/log in code blocks).
|
||||||
See: https://help.github.com/articles/basic-writing-and-formatting-syntax/
|
See: https://help.github.com/articles/basic-writing-and-formatting-syntax/
|
||||||
* Iclude a link to your **FULL** log file that has the error(not just a few lines!).
|
* Include a link to your **FULL** log file that has the error(not just a few lines!).
|
||||||
Please use [Gist](http://gist.github.com) or [Pastebin](http://pastebin.com/).
|
Please use [Gist](http://gist.github.com) or [Pastebin](http://pastebin.com/).
|
||||||
|
|
||||||
Feature Requests:
|
Feature Requests:
|
||||||
|
@@ -214,6 +214,7 @@ def main():
|
|||||||
'https_key': plexpy.CONFIG.HTTPS_KEY,
|
'https_key': plexpy.CONFIG.HTTPS_KEY,
|
||||||
'http_username': plexpy.CONFIG.HTTP_USERNAME,
|
'http_username': plexpy.CONFIG.HTTP_USERNAME,
|
||||||
'http_password': plexpy.CONFIG.HTTP_PASSWORD,
|
'http_password': plexpy.CONFIG.HTTP_PASSWORD,
|
||||||
|
'http_basic_auth': plexpy.CONFIG.HTTP_BASIC_AUTH
|
||||||
}
|
}
|
||||||
webstart.initialize(web_config)
|
webstart.initialize(web_config)
|
||||||
|
|
||||||
|
@@ -1184,6 +1184,7 @@ a:hover .dashboard-recent-media-cover {
|
|||||||
margin: 0 40px 0 25px;
|
margin: 0 40px 0 25px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.summary-poster-face {
|
.summary-poster-face {
|
||||||
background-position: center;
|
background-position: center;
|
||||||
@@ -1922,6 +1923,7 @@ a .library-user-instance-box:hover {
|
|||||||
.home-platforms-instance-poster {
|
.home-platforms-instance-poster {
|
||||||
margin-left: 0px;
|
margin-left: 0px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.home-platforms-instance-poster .home-platforms-poster-face {
|
.home-platforms-instance-poster .home-platforms-poster-face {
|
||||||
background-position: center;
|
background-position: center;
|
||||||
@@ -2079,6 +2081,7 @@ a .library-user-instance-box:hover {
|
|||||||
.home-platforms-instance-list-poster {
|
.home-platforms-instance-list-poster {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 20px;
|
left: 20px;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.home-platforms-instance-list-poster .home-platforms-list-poster-face {
|
.home-platforms-instance-list-poster .home-platforms-list-poster-face {
|
||||||
background-position: center;
|
background-position: center;
|
||||||
@@ -2965,3 +2968,40 @@ a.no-highlight:hover {
|
|||||||
border: 0px solid #444;
|
border: 0px solid #444;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
.overlay-refresh-image {
|
||||||
|
opacity: 0;
|
||||||
|
color: #000;
|
||||||
|
font-size: 16px;
|
||||||
|
float: left;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 10px;
|
||||||
|
z-index: 1;
|
||||||
|
transition: all .1s cubic-bezier(.4,0,1,1);
|
||||||
|
-webkit-transition: all .1s cubic-bezier(.4,0,1,1);
|
||||||
|
-moz-transition: all .1s cubic-bezier(.4,0,1,1);
|
||||||
|
-o-transition: all .1s cubic-bezier(.4,0,1,1);
|
||||||
|
text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, 1px 1px 0 #fff;
|
||||||
|
}
|
||||||
|
.overlay-refresh-image.left {
|
||||||
|
left: 10px;
|
||||||
|
}
|
||||||
|
.overlay-refresh-image.info-art {
|
||||||
|
color: #999;
|
||||||
|
top: 15px;
|
||||||
|
right: 25px;
|
||||||
|
opacity: 1;
|
||||||
|
text-shadow: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.overlay-refresh-image.info-art:hover {
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
a:hover .overlay-refresh-image {
|
||||||
|
opacity: .25;
|
||||||
|
top: 8px;
|
||||||
|
}
|
||||||
|
a:hover .overlay-refresh-image:hover {
|
||||||
|
opacity: .9;
|
||||||
|
}
|
@@ -106,6 +106,7 @@ DOCUMENTATION :: END
|
|||||||
% else:
|
% else:
|
||||||
<div class="dashboard-activity-poster-face" style="background-image: url(${a['art']});"></div>
|
<div class="dashboard-activity-poster-face" style="background-image: url(${a['art']});"></div>
|
||||||
% endif
|
% endif
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
<div class="dashboard-activity-button-info">
|
<div class="dashboard-activity-button-info">
|
||||||
<button type="button" class="btn btn-activity-info btn-lg" data-target="#stream-${a['session_key']}">
|
<button type="button" class="btn btn-activity-info btn-lg" data-target="#stream-${a['session_key']}">
|
||||||
<i class="fa fa-info-circle"></i>
|
<i class="fa fa-info-circle"></i>
|
||||||
|
@@ -61,6 +61,8 @@ DOCUMENTATION :: END
|
|||||||
|
|
||||||
% if data is not None:
|
% if data is not None:
|
||||||
<%
|
<%
|
||||||
|
from urllib import quote
|
||||||
|
|
||||||
from plexpy import helpers
|
from plexpy import helpers
|
||||||
data['indexes'] = helpers.cast_to_int(data['indexes'])
|
data['indexes'] = helpers.cast_to_int(data['indexes'])
|
||||||
%>
|
%>
|
||||||
@@ -90,9 +92,11 @@ DOCUMENTATION :: END
|
|||||||
<div class="dashboard-activity-poster-face" style="background-image: url(${data['thumb']});"></div>
|
<div class="dashboard-activity-poster-face" style="background-image: url(${data['thumb']});"></div>
|
||||||
% else:
|
% else:
|
||||||
% if data['art']:
|
% if data['art']:
|
||||||
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${data['art']}&width=500&height=280&fallback=art);"></div>
|
<!--Hacky solution to escape the image url until I come up with something better-->
|
||||||
|
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${quote(data['art'])}&width=500&height=280&fallback=art);"></div>
|
||||||
% else:
|
% else:
|
||||||
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=500&height=280&fallback=art);"></div>
|
<!--Hacky solution to escape the image url until I come up with something better-->
|
||||||
|
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${quote(data['thumb'])}&width=500&height=280&fallback=art);"></div>
|
||||||
% endif
|
% endif
|
||||||
% endif
|
% endif
|
||||||
% elif data['media_type'] == 'photo':
|
% elif data['media_type'] == 'photo':
|
||||||
@@ -104,6 +108,7 @@ DOCUMENTATION :: END
|
|||||||
% else:
|
% else:
|
||||||
<div class="dashboard-activity-poster-face" style="background-image: url(${data['art']});"></div>
|
<div class="dashboard-activity-poster-face" style="background-image: url(${data['art']});"></div>
|
||||||
% endif
|
% endif
|
||||||
|
<span class="overlay-refresh-image left" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
<div class="dashboard-activity-button-info">
|
<div class="dashboard-activity-button-info">
|
||||||
<button type="button" class="btn btn-activity-info btn-lg" data-target="#stream-${data['session_key']}" data-id="${data['session_key']}">
|
<button type="button" class="btn btn-activity-info btn-lg" data-target="#stream-${data['session_key']}" data-id="${data['session_key']}">
|
||||||
<i class="fa fa-info-circle"></i>
|
<i class="fa fa-info-circle"></i>
|
||||||
|
@@ -103,6 +103,7 @@ DOCUMENTATION :: END
|
|||||||
% if top_stat['rows'][0]['grandparent_thumb']:
|
% if top_stat['rows'][0]['grandparent_thumb']:
|
||||||
<div class="home-platforms-instance-poster">
|
<div class="home-platforms-instance-poster">
|
||||||
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="home-platforms-instance-poster">
|
<div class="home-platforms-instance-poster">
|
||||||
@@ -149,6 +150,7 @@ DOCUMENTATION :: END
|
|||||||
% if top_stat['rows'][loop.index]['grandparent_thumb']:
|
% if top_stat['rows'][loop.index]['grandparent_thumb']:
|
||||||
<div class="home-platforms-instance-list-poster">
|
<div class="home-platforms-instance-list-poster">
|
||||||
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="home-platforms-instance-list-poster">
|
<div class="home-platforms-instance-list-poster">
|
||||||
@@ -199,6 +201,7 @@ DOCUMENTATION :: END
|
|||||||
% if top_stat['rows'][0]['grandparent_thumb'] != '':
|
% if top_stat['rows'][0]['grandparent_thumb'] != '':
|
||||||
<div class="home-platforms-instance-poster">
|
<div class="home-platforms-instance-poster">
|
||||||
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="home-platforms-instance-poster">
|
<div class="home-platforms-instance-poster">
|
||||||
@@ -241,6 +244,7 @@ DOCUMENTATION :: END
|
|||||||
% if top_stat['rows'][loop.index]['grandparent_thumb']:
|
% if top_stat['rows'][loop.index]['grandparent_thumb']:
|
||||||
<div class="home-platforms-instance-list-poster">
|
<div class="home-platforms-instance-list-poster">
|
||||||
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="home-platforms-instance-list-poster">
|
<div class="home-platforms-instance-list-poster">
|
||||||
@@ -295,6 +299,7 @@ DOCUMENTATION :: END
|
|||||||
% if top_stat['rows'][0]['thumb']:
|
% if top_stat['rows'][0]['thumb']:
|
||||||
<div class="home-platforms-instance-poster">
|
<div class="home-platforms-instance-poster">
|
||||||
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="home-platforms-instance-poster">
|
<div class="home-platforms-instance-poster">
|
||||||
@@ -341,6 +346,7 @@ DOCUMENTATION :: END
|
|||||||
% if top_stat['rows'][loop.index]['thumb']:
|
% if top_stat['rows'][loop.index]['thumb']:
|
||||||
<div class="home-platforms-instance-list-poster">
|
<div class="home-platforms-instance-list-poster">
|
||||||
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="home-platforms-instance-list-poster">
|
<div class="home-platforms-instance-list-poster">
|
||||||
@@ -391,6 +397,7 @@ DOCUMENTATION :: END
|
|||||||
% if top_stat['rows'][0]['thumb']:
|
% if top_stat['rows'][0]['thumb']:
|
||||||
<div class="home-platforms-instance-poster">
|
<div class="home-platforms-instance-poster">
|
||||||
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="home-platforms-instance-poster">
|
<div class="home-platforms-instance-poster">
|
||||||
@@ -433,6 +440,7 @@ DOCUMENTATION :: END
|
|||||||
% if top_stat['rows'][loop.index]['thumb']:
|
% if top_stat['rows'][loop.index]['thumb']:
|
||||||
<div class="home-platforms-instance-list-poster">
|
<div class="home-platforms-instance-list-poster">
|
||||||
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="home-platforms-instance-list-poster">
|
<div class="home-platforms-instance-list-poster">
|
||||||
@@ -487,6 +495,7 @@ DOCUMENTATION :: END
|
|||||||
% if top_stat['rows'][0]['grandparent_thumb']:
|
% if top_stat['rows'][0]['grandparent_thumb']:
|
||||||
<div class="home-platforms-instance-poster">
|
<div class="home-platforms-instance-poster">
|
||||||
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div>
|
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="home-platforms-instance-poster">
|
<div class="home-platforms-instance-poster">
|
||||||
@@ -533,6 +542,7 @@ DOCUMENTATION :: END
|
|||||||
% if top_stat['rows'][loop.index]['grandparent_thumb']:
|
% if top_stat['rows'][loop.index]['grandparent_thumb']:
|
||||||
<div class="home-platforms-instance-list-poster">
|
<div class="home-platforms-instance-list-poster">
|
||||||
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div>
|
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="home-platforms-instance-list-poster">
|
<div class="home-platforms-instance-list-poster">
|
||||||
@@ -583,6 +593,7 @@ DOCUMENTATION :: END
|
|||||||
% if top_stat['rows'][0]['grandparent_thumb'] != '':
|
% if top_stat['rows'][0]['grandparent_thumb'] != '':
|
||||||
<div class="home-platforms-instance-poster">
|
<div class="home-platforms-instance-poster">
|
||||||
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div>
|
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="home-platforms-instance-poster">
|
<div class="home-platforms-instance-poster">
|
||||||
@@ -625,6 +636,7 @@ DOCUMENTATION :: END
|
|||||||
% if top_stat['rows'][loop.index]['grandparent_thumb']:
|
% if top_stat['rows'][loop.index]['grandparent_thumb']:
|
||||||
<div class="home-platforms-instance-list-poster">
|
<div class="home-platforms-instance-list-poster">
|
||||||
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div>
|
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="home-platforms-instance-list-poster">
|
<div class="home-platforms-instance-list-poster">
|
||||||
@@ -847,6 +859,7 @@ DOCUMENTATION :: END
|
|||||||
% if top_stat['rows'][0]['thumb']:
|
% if top_stat['rows'][0]['thumb']:
|
||||||
<div class="home-platforms-instance-poster">
|
<div class="home-platforms-instance-poster">
|
||||||
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="home-platforms-instance-poster">
|
<div class="home-platforms-instance-poster">
|
||||||
@@ -903,6 +916,7 @@ DOCUMENTATION :: END
|
|||||||
% if top_stat['rows'][loop.index]['thumb']:
|
% if top_stat['rows'][loop.index]['thumb']:
|
||||||
<div class="home-platforms-instance-list-poster">
|
<div class="home-platforms-instance-list-poster">
|
||||||
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="home-platforms-instance-list-poster">
|
<div class="home-platforms-instance-list-poster">
|
||||||
|
@@ -103,10 +103,20 @@
|
|||||||
type: 'GET',
|
type: 'GET',
|
||||||
cache: false,
|
cache: false,
|
||||||
async: true,
|
async: true,
|
||||||
|
error: function (xhr, status, error) {
|
||||||
|
console.log(status + ': ' + error);
|
||||||
|
},
|
||||||
complete: function (xhr, status) {
|
complete: function (xhr, status) {
|
||||||
$('#dashboard-checking-activity').remove();
|
$('#dashboard-checking-activity').remove();
|
||||||
|
|
||||||
var current_activity = $.parseJSON(xhr.responseText);
|
var current_activity;
|
||||||
|
try {
|
||||||
|
current_activity = $.parseJSON(xhr.responseText);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(status + ': ' + e);
|
||||||
|
current_activity = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(current_activity)) {
|
if (!(current_activity)) {
|
||||||
$('#currentActivity').html('<div id="dashboard-no-activity" class="text-muted">There was an error communicating with your Plex Server.</div>');
|
$('#currentActivity').html('<div id="dashboard-no-activity" class="text-muted">There was an error communicating with your Plex Server.</div>');
|
||||||
return
|
return
|
||||||
|
@@ -68,6 +68,7 @@ DOCUMENTATION :: END
|
|||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="art-face" style="background-image:url(pms_image_proxy?img=${data['art']}&width=1920&height=1080)"></div>
|
<div class="art-face" style="background-image:url(pms_image_proxy?img=${data['art']}&width=1920&height=1080)"></div>
|
||||||
|
<span class="overlay-refresh-image info-art" title="Refresh background image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
<div class="summary-container">
|
<div class="summary-container">
|
||||||
<div class="summary-navbar">
|
<div class="summary-navbar">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
@@ -119,18 +120,21 @@ DOCUMENTATION :: END
|
|||||||
<span></span>
|
<span></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% elif data['media_type'] == 'artist' or data['media_type'] == 'album' or data['media_type'] == 'track':
|
% elif data['media_type'] == 'artist' or data['media_type'] == 'album' or data['media_type'] == 'track':
|
||||||
<div class="summary-poster-face-track" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=500&height=500&fallback=cover);">
|
<div class="summary-poster-face-track" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=500&height=500&fallback=cover);">
|
||||||
<div class="summary-poster-face-overlay">
|
<div class="summary-poster-face-overlay">
|
||||||
<span></span>
|
<span></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% else:
|
% else:
|
||||||
<div class="summary-poster-face" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=300&height=450&fallback=poster);">
|
<div class="summary-poster-face" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=300&height=450&fallback=poster);">
|
||||||
<div class="summary-poster-face-overlay">
|
<div class="summary-poster-face-overlay">
|
||||||
<span></span>
|
<span></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -51,6 +51,7 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
% elif data['children_type'] == 'episode':
|
% elif data['children_type'] == 'episode':
|
||||||
@@ -63,6 +64,7 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div class="item-children-instance-text-wrapper episode-item">
|
<div class="item-children-instance-text-wrapper episode-item">
|
||||||
@@ -74,6 +76,7 @@ DOCUMENTATION :: END
|
|||||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">
|
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face album-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=300&fallback=cover);"></div>
|
<div class="item-children-poster-face album-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=300&fallback=cover);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div class="item-children-instance-text-wrapper album-item">
|
<div class="item-children-instance-text-wrapper album-item">
|
||||||
|
@@ -65,6 +65,7 @@ DOCUMENTATION :: END
|
|||||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face season-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="item-children-poster-face season-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-children-instance-text-wrapper season-item">
|
<div class="item-children-instance-text-wrapper season-item">
|
||||||
<h3 title="${child['title']}">${child['title']}</h3>
|
<h3 title="${child['title']}">${child['title']}</h3>
|
||||||
@@ -87,6 +88,7 @@ DOCUMENTATION :: END
|
|||||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face season-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="item-children-poster-face season-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-children-instance-text-wrapper season-item">
|
<div class="item-children-instance-text-wrapper season-item">
|
||||||
<h3 title="${child['title']}">${child['title']}</h3>
|
<h3 title="${child['title']}">${child['title']}</h3>
|
||||||
@@ -109,6 +111,7 @@ DOCUMENTATION :: END
|
|||||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face season-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="item-children-poster-face season-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-children-instance-text-wrapper season-item">
|
<div class="item-children-instance-text-wrapper season-item">
|
||||||
<h3 title="${child['parent_title']}">${child['parent_title']}</h3>
|
<h3 title="${child['parent_title']}">${child['parent_title']}</h3>
|
||||||
@@ -131,6 +134,7 @@ DOCUMENTATION :: END
|
|||||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face episode-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=500&height=250&fallback=art);"></div>
|
<div class="item-children-poster-face episode-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=500&height=250&fallback=art);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-children-instance-text-wrapper episode-item">
|
<div class="item-children-instance-text-wrapper episode-item">
|
||||||
<h3 title="${child['grandparent_title']}">${child['grandparent_title']}</h3>
|
<h3 title="${child['grandparent_title']}">${child['grandparent_title']}</h3>
|
||||||
@@ -154,6 +158,7 @@ DOCUMENTATION :: END
|
|||||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face album-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=300&fallback=cover);"></div>
|
<div class="item-children-poster-face album-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=300&fallback=cover);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-children-instance-text-wrapper album-item">
|
<div class="item-children-instance-text-wrapper album-item">
|
||||||
<h3 title="${child['title']}">${child['title']}</h3>
|
<h3 title="${child['title']}">${child['title']}</h3>
|
||||||
@@ -175,6 +180,7 @@ DOCUMENTATION :: END
|
|||||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face album-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=300&fallback=cover);"></div>
|
<div class="item-children-poster-face album-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=300&fallback=cover);"></div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-children-instance-text-wrapper album-item">
|
<div class="item-children-instance-text-wrapper album-item">
|
||||||
<h3 title="${child['parent_title']}">${child['parent_title']}</h3>
|
<h3 title="${child['parent_title']}">${child['parent_title']}</h3>
|
||||||
@@ -204,6 +210,7 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
<div class="item-children-instance-text-wrapper album-item">
|
<div class="item-children-instance-text-wrapper album-item">
|
||||||
<h3 title="${child['grandparent_title']}">${child['grandparent_title']}</h3>
|
<h3 title="${child['grandparent_title']}">${child['grandparent_title']}</h3>
|
||||||
<h3 title="${child['title']}">${child['title']}</h3>
|
<h3 title="${child['title']}">${child['title']}</h3>
|
||||||
|
@@ -400,3 +400,26 @@ window.onerror = function (message, file, line) {
|
|||||||
};
|
};
|
||||||
$.post("log_js_errors", e, function (data) { });
|
$.post("log_js_errors", e, function (data) { });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$('*').on('click', '.refresh_pms_image', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
var background_div = $(this).parent().siblings(['style*=pms_image_proxy']).first();
|
||||||
|
var pms_proxy_url = background_div.css('background-image');
|
||||||
|
pms_proxy_url = /^url\((['"]?)(.*)\1\)$/.exec(pms_proxy_url);
|
||||||
|
pms_proxy_url = pms_proxy_url ? pms_proxy_url[2] : ""; // If matched, retrieve url, otherwise ""
|
||||||
|
|
||||||
|
if (pms_proxy_url.indexOf('pms_image_proxy') == -1) {
|
||||||
|
console.log('PMS image proxy url not found.');
|
||||||
|
} else {
|
||||||
|
if (pms_proxy_url.indexOf('refresh=true') > -1) {
|
||||||
|
pms_proxy_url = pms_proxy_url.replace("&refresh=true", "");
|
||||||
|
console.log(pms_proxy_url)
|
||||||
|
background_div.css('background-image', 'url(' + pms_proxy_url + ')');
|
||||||
|
background_div.css('background-image', 'url(' + pms_proxy_url + '&refresh=true)');
|
||||||
|
} else {
|
||||||
|
background_div.css('background-image', 'url(' + pms_proxy_url + '&refresh=true)');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
@@ -448,10 +448,10 @@ function childTableOptions(rowData) {
|
|||||||
|
|
||||||
// Create the tooltips.
|
// Create the tooltips.
|
||||||
$('.expand-history-tooltip').tooltip({ container: 'body' });
|
$('.expand-history-tooltip').tooltip({ container: 'body' });
|
||||||
$('.external-ip-tooltip').tooltip();
|
$('.external-ip-tooltip').tooltip({ container: 'body' });
|
||||||
$('.transcode-tooltip').tooltip();
|
$('.transcode-tooltip').tooltip({ container: 'body' });
|
||||||
$('.media-type-tooltip').tooltip();
|
$('.media-type-tooltip').tooltip({ container: 'body' });
|
||||||
$('.watched-tooltip').tooltip();
|
$('.watched-tooltip').tooltip({ container: 'body' });
|
||||||
$('.thumb-tooltip').popover({
|
$('.thumb-tooltip').popover({
|
||||||
html: true,
|
html: true,
|
||||||
container: 'body',
|
container: 'body',
|
||||||
|
@@ -132,8 +132,8 @@ history_table_modal_options = {
|
|||||||
$('#ajaxMsg').fadeOut();
|
$('#ajaxMsg').fadeOut();
|
||||||
|
|
||||||
// Create the tooltips.
|
// Create the tooltips.
|
||||||
$('.transcode-tooltip').tooltip();
|
$('.transcode-tooltip').tooltip({ container: 'body' });
|
||||||
$('.media-type-tooltip').tooltip();
|
$('.media-type-tooltip').tooltip({ container: 'body' });
|
||||||
$('.thumb-tooltip').popover({
|
$('.thumb-tooltip').popover({
|
||||||
html: true,
|
html: true,
|
||||||
container: '#history-modal',
|
container: '#history-modal',
|
||||||
|
@@ -217,10 +217,10 @@ libraries_list_table_options = {
|
|||||||
$('#ajaxMsg').fadeOut();
|
$('#ajaxMsg').fadeOut();
|
||||||
|
|
||||||
// Create the tooltips.
|
// Create the tooltips.
|
||||||
$('.purge-tooltip').tooltip();
|
$('.purge-tooltip').tooltip({ container: 'body' });
|
||||||
$('.edit-tooltip').tooltip();
|
$('.edit-tooltip').tooltip({ container: 'body' });
|
||||||
$('.transcode-tooltip').tooltip();
|
$('.transcode-tooltip').tooltip({ container: 'body' });
|
||||||
$('.media-type-tooltip').tooltip();
|
$('.media-type-tooltip').tooltip({ container: 'body' });
|
||||||
$('.thumb-tooltip').popover({
|
$('.thumb-tooltip').popover({
|
||||||
html: true,
|
html: true,
|
||||||
container: 'body',
|
container: 'body',
|
||||||
|
@@ -220,13 +220,14 @@ users_list_table_options = {
|
|||||||
$('#ajaxMsg').fadeOut();
|
$('#ajaxMsg').fadeOut();
|
||||||
|
|
||||||
// Create the tooltips.
|
// Create the tooltips.
|
||||||
$('.purge-tooltip').tooltip();
|
$('.purge-tooltip').tooltip({ container: 'body' });
|
||||||
$('.edit-tooltip').tooltip();
|
$('.edit-tooltip').tooltip({ container: 'body' });
|
||||||
$('.transcode-tooltip').tooltip();
|
$('.transcode-tooltip').tooltip({ container: 'body' });
|
||||||
$('.media-type-tooltip').tooltip();
|
$('.media-type-tooltip').tooltip({ container: 'body' });
|
||||||
$('.watched-tooltip').tooltip();
|
$('.watched-tooltip').tooltip({ container: 'body' });
|
||||||
$('.thumb-tooltip').popover({
|
$('.thumb-tooltip').popover({
|
||||||
html: true,
|
html: true,
|
||||||
|
container: 'body',
|
||||||
trigger: 'hover',
|
trigger: 'hover',
|
||||||
placement: 'right',
|
placement: 'right',
|
||||||
template: '<div class="popover history-thumbnail-popover" role="tooltip"><div class="arrow" style="top: 50%;"></div><div class="popover-content"></div></div>',
|
template: '<div class="popover history-thumbnail-popover" role="tooltip"><div class="arrow" style="top: 50%;"></div><div class="popover-content"></div></div>',
|
||||||
|
@@ -39,6 +39,7 @@ DOCUMENTATION :: END
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
% if data['library_art']:
|
% if data['library_art']:
|
||||||
<div class="art-face" style="background-image:url(pms_image_proxy?img=${data['library_art']}&width=1920&height=1080)"></div>
|
<div class="art-face" style="background-image:url(pms_image_proxy?img=${data['library_art']}&width=1920&height=1080)"></div>
|
||||||
|
<span class="overlay-refresh-image info-art" title="Refresh background image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
<div class="summary-container">
|
<div class="summary-container">
|
||||||
<div class="summary-navbar">
|
<div class="summary-navbar">
|
||||||
@@ -362,7 +363,7 @@ DOCUMENTATION :: END
|
|||||||
|
|
||||||
// Populate watch time stats
|
// Populate watch time stats
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'get_library_watch_time_stats',
|
url: 'library_watch_time_stats',
|
||||||
async: true,
|
async: true,
|
||||||
data: { section_id: section_id },
|
data: { section_id: section_id },
|
||||||
complete: function(xhr, status) {
|
complete: function(xhr, status) {
|
||||||
@@ -372,7 +373,7 @@ DOCUMENTATION :: END
|
|||||||
|
|
||||||
// Populate user stats
|
// Populate user stats
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'get_library_user_stats',
|
url: 'library_user_stats',
|
||||||
async: true,
|
async: true,
|
||||||
data: { section_id: section_id },
|
data: { section_id: section_id },
|
||||||
complete: function(xhr, status) {
|
complete: function(xhr, status) {
|
||||||
@@ -498,7 +499,7 @@ DOCUMENTATION :: END
|
|||||||
function recentlyWatched() {
|
function recentlyWatched() {
|
||||||
// Populate recently watched
|
// Populate recently watched
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'get_library_recently_watched',
|
url: 'library_recently_watched',
|
||||||
async: true,
|
async: true,
|
||||||
data: {
|
data: {
|
||||||
section_id: section_id,
|
section_id: section_id,
|
||||||
@@ -514,7 +515,7 @@ DOCUMENTATION :: END
|
|||||||
function recentlyAdded() {
|
function recentlyAdded() {
|
||||||
// Populate recently added
|
// Populate recently added
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'get_library_recently_added',
|
url: 'library_recently_added',
|
||||||
async: true,
|
async: true,
|
||||||
data: {
|
data: {
|
||||||
section_id: section_id,
|
section_id: section_id,
|
||||||
|
@@ -60,6 +60,7 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
|
@@ -21,7 +21,33 @@
|
|||||||
<span><i class="fa fa-list-alt"></i> Logs</span>
|
<span><i class="fa fa-list-alt"></i> Logs</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="button-bar">
|
<div class="button-bar">
|
||||||
<button class="btn btn-dark" id="download-plexpylog"><i class="fa fa-download"></i> Download log</button>
|
<div class="btn-group" id="plexpy-log-levels">
|
||||||
|
<label>
|
||||||
|
<select name="plexpy-log-level-filter" id="plexpy-log-level-filter" class="btn" style="color: inherit;">
|
||||||
|
<option value="">All log levels</option>
|
||||||
|
<option disabled>────────────</option>
|
||||||
|
<option value="DEBUG">Debug</option>
|
||||||
|
<option value="INFO">Info</option>
|
||||||
|
<option value="WARN">Warning</option>
|
||||||
|
<option value="ERROR">Error</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group" id="plex-log-levels" style="display: none;">
|
||||||
|
<label>
|
||||||
|
<select name="plex-log-level-filter" id="plex-log-level-filter" class="btn" style="color: inherit;">
|
||||||
|
<option value="">All log levels</option>
|
||||||
|
<option disabled>────────────</option>
|
||||||
|
<option value="DEBUG">Debug</option>
|
||||||
|
<option value="INFO">Info</option>
|
||||||
|
<option value="WARN">Warning</option>
|
||||||
|
<option value="ERROR">Error</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-dark" id="download-plexpylog"><i class="fa fa-download"></i> Download logs</button>
|
||||||
|
<button class="btn btn-dark" id="download-plexserverlog" style="display: none;"><i class="fa fa-download"></i> Download logs</button>
|
||||||
|
<button class="btn btn-dark" id="download-plexscannerlog" style="display: none;"><i class="fa fa-download"></i> Download logs</button>
|
||||||
<button class="btn btn-dark" id="clear-logs"><i class="fa fa-trash-o"></i> Clear logs</button>
|
<button class="btn btn-dark" id="clear-logs"><i class="fa fa-trash-o"></i> Clear logs</button>
|
||||||
<button class="btn btn-dark" id="clear-notify-logs" style="display: none;"><i class="fa fa-trash-o"></i> Clear logs</button>
|
<button class="btn btn-dark" id="clear-notify-logs" style="display: none;"><i class="fa fa-trash-o"></i> Clear logs</button>
|
||||||
<button class="btn btn-dark" id="clear-login-logs" style="display: none;"><i class="fa fa-trash-o"></i> Clear logs</button>
|
<button class="btn btn-dark" id="clear-login-logs" style="display: none;"><i class="fa fa-trash-o"></i> Clear logs</button>
|
||||||
@@ -40,27 +66,25 @@
|
|||||||
<div role="tabpanel" class="tab-pane active" id="tabs-1">
|
<div role="tabpanel" class="tab-pane active" id="tabs-1">
|
||||||
<table class="display" id="log_table" width="100%">
|
<table class="display" id="log_table" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="min-tablet" align="left" id="timestamp">Timestamp</th>
|
<th class="min-tablet" align="left" id="timestamp">Timestamp</th>
|
||||||
<th class="desktop" align="left" id="level">Level</th>
|
<th class="desktop" align="left" id="level">Level</th>
|
||||||
<th class="all" align="left" id="message">Message</th>
|
<th class="all" align="left" id="message">Message</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody></tbody>
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div role="tabpanel" class="tab-pane" id="tabs-2">
|
<div role="tabpanel" class="tab-pane" id="tabs-2">
|
||||||
<table class="display" id="plex_log_table" width="100%">
|
<table class="display" id="plex_log_table" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th align="left" id="plex_timestamp">Timestamp</th>
|
<th align="left" id="plex_timestamp">Timestamp</th>
|
||||||
<th align="left" id="plex_level">Level</th>
|
<th align="left" id="plex_level">Level</th>
|
||||||
<th align="left" id="plex_message">Message</th>
|
<th align="left" id="plex_message">Message</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody></tbody>
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div role="tabpanel" class="tab-pane" id="tabs-3">
|
<div role="tabpanel" class="tab-pane" id="tabs-3">
|
||||||
@@ -114,7 +138,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<div align="center">Refresh rate:
|
<div align="center">
|
||||||
|
Refresh rate:
|
||||||
<select id="refreshrate" onchange="setRefresh()">
|
<select id="refreshrate" onchange="setRefresh()">
|
||||||
<option value="0" selected="selected">No Refresh</option>
|
<option value="0" selected="selected">No Refresh</option>
|
||||||
<option value="5">5 Seconds</option>
|
<option value="5">5 Seconds</option>
|
||||||
@@ -139,21 +164,62 @@
|
|||||||
<script>
|
<script>
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
loadPlexPyLogs();
|
loadPlexPyLogs(selected_log_level);
|
||||||
clearSearchButton('log_table', log_table);
|
clearSearchButton('log_table', log_table);
|
||||||
});
|
});
|
||||||
|
|
||||||
function loadPlexPyLogs() {
|
var log_levels = ['DEBUG', 'INFO', 'WARN', 'ERROR'];
|
||||||
|
|
||||||
|
function bindLogLevelFilter() {
|
||||||
|
clearLogLevelFilter();
|
||||||
|
var log_level_column = this.api().column(1);
|
||||||
|
var select = $('#plex-log-level-filter');
|
||||||
|
select.on('change', function () {
|
||||||
|
var val = $.fn.dataTable.util.escapeRegex(
|
||||||
|
$(this).val()
|
||||||
|
);
|
||||||
|
var search_string = '';
|
||||||
|
var levelIndex = log_levels.indexOf(val);
|
||||||
|
if (levelIndex >= 0) {
|
||||||
|
search_string = '^' + log_levels
|
||||||
|
.slice(levelIndex)
|
||||||
|
.join('|') + '$';
|
||||||
|
}
|
||||||
|
log_level_column
|
||||||
|
.search(search_string, true, false)
|
||||||
|
.draw();
|
||||||
|
}).change();
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearLogLevelFilter() {
|
||||||
|
$('#plex-log-level-filter').off('change');
|
||||||
|
}
|
||||||
|
|
||||||
|
var selected_log_level = null;
|
||||||
|
function loadPlexPyLogs(selected_log_level) {
|
||||||
log_table_options.ajax = {
|
log_table_options.ajax = {
|
||||||
url: "getLog"
|
url: "getLog",
|
||||||
|
type: 'post',
|
||||||
|
data: function (d) {
|
||||||
|
return {
|
||||||
|
json_data: JSON.stringify(d),
|
||||||
|
log_level: selected_log_level
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
log_table = $('#log_table').DataTable(log_table_options);
|
log_table = $('#log_table').DataTable(log_table_options);
|
||||||
|
|
||||||
|
$('#plexpy-log-level-filter').on('change', function () {
|
||||||
|
selected_log_level = $(this).val() || null;
|
||||||
|
log_table.draw();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadPlexLogs() {
|
function loadPlexLogs() {
|
||||||
plex_log_table_options.ajax = {
|
plex_log_table_options.ajax = {
|
||||||
url: "get_plex_log?log_type=server"
|
url: "get_plex_log?log_type=server"
|
||||||
}
|
}
|
||||||
|
plex_log_table_options.initComplete = bindLogLevelFilter;
|
||||||
plex_log_table = $('#plex_log_table').DataTable(plex_log_table_options);
|
plex_log_table = $('#plex_log_table').DataTable(plex_log_table_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,6 +227,7 @@
|
|||||||
plex_log_table_options.ajax = {
|
plex_log_table_options.ajax = {
|
||||||
url: "get_plex_log?log_type=scanner"
|
url: "get_plex_log?log_type=scanner"
|
||||||
}
|
}
|
||||||
|
plex_log_table_options.initComplete = bindLogLevelFilter;
|
||||||
plex_scanner_log_table = $('#plex_scanner_log_table').DataTable(plex_log_table_options);
|
plex_scanner_log_table = $('#plex_scanner_log_table').DataTable(plex_log_table_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,17 +257,25 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$("#plexpy-logs-btn").click(function () {
|
$("#plexpy-logs-btn").click(function () {
|
||||||
|
$("#plexpy-log-levels").show();
|
||||||
|
$("#plex-log-levels").hide();
|
||||||
$("#clear-logs").show();
|
$("#clear-logs").show();
|
||||||
$("#download-plexpylog").show()
|
$("#download-plexpylog").show()
|
||||||
|
$("#download-plexserverlog").hide()
|
||||||
|
$("#download-plexscannerlog").hide()
|
||||||
$("#clear-notify-logs").hide();
|
$("#clear-notify-logs").hide();
|
||||||
$("#clear-login-logs").hide();
|
$("#clear-login-logs").hide();
|
||||||
loadPlexPyLogs();
|
loadPlexPyLogs(selected_log_level);
|
||||||
clearSearchButton('log_table', log_table);
|
clearSearchButton('log_table', log_table);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#plex-logs-btn").click(function () {
|
$("#plex-logs-btn").click(function () {
|
||||||
|
$("#plexpy-log-levels").hide();
|
||||||
|
$("#plex-log-levels").show();
|
||||||
$("#clear-logs").hide();
|
$("#clear-logs").hide();
|
||||||
$("#download-plexpylog").hide()
|
$("#download-plexpylog").hide()
|
||||||
|
$("#download-plexserverlog").show()
|
||||||
|
$("#download-plexscannerlog").hide()
|
||||||
$("#clear-notify-logs").hide();
|
$("#clear-notify-logs").hide();
|
||||||
$("#clear-login-logs").hide();
|
$("#clear-login-logs").hide();
|
||||||
loadPlexLogs();
|
loadPlexLogs();
|
||||||
@@ -208,8 +283,12 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
$("#plex-scanner-logs-btn").click(function () {
|
$("#plex-scanner-logs-btn").click(function () {
|
||||||
|
$("#plexpy-log-levels").hide();
|
||||||
|
$("#plex-log-levels").show();
|
||||||
$("#clear-logs").hide();
|
$("#clear-logs").hide();
|
||||||
$("#download-plexpylog").hide()
|
$("#download-plexpylog").hide()
|
||||||
|
$("#download-plexserverlog").hide()
|
||||||
|
$("#download-plexscannerlog").show()
|
||||||
$("#clear-notify-logs").hide();
|
$("#clear-notify-logs").hide();
|
||||||
$("#clear-login-logs").hide();
|
$("#clear-login-logs").hide();
|
||||||
loadPlexScannerLogs();
|
loadPlexScannerLogs();
|
||||||
@@ -217,8 +296,12 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
$("#notification-logs-btn").click(function () {
|
$("#notification-logs-btn").click(function () {
|
||||||
|
$("#plexpy-log-levels").hide();
|
||||||
|
$("#plex-log-levels").hide();
|
||||||
$("#clear-logs").hide();
|
$("#clear-logs").hide();
|
||||||
$("#download-plexpylog").hide()
|
$("#download-plexpylog").hide()
|
||||||
|
$("#download-plexserverlog").hide()
|
||||||
|
$("#download-plexscannerlog").hide()
|
||||||
$("#clear-notify-logs").show();
|
$("#clear-notify-logs").show();
|
||||||
$("#clear-login-logs").hide();
|
$("#clear-login-logs").hide();
|
||||||
loadNotificationLogs();
|
loadNotificationLogs();
|
||||||
@@ -226,8 +309,12 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
$("#login-logs-btn").click(function () {
|
$("#login-logs-btn").click(function () {
|
||||||
|
$("#plexpy-log-levels").hide();
|
||||||
|
$("#plex-log-levels").hide();
|
||||||
$("#clear-logs").hide();
|
$("#clear-logs").hide();
|
||||||
$("#download-plexpylog").hide()
|
$("#download-plexpylog").hide()
|
||||||
|
$("#download-plexserverlog").hide()
|
||||||
|
$("#download-plexscannerlog").hide()
|
||||||
$("#clear-notify-logs").hide();
|
$("#clear-notify-logs").hide();
|
||||||
$("#clear-login-logs").show();
|
$("#clear-login-logs").show();
|
||||||
loadLoginLogs();
|
loadLoginLogs();
|
||||||
@@ -263,6 +350,13 @@
|
|||||||
window.location.href = "download_log";
|
window.location.href = "download_log";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#download-plexserverlog").click(function () {
|
||||||
|
window.location.href = "download_plex_log?log_type=server";
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#download-plexscannerlog").click(function () {
|
||||||
|
window.location.href = "download_plex_log?log_type=scanner";
|
||||||
|
});
|
||||||
|
|
||||||
$("#clear-notify-logs").click(function () {
|
$("#clear-notify-logs").click(function () {
|
||||||
$("#confirm-message").text("Are you sure you want to clear the PlexPy notification logs?");
|
$("#confirm-message").text("Are you sure you want to clear the PlexPy notification logs?");
|
||||||
|
@@ -49,6 +49,7 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
@@ -69,6 +70,7 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
@@ -91,6 +93,7 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
|
@@ -434,7 +434,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" name="http_proxy http-settings" id="http_proxy" value="1" ${config['http_proxy']}> Enable HTTP Proxy
|
<input type="checkbox" class="http-settings" name="http_proxy" id="http_proxy" value="1" ${config['http_proxy']}> Enable HTTP Proxy
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Respect the X-Forwarded-Proto header. Used for reverse proxies with SSL.</p>
|
<p class="help-block">Respect the X-Forwarded-Proto header. Used for reverse proxies with SSL.</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -528,10 +528,17 @@
|
|||||||
<label>
|
<label>
|
||||||
<input type="checkbox" name="http_hash_password" id="http_hash_password" value="1" ${config['http_hash_password']} data-parsley-trigger="change"> Hash Password in the Config File
|
<input type="checkbox" name="http_hash_password" id="http_hash_password" value="1" ${config['http_hash_password']} data-parsley-trigger="change"> Hash Password in the Config File
|
||||||
</label>
|
</label>
|
||||||
|
<span id="hashPasswordCheck" style="color: #eb8600; padding-left: 10px;"></span>
|
||||||
<p class="help-block">Store a hashed password in the config file.<br />Warning: Your password cannot be recovered if forgotten!</p>
|
<p class="help-block">Store a hashed password in the config file.<br />Warning: Your password cannot be recovered if forgotten!</p>
|
||||||
</div>
|
</div>
|
||||||
<input type="text" id="http_hashed_password" name="http_hashed_password" value="${config['http_hashed_password']}" style="display: none;" data-parsley-trigger="change" data-parsley-type="integer" data-parsley-range="[0, 1]"
|
<input type="text" id="http_hashed_password" name="http_hashed_password" value="${config['http_hashed_password']}" style="display: none;" data-parsley-trigger="change" data-parsley-type="integer" data-parsley-range="[0, 1]"
|
||||||
data-parsley-errors-container="#http_hash_password_error" data-parsley-error-message="Cannot un-hash password, please set a new password." data-parsley-no-focus required>
|
data-parsley-errors-container="#http_hash_password_error" data-parsley-error-message="Cannot un-hash password, please set a new password." data-parsley-no-focus required>
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" class="auth-settings" name="http_basic_auth" id="http_basic_auth" value="1" ${config['http_basic_auth']} data-parsley-trigger="change"> Use Basic Authentication
|
||||||
|
</label>
|
||||||
|
<p class="help-block">Use basic HTTP authentication instead of the HTML login form.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="padded-header">
|
<div class="padded-header">
|
||||||
@@ -566,7 +573,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">Current API key: <strong><br/>${config['api_key']}</strong></p>
|
<p class="help-block">Current API key: <strong> ${config['api_key']}</strong></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
|
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
|
||||||
@@ -1818,6 +1825,26 @@
|
|||||||
<td><strong>{year}</strong></td>
|
<td><strong>{year}</strong></td>
|
||||||
<td>The release year for the item.</td>
|
<td>The release year for the item.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>{release_date}</strong></td>
|
||||||
|
<td>The release date (in date format) for the item.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>{air_date}</strong></td>
|
||||||
|
<td>The air date (in date format) for the item.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>{added_date}</strong></td>
|
||||||
|
<td>The date (in date format) the item was added to Plex.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>{updated_date}</strong></td>
|
||||||
|
<td>The date (in date format) the item was updated on Plex.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>{last_viewed_date}</strong></td>
|
||||||
|
<td>The date (in date format) the item was last viewed on Plex.</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>{studio}</strong></td>
|
<td><strong>{studio}</strong></td>
|
||||||
<td>The studio for the item.</td>
|
<td>The studio for the item.</td>
|
||||||
@@ -2570,7 +2597,11 @@ $(document).ready(function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function allowGuestAccessCheck () {
|
function allowGuestAccessCheck () {
|
||||||
if ($('#http_username').val() == '' || $('#http_password').val() == '') {
|
if ($("#http_basic_auth").is(":checked")) {
|
||||||
|
$("#allow_guest_access").attr("disabled", true);
|
||||||
|
$("#allow_guest_access").attr("checked", false);
|
||||||
|
$("#allowGuestCheck").html("Guest access cannot be enabled with basic authentication.");
|
||||||
|
} else if ($('#http_username').val() == '' || $('#http_password').val() == '') {
|
||||||
$("#allow_guest_access").attr("disabled", true);
|
$("#allow_guest_access").attr("disabled", true);
|
||||||
$("#allow_guest_access").attr("checked", false);
|
$("#allow_guest_access").attr("checked", false);
|
||||||
$("#allowGuestCheck").html("You must set an admin password above to allow guest access.");
|
$("#allowGuestCheck").html("You must set an admin password above to allow guest access.");
|
||||||
@@ -2581,18 +2612,30 @@ $(document).ready(function() {
|
|||||||
}
|
}
|
||||||
allowGuestAccessCheck();
|
allowGuestAccessCheck();
|
||||||
|
|
||||||
$('#http_username, #http_password').change(function () {
|
$('#http_username, #http_password, #http_basic_auth').change(function () {
|
||||||
allowGuestAccessCheck();
|
allowGuestAccessCheck();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function hashPasswordCheck () {
|
||||||
$("#http_hash_password").click(function(){
|
if ($("#http_basic_auth").is(":checked")) {
|
||||||
|
$("#http_hash_password").attr("checked", false);
|
||||||
|
$("#http_hash_password").attr("disabled", true);
|
||||||
|
$("#hashPasswordCheck").html("Password cannot be hashed with basic authentication.");
|
||||||
|
} else {
|
||||||
|
$("#http_hash_password").attr("disabled", false);
|
||||||
|
$("#hashPasswordCheck").html("");
|
||||||
|
}
|
||||||
if (!($("#http_hash_password").is(":checked")) && $("#http_hashed_password").val() == "1" && $("#http_password").val() == " ") {
|
if (!($("#http_hash_password").is(":checked")) && $("#http_hashed_password").val() == "1" && $("#http_password").val() == " ") {
|
||||||
$("#http_hashed_password").val(-1);
|
$("#http_hashed_password").val(-1);
|
||||||
} else if ($("#http_hash_password").is(":checked") && $("#http_hashed_password").val() == "-1" && $("#http_password").val() == " ") {
|
} else if ($("#http_hash_password").is(":checked") && $("#http_hashed_password").val() == "-1" && $("#http_password").val() == " ") {
|
||||||
$("#http_hashed_password").val(1);
|
$("#http_hashed_password").val(1);
|
||||||
$("#http_hash_password_error").html("");
|
$("#http_hash_password_error").html("");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
hashPasswordCheck();
|
||||||
|
|
||||||
|
$('#http_password, #http_hash_password, #http_basic_auth').change(function () {
|
||||||
|
hashPasswordCheck();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#http_password').change(function () {
|
$('#http_password').change(function () {
|
||||||
|
@@ -383,7 +383,7 @@ DOCUMENTATION :: END
|
|||||||
|
|
||||||
// Populate watch time stats
|
// Populate watch time stats
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'get_user_watch_time_stats',
|
url: 'user_watch_time_stats',
|
||||||
async: true,
|
async: true,
|
||||||
data: { user_id: user_id, user: username },
|
data: { user_id: user_id, user: username },
|
||||||
complete: function(xhr, status) {
|
complete: function(xhr, status) {
|
||||||
@@ -393,7 +393,7 @@ DOCUMENTATION :: END
|
|||||||
|
|
||||||
// Populate platform stats
|
// Populate platform stats
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'get_user_player_stats',
|
url: 'user_player_stats',
|
||||||
async: true,
|
async: true,
|
||||||
data: { user_id: user_id, user: username },
|
data: { user_id: user_id, user: username },
|
||||||
complete: function(xhr, status) {
|
complete: function(xhr, status) {
|
||||||
|
@@ -49,6 +49,7 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
# default. Do not sets it as empty or it will run
|
# default. Do not sets it as empty or it will run
|
||||||
# as root.
|
# as root.
|
||||||
# plexpy_dir: Directory where PlexPy lives.
|
# plexpy_dir: Directory where PlexPy lives.
|
||||||
# Default: /usr/local/plexpy
|
# Default: /usr/local/share/plexpy
|
||||||
# plexpy_chdir: Change to this directory before running PlexPy.
|
# plexpy_chdir: Change to this directory before running PlexPy.
|
||||||
# Default is same as plexpy_dir.
|
# Default is same as plexpy_dir.
|
||||||
# plexpy_pid: The name of the pidfile to create.
|
# plexpy_pid: The name of the pidfile to create.
|
||||||
@@ -30,7 +30,7 @@ load_rc_config ${name}
|
|||||||
|
|
||||||
: ${plexpy_enable:="NO"}
|
: ${plexpy_enable:="NO"}
|
||||||
: ${plexpy_user:="_sabnzbd"}
|
: ${plexpy_user:="_sabnzbd"}
|
||||||
: ${plexpy_dir:="/usr/local/plexpy"}
|
: ${plexpy_dir:="/usr/local/share/plexpy"}
|
||||||
: ${plexpy_chdir:="${plexpy_dir}"}
|
: ${plexpy_chdir:="${plexpy_dir}"}
|
||||||
: ${plexpy_pid:="${plexpy_dir}/plexpy.pid"}
|
: ${plexpy_pid:="${plexpy_dir}/plexpy.pid"}
|
||||||
: ${plexpy_flags:=""}
|
: ${plexpy_flags:=""}
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
# default. Do not sets it as empty or it will run
|
# default. Do not sets it as empty or it will run
|
||||||
# as root.
|
# as root.
|
||||||
# plexpy_dir: Directory where PlexPy lives.
|
# plexpy_dir: Directory where PlexPy lives.
|
||||||
# Default: /usr/local/plexpy
|
# Default: /usr/local/share/plexpy
|
||||||
# plexpy_chdir: Change to this directory before running PlexPy.
|
# plexpy_chdir: Change to this directory before running PlexPy.
|
||||||
# Default is same as plexpy_dir.
|
# Default is same as plexpy_dir.
|
||||||
# plexpy_pid: The name of the pidfile to create.
|
# plexpy_pid: The name of the pidfile to create.
|
||||||
|
@@ -48,9 +48,10 @@ class ActivityHandler(object):
|
|||||||
pms_connect = pmsconnect.PmsConnect()
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
session_list = pms_connect.get_current_activity()
|
session_list = pms_connect.get_current_activity()
|
||||||
|
|
||||||
for session in session_list['sessions']:
|
if session_list:
|
||||||
if int(session['session_key']) == self.get_session_key():
|
for session in session_list['sessions']:
|
||||||
return session
|
if int(session['session_key']) == self.get_session_key():
|
||||||
|
return session
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@@ -46,6 +46,7 @@ _CONFIG_DEFINITIONS = {
|
|||||||
'PMS_IP': (str, 'PMS', '127.0.0.1'),
|
'PMS_IP': (str, 'PMS', '127.0.0.1'),
|
||||||
'PMS_IS_REMOTE': (int, 'PMS', 0),
|
'PMS_IS_REMOTE': (int, 'PMS', 0),
|
||||||
'PMS_LOGS_FOLDER': (str, 'PMS', ''),
|
'PMS_LOGS_FOLDER': (str, 'PMS', ''),
|
||||||
|
'PMS_LOGS_LINE_CAP': (int, 'PMS', 1000),
|
||||||
'PMS_NAME': (unicode, 'PMS', ''),
|
'PMS_NAME': (unicode, 'PMS', ''),
|
||||||
'PMS_PORT': (int, 'PMS', 32400),
|
'PMS_PORT': (int, 'PMS', 32400),
|
||||||
'PMS_TOKEN': (str, 'PMS', ''),
|
'PMS_TOKEN': (str, 'PMS', ''),
|
||||||
@@ -185,6 +186,7 @@ _CONFIG_DEFINITIONS = {
|
|||||||
'HTTPS_KEY': (str, 'General', ''),
|
'HTTPS_KEY': (str, 'General', ''),
|
||||||
'HTTPS_DOMAIN': (str, 'General', 'localhost'),
|
'HTTPS_DOMAIN': (str, 'General', 'localhost'),
|
||||||
'HTTPS_IP': (str, 'General', '127.0.0.1'),
|
'HTTPS_IP': (str, 'General', '127.0.0.1'),
|
||||||
|
'HTTP_BASIC_AUTH': (int, 'General', 0),
|
||||||
'HTTP_ENVIRONMENT': (str, 'General', 'production'),
|
'HTTP_ENVIRONMENT': (str, 'General', 'production'),
|
||||||
'HTTP_HASH_PASSWORD': (int, 'General', 0),
|
'HTTP_HASH_PASSWORD': (int, 'General', 0),
|
||||||
'HTTP_HASHED_PASSWORD': (int, 'General', 0),
|
'HTTP_HASHED_PASSWORD': (int, 'General', 0),
|
||||||
|
@@ -727,6 +727,16 @@ def build_notify_text(session=None, timeline=None, notify_action=None, agent_id=
|
|||||||
'track_num': metadata['media_index'].zfill(1),
|
'track_num': metadata['media_index'].zfill(1),
|
||||||
'track_num00': metadata['media_index'].zfill(2),
|
'track_num00': metadata['media_index'].zfill(2),
|
||||||
'year': metadata['year'],
|
'year': metadata['year'],
|
||||||
|
'release_date': arrow.get(metadata['originally_available_at']).format(date_format)
|
||||||
|
if metadata['originally_available_at'] else '',
|
||||||
|
'air_date': arrow.get(metadata['originally_available_at']).format(date_format)
|
||||||
|
if metadata['originally_available_at'] else '',
|
||||||
|
'added_date': arrow.get(metadata['added_at']).format(date_format)
|
||||||
|
if metadata['added_at'] else '',
|
||||||
|
'updated_date': arrow.get(metadata['updated_at']).format(date_format)
|
||||||
|
if metadata['updated_at'] else '',
|
||||||
|
'last_viewed_date': arrow.get(metadata['last_viewed_at']).format(date_format)
|
||||||
|
if metadata['last_viewed_at'] else '',
|
||||||
'studio': metadata['studio'],
|
'studio': metadata['studio'],
|
||||||
'content_rating': metadata['content_rating'],
|
'content_rating': metadata['content_rating'],
|
||||||
'directors': ', '.join(metadata['directors']),
|
'directors': ', '.join(metadata['directors']),
|
||||||
|
@@ -100,6 +100,7 @@ def extract_plexivity_xml(xml=None):
|
|||||||
video_resolution = helpers.get_xml_attr(c, 'videoResolution')
|
video_resolution = helpers.get_xml_attr(c, 'videoResolution')
|
||||||
width = helpers.get_xml_attr(c, 'width')
|
width = helpers.get_xml_attr(c, 'width')
|
||||||
|
|
||||||
|
ip_address = ''
|
||||||
machine_id = ''
|
machine_id = ''
|
||||||
platform = ''
|
platform = ''
|
||||||
player = ''
|
player = ''
|
||||||
@@ -107,7 +108,7 @@ def extract_plexivity_xml(xml=None):
|
|||||||
if a.getElementsByTagName('Player'):
|
if a.getElementsByTagName('Player'):
|
||||||
player_elem = a.getElementsByTagName('Player')
|
player_elem = a.getElementsByTagName('Player')
|
||||||
for d in player_elem:
|
for d in player_elem:
|
||||||
ip_address = helpers.get_xml_attr(d, 'address')
|
ip_address = helpers.get_xml_attr(d, 'address').split('::ffff:')[-1]
|
||||||
machine_id = helpers.get_xml_attr(d, 'machineIdentifier')
|
machine_id = helpers.get_xml_attr(d, 'machineIdentifier')
|
||||||
platform = helpers.get_xml_attr(d, 'platform')
|
platform = helpers.get_xml_attr(d, 'platform')
|
||||||
player = helpers.get_xml_attr(d, 'title')
|
player = helpers.get_xml_attr(d, 'title')
|
||||||
|
@@ -44,7 +44,11 @@ def refresh_users():
|
|||||||
if user_tokens and user_tokens['server_token']:
|
if user_tokens and user_tokens['server_token']:
|
||||||
pms_connect = pmsconnect.PmsConnect(token=user_tokens['server_token'])
|
pms_connect = pmsconnect.PmsConnect(token=user_tokens['server_token'])
|
||||||
library_details = pms_connect.get_server_children()
|
library_details = pms_connect.get_server_children()
|
||||||
shared_libraries = ';'.join(d['section_id'] for d in library_details['libraries_list'])
|
|
||||||
|
if library_details:
|
||||||
|
shared_libraries = ';'.join(d['section_id'] for d in library_details['libraries_list'])
|
||||||
|
else:
|
||||||
|
shared_libraries = ''
|
||||||
|
|
||||||
control_value_dict = {"user_id": item['user_id']}
|
control_value_dict = {"user_id": item['user_id']}
|
||||||
new_value_dict = {"username": item['username'],
|
new_value_dict = {"username": item['username'],
|
||||||
@@ -108,7 +112,8 @@ def get_real_pms_url():
|
|||||||
|
|
||||||
if connections:
|
if connections:
|
||||||
# Get connection with matching address, otherwise return first connection
|
# Get connection with matching address, otherwise return first connection
|
||||||
conn = next((c for c in connections if c['address'] == plexpy.CONFIG.PMS_IP), connections[0])
|
conn = next((c for c in connections if c['address'] == plexpy.CONFIG.PMS_IP
|
||||||
|
and c['port'] == str(plexpy.CONFIG.PMS_PORT)), connections[0])
|
||||||
plexpy.CONFIG.__setattr__('PMS_URL', conn['uri'])
|
plexpy.CONFIG.__setattr__('PMS_URL', conn['uri'])
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
logger.info(u"PlexPy PlexTV :: Server URL retrieved.")
|
logger.info(u"PlexPy PlexTV :: Server URL retrieved.")
|
||||||
@@ -142,13 +147,15 @@ class PlexTV(object):
|
|||||||
if session.get_session_user_id():
|
if session.get_session_user_id():
|
||||||
user_data = users.Users()
|
user_data = users.Users()
|
||||||
user_tokens = user_data.get_tokens(user_id=session.get_session_user_id())
|
user_tokens = user_data.get_tokens(user_id=session.get_session_user_id())
|
||||||
token = user_tokens['server_token']
|
self.token = user_tokens['server_token']
|
||||||
else:
|
else:
|
||||||
token = plexpy.CONFIG.PMS_TOKEN
|
self.token = plexpy.CONFIG.PMS_TOKEN
|
||||||
|
else:
|
||||||
|
self.token = token
|
||||||
|
|
||||||
self.request_handler = http_handler.HTTPHandler(host='plex.tv',
|
self.request_handler = http_handler.HTTPHandler(host='plex.tv',
|
||||||
port=443,
|
port=443,
|
||||||
token=token,
|
token=self.token,
|
||||||
ssl_verify=self.ssl_verify)
|
ssl_verify=self.ssl_verify)
|
||||||
|
|
||||||
def get_plex_auth(self, output_format='raw'):
|
def get_plex_auth(self, output_format='raw'):
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import threading
|
import threading
|
||||||
import urllib2
|
import urllib
|
||||||
from urlparse import urlparse
|
from urlparse import urlparse
|
||||||
|
|
||||||
import plexpy
|
import plexpy
|
||||||
@@ -121,13 +121,15 @@ class PmsConnect(object):
|
|||||||
if session.get_session_user_id():
|
if session.get_session_user_id():
|
||||||
user_data = users.Users()
|
user_data = users.Users()
|
||||||
user_tokens = user_data.get_tokens(user_id=session.get_session_user_id())
|
user_tokens = user_data.get_tokens(user_id=session.get_session_user_id())
|
||||||
token = user_tokens['server_token']
|
self.token = user_tokens['server_token']
|
||||||
else:
|
else:
|
||||||
token = plexpy.CONFIG.PMS_TOKEN
|
self.token = plexpy.CONFIG.PMS_TOKEN
|
||||||
|
else:
|
||||||
|
self.token = token
|
||||||
|
|
||||||
self.request_handler = http_handler.HTTPHandler(host=hostname,
|
self.request_handler = http_handler.HTTPHandler(host=hostname,
|
||||||
port=port,
|
port=port,
|
||||||
token=token)
|
token=self.token)
|
||||||
|
|
||||||
def get_sessions(self, output_format=''):
|
def get_sessions(self, output_format=''):
|
||||||
"""
|
"""
|
||||||
@@ -387,7 +389,7 @@ class PmsConnect(object):
|
|||||||
|
|
||||||
Output: array
|
Output: array
|
||||||
"""
|
"""
|
||||||
uri = '/search?query=' + urllib2.quote(query.encode('utf8')) + track
|
uri = '/search?query=' + urllib.quote(query.encode('utf8')) + track
|
||||||
request = self.request_handler.make_request(uri=uri,
|
request = self.request_handler.make_request(uri=uri,
|
||||||
proto=self.protocol,
|
proto=self.protocol,
|
||||||
request_type='GET',
|
request_type='GET',
|
||||||
@@ -1021,6 +1023,8 @@ class PmsConnect(object):
|
|||||||
session_output = self.get_session_each(session_type, session_)
|
session_output = self.get_session_each(session_type, session_)
|
||||||
session_list.append(session_output)
|
session_list.append(session_output)
|
||||||
|
|
||||||
|
session_list = sorted(session_list, key=lambda k: k['session_key'])
|
||||||
|
|
||||||
output = {'stream_count': helpers.get_xml_attr(xml_head[0], 'size'),
|
output = {'stream_count': helpers.get_xml_attr(xml_head[0], 'size'),
|
||||||
'sessions': session.mask_session_info(session_list)
|
'sessions': session.mask_session_info(session_list)
|
||||||
}
|
}
|
||||||
@@ -1902,10 +1906,12 @@ class PmsConnect(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if img:
|
if img:
|
||||||
uri = '/photo/:/transcode?url=http://127.0.0.1:32400%s' % img
|
params = {'url': 'http://127.0.0.1:32400%s?%s' % (img, urllib.urlencode({'X-Plex-Token': self.token}))}
|
||||||
if width.isdigit() and height.isdigit():
|
if width.isdigit() and height.isdigit():
|
||||||
uri += '&width=%s&height=%s' % (width, height)
|
params['width'] = width
|
||||||
|
params['height'] = height
|
||||||
|
|
||||||
|
uri = '/photo/:/transcode?%s' % urllib.urlencode(params)
|
||||||
result = self.request_handler.make_request(uri=uri,
|
result = self.request_handler.make_request(uri=uri,
|
||||||
proto=self.protocol,
|
proto=self.protocol,
|
||||||
request_type='GET',
|
request_type='GET',
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
PLEXPY_VERSION = "master"
|
PLEXPY_VERSION = "master"
|
||||||
PLEXPY_RELEASE_VERSION = "1.4.1"
|
PLEXPY_RELEASE_VERSION = "1.4.6"
|
||||||
|
@@ -86,7 +86,7 @@ def run():
|
|||||||
|
|
||||||
# successfully received data, reset reconnects counter
|
# successfully received data, reset reconnects counter
|
||||||
reconnects = 0
|
reconnects = 0
|
||||||
except websocket.WebSocketConnectionClosedException:
|
except (websocket.WebSocketConnectionClosedException, Exception):
|
||||||
if reconnects <= 15:
|
if reconnects <= 15:
|
||||||
reconnects += 1
|
reconnects += 1
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ def run():
|
|||||||
if reconnects > 1:
|
if reconnects > 1:
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
logger.warn(u"PlexPy WebSocket :: Connection has closed, reconnecting...")
|
logger.warn(u"PlexPy WebSocket :: Connection has closed, reconnection attempt %s." % reconnects)
|
||||||
try:
|
try:
|
||||||
ws = create_connection(uri, header=header)
|
ws = create_connection(uri, header=header)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
|
@@ -34,6 +34,7 @@ import config
|
|||||||
import database
|
import database
|
||||||
import datafactory
|
import datafactory
|
||||||
import graphs
|
import graphs
|
||||||
|
import helpers
|
||||||
import http_handler
|
import http_handler
|
||||||
import libraries
|
import libraries
|
||||||
import log_reader
|
import log_reader
|
||||||
@@ -477,9 +478,9 @@ class WebInterface(object):
|
|||||||
"get_file_sizes_hold": plexpy.CONFIG.GET_FILE_SIZES_HOLD
|
"get_file_sizes_hold": plexpy.CONFIG.GET_FILE_SIZES_HOLD
|
||||||
}
|
}
|
||||||
|
|
||||||
library_data = libraries.Libraries()
|
|
||||||
if section_id:
|
if section_id:
|
||||||
try:
|
try:
|
||||||
|
library_data = libraries.Libraries()
|
||||||
library_details = library_data.get_details(section_id=section_id)
|
library_details = library_data.get_details(section_id=section_id)
|
||||||
except:
|
except:
|
||||||
logger.warn(u"Unable to retrieve library details for section_id %s " % section_id)
|
logger.warn(u"Unable to retrieve library details for section_id %s " % section_id)
|
||||||
@@ -493,8 +494,8 @@ class WebInterface(object):
|
|||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
def edit_library_dialog(self, section_id=None, **kwargs):
|
def edit_library_dialog(self, section_id=None, **kwargs):
|
||||||
library_data = libraries.Libraries()
|
|
||||||
if section_id:
|
if section_id:
|
||||||
|
library_data = libraries.Libraries()
|
||||||
result = library_data.get_details(section_id=section_id)
|
result = library_data.get_details(section_id=section_id)
|
||||||
status_message = ''
|
status_message = ''
|
||||||
else:
|
else:
|
||||||
@@ -528,9 +529,9 @@ class WebInterface(object):
|
|||||||
do_notify_created = kwargs.get('do_notify_created', 0)
|
do_notify_created = kwargs.get('do_notify_created', 0)
|
||||||
keep_history = kwargs.get('keep_history', 0)
|
keep_history = kwargs.get('keep_history', 0)
|
||||||
|
|
||||||
library_data = libraries.Libraries()
|
|
||||||
if section_id:
|
if section_id:
|
||||||
try:
|
try:
|
||||||
|
library_data = libraries.Libraries()
|
||||||
library_data.set_config(section_id=section_id,
|
library_data.set_config(section_id=section_id,
|
||||||
custom_thumb=custom_thumb,
|
custom_thumb=custom_thumb,
|
||||||
do_notify=do_notify,
|
do_notify=do_notify,
|
||||||
@@ -543,7 +544,7 @@ class WebInterface(object):
|
|||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
def get_library_watch_time_stats(self, section_id=None, **kwargs):
|
def library_watch_time_stats(self, section_id=None, **kwargs):
|
||||||
if not allow_session_library(section_id):
|
if not allow_session_library(section_id):
|
||||||
return serve_template(templatename="user_watch_time_stats.html", data=None, title="Watch Stats")
|
return serve_template(templatename="user_watch_time_stats.html", data=None, title="Watch Stats")
|
||||||
|
|
||||||
@@ -556,12 +557,12 @@ class WebInterface(object):
|
|||||||
if result:
|
if result:
|
||||||
return serve_template(templatename="user_watch_time_stats.html", data=result, title="Watch Stats")
|
return serve_template(templatename="user_watch_time_stats.html", data=result, title="Watch Stats")
|
||||||
else:
|
else:
|
||||||
logger.warn(u"Unable to retrieve data for get_library_watch_time_stats.")
|
logger.warn(u"Unable to retrieve data for library_watch_time_stats.")
|
||||||
return serve_template(templatename="user_watch_time_stats.html", data=None, title="Watch Stats")
|
return serve_template(templatename="user_watch_time_stats.html", data=None, title="Watch Stats")
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
def get_library_user_stats(self, section_id=None, **kwargs):
|
def library_user_stats(self, section_id=None, **kwargs):
|
||||||
if not allow_session_library(section_id):
|
if not allow_session_library(section_id):
|
||||||
return serve_template(templatename="library_user_stats.html", data=None, title="Player Stats")
|
return serve_template(templatename="library_user_stats.html", data=None, title="Player Stats")
|
||||||
|
|
||||||
@@ -574,12 +575,12 @@ class WebInterface(object):
|
|||||||
if result:
|
if result:
|
||||||
return serve_template(templatename="library_user_stats.html", data=result, title="Player Stats")
|
return serve_template(templatename="library_user_stats.html", data=result, title="Player Stats")
|
||||||
else:
|
else:
|
||||||
logger.warn(u"Unable to retrieve data for get_library_user_stats.")
|
logger.warn(u"Unable to retrieve data for library_user_stats.")
|
||||||
return serve_template(templatename="library_user_stats.html", data=None, title="Player Stats")
|
return serve_template(templatename="library_user_stats.html", data=None, title="Player Stats")
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
def get_library_recently_watched(self, section_id=None, limit='10', **kwargs):
|
def library_recently_watched(self, section_id=None, limit='10', **kwargs):
|
||||||
if not allow_session_library(section_id):
|
if not allow_session_library(section_id):
|
||||||
return serve_template(templatename="user_recently_watched.html", data=None, title="Recently Watched")
|
return serve_template(templatename="user_recently_watched.html", data=None, title="Recently Watched")
|
||||||
|
|
||||||
@@ -592,12 +593,12 @@ class WebInterface(object):
|
|||||||
if result:
|
if result:
|
||||||
return serve_template(templatename="user_recently_watched.html", data=result, title="Recently Watched")
|
return serve_template(templatename="user_recently_watched.html", data=result, title="Recently Watched")
|
||||||
else:
|
else:
|
||||||
logger.warn(u"Unable to retrieve data for get_library_recently_watched.")
|
logger.warn(u"Unable to retrieve data for library_recently_watched.")
|
||||||
return serve_template(templatename="user_recently_watched.html", data=None, title="Recently Watched")
|
return serve_template(templatename="user_recently_watched.html", data=None, title="Recently Watched")
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
def get_library_recently_added(self, section_id=None, limit='10', **kwargs):
|
def library_recently_added(self, section_id=None, limit='10', **kwargs):
|
||||||
if not allow_session_library(section_id):
|
if not allow_session_library(section_id):
|
||||||
return serve_template(templatename="library_recently_added.html", data=None, title="Recently Added")
|
return serve_template(templatename="library_recently_added.html", data=None, title="Recently Added")
|
||||||
|
|
||||||
@@ -610,7 +611,7 @@ class WebInterface(object):
|
|||||||
if result:
|
if result:
|
||||||
return serve_template(templatename="library_recently_added.html", data=result['recently_added'], title="Recently Added")
|
return serve_template(templatename="library_recently_added.html", data=result['recently_added'], title="Recently Added")
|
||||||
else:
|
else:
|
||||||
logger.warn(u"Unable to retrieve data for get_library_recently_added.")
|
logger.warn(u"Unable to retrieve data for library_recently_added.")
|
||||||
return serve_template(templatename="library_recently_added.html", data=None, title="Recently Added")
|
return serve_template(templatename="library_recently_added.html", data=None, title="Recently Added")
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@@ -733,6 +734,132 @@ class WebInterface(object):
|
|||||||
|
|
||||||
return {'success': result}
|
return {'success': result}
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
@cherrypy.tools.json_out()
|
||||||
|
@requireAuth(member_of("admin"))
|
||||||
|
@addtoapi()
|
||||||
|
def get_library(self, section_id=None, **kwargs):
|
||||||
|
""" Get a library's details.
|
||||||
|
|
||||||
|
```
|
||||||
|
Required parameters:
|
||||||
|
section_id (str): The id of the Plex library section
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
None
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
json:
|
||||||
|
{"child_count": null,
|
||||||
|
"count": 887,
|
||||||
|
"do_notify": 1,
|
||||||
|
"do_notify_created": 1,
|
||||||
|
"keep_history": 1,
|
||||||
|
"library_art": "/:/resources/movie-fanart.jpg",
|
||||||
|
"library_thumb": "/:/resources/movie.png",
|
||||||
|
"parent_count": null,
|
||||||
|
"section_id": 1,
|
||||||
|
"section_name": "Movies",
|
||||||
|
"section_type": "movie"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
if section_id:
|
||||||
|
library_data = libraries.Libraries()
|
||||||
|
library_details = library_data.get_details(section_id=section_id)
|
||||||
|
if library_details:
|
||||||
|
return library_details
|
||||||
|
else:
|
||||||
|
logger.warn(u"Unable to retrieve data for get_library.")
|
||||||
|
else:
|
||||||
|
logger.warn(u"Library details requested but no section_id received.")
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
@cherrypy.tools.json_out()
|
||||||
|
@requireAuth(member_of("admin"))
|
||||||
|
@addtoapi()
|
||||||
|
def get_library_watch_time_stats(self, section_id=None, **kwargs):
|
||||||
|
""" Get a library's watch time statistics.
|
||||||
|
|
||||||
|
```
|
||||||
|
Required parameters:
|
||||||
|
section_id (str): The id of the Plex library section
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
None
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
json:
|
||||||
|
[{"query_days": 1,
|
||||||
|
"total_plays": 0,
|
||||||
|
"total_time": 0
|
||||||
|
},
|
||||||
|
{"query_days": 7,
|
||||||
|
"total_plays": 3,
|
||||||
|
"total_time": 15694
|
||||||
|
},
|
||||||
|
{"query_days": 30,
|
||||||
|
"total_plays": 35,
|
||||||
|
"total_time": 63054
|
||||||
|
},
|
||||||
|
{"query_days": 0,
|
||||||
|
"total_plays": 508,
|
||||||
|
"total_time": 1183080
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
if section_id:
|
||||||
|
library_data = libraries.Libraries()
|
||||||
|
result = library_data.get_watch_time_stats(section_id=section_id)
|
||||||
|
if result:
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
logger.warn(u"Unable to retrieve data for get_library_watch_time_stats.")
|
||||||
|
else:
|
||||||
|
logger.warn(u"Library watch time stats requested but no section_id received.")
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
@cherrypy.tools.json_out()
|
||||||
|
@requireAuth(member_of("admin"))
|
||||||
|
@addtoapi()
|
||||||
|
def get_library_user_stats(self, section_id=None, **kwargs):
|
||||||
|
""" Get a library's user statistics.
|
||||||
|
|
||||||
|
```
|
||||||
|
Required parameters:
|
||||||
|
section_id (str): The id of the Plex library section
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
None
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
json:
|
||||||
|
[{"friendly_name": "Jon Snow",
|
||||||
|
"total_plays": 170,
|
||||||
|
"user_id": 133788,
|
||||||
|
"user_thumb": "https://plex.tv/users/k10w42309cynaopq/avatar"
|
||||||
|
},
|
||||||
|
{"platform_type": "DanyKhaleesi69",
|
||||||
|
"total_plays": 42,
|
||||||
|
"user_id": 8008135,
|
||||||
|
"user_thumb": "https://plex.tv/users/568gwwoib5t98a3a/avatar"
|
||||||
|
},
|
||||||
|
{...},
|
||||||
|
{...}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
if section_id:
|
||||||
|
library_data = libraries.Libraries()
|
||||||
|
result = library_data.get_user_stats(section_id=section_id)
|
||||||
|
if result:
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
logger.warn(u"Unable to retrieve data for get_library_user_stats.")
|
||||||
|
else:
|
||||||
|
logger.warn(u"Library user stats requested but no section_id received.")
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@cherrypy.tools.json_out()
|
@cherrypy.tools.json_out()
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@@ -977,9 +1104,9 @@ class WebInterface(object):
|
|||||||
if not allow_session_user(user_id):
|
if not allow_session_user(user_id):
|
||||||
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
|
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
|
||||||
|
|
||||||
user_data = users.Users()
|
|
||||||
if user_id:
|
if user_id:
|
||||||
try:
|
try:
|
||||||
|
user_data = users.Users()
|
||||||
user_details = user_data.get_details(user_id=user_id)
|
user_details = user_data.get_details(user_id=user_id)
|
||||||
except:
|
except:
|
||||||
logger.warn(u"Unable to retrieve user details for user_id %s " % user_id)
|
logger.warn(u"Unable to retrieve user details for user_id %s " % user_id)
|
||||||
@@ -993,8 +1120,8 @@ class WebInterface(object):
|
|||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
def edit_user_dialog(self, user=None, user_id=None, **kwargs):
|
def edit_user_dialog(self, user=None, user_id=None, **kwargs):
|
||||||
user_data = users.Users()
|
|
||||||
if user_id:
|
if user_id:
|
||||||
|
user_data = users.Users()
|
||||||
result = user_data.get_details(user_id=user_id)
|
result = user_data.get_details(user_id=user_id)
|
||||||
status_message = ''
|
status_message = ''
|
||||||
else:
|
else:
|
||||||
@@ -1030,9 +1157,9 @@ class WebInterface(object):
|
|||||||
keep_history = kwargs.get('keep_history', 0)
|
keep_history = kwargs.get('keep_history', 0)
|
||||||
allow_guest = kwargs.get('allow_guest', 0)
|
allow_guest = kwargs.get('allow_guest', 0)
|
||||||
|
|
||||||
user_data = users.Users()
|
|
||||||
if user_id:
|
if user_id:
|
||||||
try:
|
try:
|
||||||
|
user_data = users.Users()
|
||||||
user_data.set_config(user_id=user_id,
|
user_data.set_config(user_id=user_id,
|
||||||
friendly_name=friendly_name,
|
friendly_name=friendly_name,
|
||||||
custom_thumb=custom_thumb,
|
custom_thumb=custom_thumb,
|
||||||
@@ -1047,7 +1174,7 @@ class WebInterface(object):
|
|||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
def get_user_watch_time_stats(self, user=None, user_id=None, **kwargs):
|
def user_watch_time_stats(self, user=None, user_id=None, **kwargs):
|
||||||
if not allow_session_user(user_id):
|
if not allow_session_user(user_id):
|
||||||
return serve_template(templatename="user_watch_time_stats.html", data=None, title="Watch Stats")
|
return serve_template(templatename="user_watch_time_stats.html", data=None, title="Watch Stats")
|
||||||
|
|
||||||
@@ -1060,12 +1187,12 @@ class WebInterface(object):
|
|||||||
if result:
|
if result:
|
||||||
return serve_template(templatename="user_watch_time_stats.html", data=result, title="Watch Stats")
|
return serve_template(templatename="user_watch_time_stats.html", data=result, title="Watch Stats")
|
||||||
else:
|
else:
|
||||||
logger.warn(u"Unable to retrieve data for get_user_watch_time_stats.")
|
logger.warn(u"Unable to retrieve data for user_watch_time_stats.")
|
||||||
return serve_template(templatename="user_watch_time_stats.html", data=None, title="Watch Stats")
|
return serve_template(templatename="user_watch_time_stats.html", data=None, title="Watch Stats")
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
def get_user_player_stats(self, user=None, user_id=None, **kwargs):
|
def user_player_stats(self, user=None, user_id=None, **kwargs):
|
||||||
if not allow_session_user(user_id):
|
if not allow_session_user(user_id):
|
||||||
return serve_template(templatename="user_player_stats.html", data=None, title="Player Stats")
|
return serve_template(templatename="user_player_stats.html", data=None, title="Player Stats")
|
||||||
|
|
||||||
@@ -1078,7 +1205,7 @@ class WebInterface(object):
|
|||||||
if result:
|
if result:
|
||||||
return serve_template(templatename="user_player_stats.html", data=result, title="Player Stats")
|
return serve_template(templatename="user_player_stats.html", data=result, title="Player Stats")
|
||||||
else:
|
else:
|
||||||
logger.warn(u"Unable to retrieve data for get_user_player_stats.")
|
logger.warn(u"Unable to retrieve data for user_player_stats.")
|
||||||
return serve_template(templatename="user_player_stats.html", data=None, title="Player Stats")
|
return serve_template(templatename="user_player_stats.html", data=None, title="Player Stats")
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@@ -1222,6 +1349,134 @@ class WebInterface(object):
|
|||||||
|
|
||||||
return history
|
return history
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
@cherrypy.tools.json_out()
|
||||||
|
@requireAuth(member_of("admin"))
|
||||||
|
@addtoapi()
|
||||||
|
def get_user(self, user_id=None, **kwargs):
|
||||||
|
""" Get a user's details.
|
||||||
|
|
||||||
|
```
|
||||||
|
Required parameters:
|
||||||
|
user_id (str): The id of the Plex user
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
None
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
json:
|
||||||
|
{"allow_guest": 1,
|
||||||
|
"deleted_user": 0,
|
||||||
|
"do_notify": 1,
|
||||||
|
"email": "Jon.Snow.1337@CastleBlack.com",
|
||||||
|
"friendly_name": "Jon Snow",
|
||||||
|
"is_allow_sync": 1,
|
||||||
|
"is_home_user": 1,
|
||||||
|
"is_restricted": 0,
|
||||||
|
"keep_history": 1,
|
||||||
|
"shared_libraries": ["10", "1", "4", "5", "15", "20", "2"],
|
||||||
|
"user_id": 133788,
|
||||||
|
"user_thumb": "https://plex.tv/users/k10w42309cynaopq/avatar",
|
||||||
|
"username": "LordCommanderSnow"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
if user_id:
|
||||||
|
user_data = users.Users()
|
||||||
|
user_details = user_data.get_details(user_id=user_id)
|
||||||
|
if user_details:
|
||||||
|
return user_details
|
||||||
|
else:
|
||||||
|
logger.warn(u"Unable to retrieve data for get_user.")
|
||||||
|
else:
|
||||||
|
logger.warn(u"User details requested but no user_id received.")
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
@cherrypy.tools.json_out()
|
||||||
|
@requireAuth(member_of("admin"))
|
||||||
|
@addtoapi()
|
||||||
|
def get_user_watch_time_stats(self, user_id=None, **kwargs):
|
||||||
|
""" Get a user's watch time statistics.
|
||||||
|
|
||||||
|
```
|
||||||
|
Required parameters:
|
||||||
|
user_id (str): The id of the Plex user
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
None
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
json:
|
||||||
|
[{"query_days": 1,
|
||||||
|
"total_plays": 0,
|
||||||
|
"total_time": 0
|
||||||
|
},
|
||||||
|
{"query_days": 7,
|
||||||
|
"total_plays": 3,
|
||||||
|
"total_time": 15694
|
||||||
|
},
|
||||||
|
{"query_days": 30,
|
||||||
|
"total_plays": 35,
|
||||||
|
"total_time": 63054
|
||||||
|
},
|
||||||
|
{"query_days": 0,
|
||||||
|
"total_plays": 508,
|
||||||
|
"total_time": 1183080
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
if user_id:
|
||||||
|
user_data = users.Users()
|
||||||
|
result = user_data.get_watch_time_stats(user_id=user_id)
|
||||||
|
if result:
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
logger.warn(u"Unable to retrieve data for get_user_watch_time_stats.")
|
||||||
|
else:
|
||||||
|
logger.warn(u"User watch time stats requested but no user_id received.")
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
@cherrypy.tools.json_out()
|
||||||
|
@requireAuth(member_of("admin"))
|
||||||
|
@addtoapi()
|
||||||
|
def get_user_player_stats(self, user_id=None, **kwargs):
|
||||||
|
""" Get a user's player statistics.
|
||||||
|
|
||||||
|
```
|
||||||
|
Required parameters:
|
||||||
|
user_id (str): The id of the Plex user
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
None
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
json:
|
||||||
|
[{"platform_type": "Chrome",
|
||||||
|
"player_name": "Plex Web (Chrome)",
|
||||||
|
"result_id": 1,
|
||||||
|
"total_plays": 170
|
||||||
|
},
|
||||||
|
{"platform_type": "Chromecast",
|
||||||
|
"player_name": "Chromecast",
|
||||||
|
"result_id": 2,
|
||||||
|
"total_plays": 42
|
||||||
|
},
|
||||||
|
{...},
|
||||||
|
{...}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
if user_id:
|
||||||
|
user_data = users.Users()
|
||||||
|
result = user_data.get_player_stats(user_id=user_id)
|
||||||
|
if result:
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
logger.warn(u"Unable to retrieve data for get_user_player_stats.")
|
||||||
|
else:
|
||||||
|
logger.warn(u"User watch time stats requested but no user_id received.")
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@cherrypy.tools.json_out()
|
@cherrypy.tools.json_out()
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@@ -1240,9 +1495,8 @@ class WebInterface(object):
|
|||||||
None
|
None
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
user_data = users.Users()
|
|
||||||
|
|
||||||
if user_id:
|
if user_id:
|
||||||
|
user_data = users.Users()
|
||||||
delete_row = user_data.delete_all_history(user_id=user_id)
|
delete_row = user_data.delete_all_history(user_id=user_id)
|
||||||
if delete_row:
|
if delete_row:
|
||||||
return {'message': delete_row}
|
return {'message': delete_row}
|
||||||
@@ -1267,11 +1521,9 @@ class WebInterface(object):
|
|||||||
None
|
None
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
user_data = users.Users()
|
|
||||||
|
|
||||||
if user_id:
|
if user_id:
|
||||||
|
user_data = users.Users()
|
||||||
delete_row = user_data.delete(user_id=user_id)
|
delete_row = user_data.delete(user_id=user_id)
|
||||||
|
|
||||||
if delete_row:
|
if delete_row:
|
||||||
return {'message': delete_row}
|
return {'message': delete_row}
|
||||||
else:
|
else:
|
||||||
@@ -1296,16 +1548,14 @@ class WebInterface(object):
|
|||||||
None
|
None
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
user_data = users.Users()
|
|
||||||
|
|
||||||
if user_id:
|
if user_id:
|
||||||
|
user_data = users.Users()
|
||||||
delete_row = user_data.undelete(user_id=user_id)
|
delete_row = user_data.undelete(user_id=user_id)
|
||||||
|
|
||||||
if delete_row:
|
if delete_row:
|
||||||
return {'message': delete_row}
|
return {'message': delete_row}
|
||||||
elif username:
|
elif username:
|
||||||
|
user_data = users.Users()
|
||||||
delete_row = user_data.undelete(username=username)
|
delete_row = user_data.undelete(username=username)
|
||||||
|
|
||||||
if delete_row:
|
if delete_row:
|
||||||
return {'message': delete_row}
|
return {'message': delete_row}
|
||||||
else:
|
else:
|
||||||
@@ -1984,13 +2234,15 @@ class WebInterface(object):
|
|||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
def getLog(self, start=0, length=100, **kwargs):
|
def getLog(self, **kwargs):
|
||||||
start = int(start)
|
json_data = helpers.process_json_kwargs(json_kwargs=kwargs.get('json_data'))
|
||||||
length = int(length)
|
log_level = kwargs.get('log_level', "")
|
||||||
order_dir = kwargs.get('order[0][dir]', "desc")
|
|
||||||
order_column = kwargs.get('order[0][column]', "0")
|
start = json_data['start']
|
||||||
search_value = kwargs.get('search[value]', "")
|
length = json_data['length']
|
||||||
search_regex = kwargs.get('search[regex]', "") # Remove?
|
order_column = json_data['order'][0]['column']
|
||||||
|
order_dir = json_data['order'][0]['dir']
|
||||||
|
search_value = json_data['search']['value']
|
||||||
sortcolumn = 0
|
sortcolumn = 0
|
||||||
|
|
||||||
filt = []
|
filt = []
|
||||||
@@ -2001,7 +2253,7 @@ class WebInterface(object):
|
|||||||
try:
|
try:
|
||||||
temp_loglevel_and_time = l.split(' - ', 1)
|
temp_loglevel_and_time = l.split(' - ', 1)
|
||||||
loglvl = temp_loglevel_and_time[1].split(' ::', 1)[0].strip()
|
loglvl = temp_loglevel_and_time[1].split(' ::', 1)[0].strip()
|
||||||
msg = l.split(' : ', 1)[1].replace('\n', '')
|
msg = unicode(l.split(' : ', 1)[1].replace('\n', ''), 'utf-8')
|
||||||
fa([temp_loglevel_and_time[0], loglvl, msg])
|
fa([temp_loglevel_and_time[0], loglvl, msg])
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# Add traceback message to previous msg.
|
# Add traceback message to previous msg.
|
||||||
@@ -2011,10 +2263,15 @@ class WebInterface(object):
|
|||||||
filt[tl][2] += '<br>' + l
|
filt[tl][2] += '<br>' + l
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if search_value == '':
|
log_levels = ['DEBUG', 'INFO', 'WARN', 'ERROR']
|
||||||
filtered = filt
|
if log_level in log_levels:
|
||||||
|
log_levels = log_levels[log_levels.index(log_level)::]
|
||||||
|
filtered = [row for row in filt if row[1] in log_levels]
|
||||||
else:
|
else:
|
||||||
filtered = [row for row in filt for column in row if search_value.lower() in column.lower()]
|
filtered = filt
|
||||||
|
|
||||||
|
if search_value:
|
||||||
|
filtered = [row for row in filtered for column in row if search_value.lower() in column.lower()]
|
||||||
|
|
||||||
if order_column == '1':
|
if order_column == '1':
|
||||||
sortcolumn = 2
|
sortcolumn = 2
|
||||||
@@ -2038,7 +2295,7 @@ class WebInterface(object):
|
|||||||
@cherrypy.tools.json_out()
|
@cherrypy.tools.json_out()
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def get_plex_log(self, window=1000, **kwargs):
|
def get_plex_log(self, **kwargs):
|
||||||
""" Get the PMS logs.
|
""" Get the PMS logs.
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -2060,6 +2317,7 @@ class WebInterface(object):
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
|
window = int(kwargs.get('window', plexpy.CONFIG.PMS_LOGS_LINE_CAP))
|
||||||
log_lines = []
|
log_lines = []
|
||||||
log_type = kwargs.get('log_type', 'server')
|
log_type = kwargs.get('log_type', 'server')
|
||||||
|
|
||||||
@@ -2247,6 +2505,7 @@ class WebInterface(object):
|
|||||||
|
|
||||||
config = {
|
config = {
|
||||||
"allow_guest_access": checked(plexpy.CONFIG.ALLOW_GUEST_ACCESS),
|
"allow_guest_access": checked(plexpy.CONFIG.ALLOW_GUEST_ACCESS),
|
||||||
|
"http_basic_auth": checked(plexpy.CONFIG.HTTP_BASIC_AUTH),
|
||||||
"http_hash_password": checked(plexpy.CONFIG.HTTP_HASH_PASSWORD),
|
"http_hash_password": checked(plexpy.CONFIG.HTTP_HASH_PASSWORD),
|
||||||
"http_hashed_password": plexpy.CONFIG.HTTP_HASHED_PASSWORD,
|
"http_hashed_password": plexpy.CONFIG.HTTP_HASHED_PASSWORD,
|
||||||
"http_host": plexpy.CONFIG.HTTP_HOST,
|
"http_host": plexpy.CONFIG.HTTP_HOST,
|
||||||
@@ -2367,7 +2626,7 @@ class WebInterface(object):
|
|||||||
"ip_logging_enable", "movie_logging_enable", "tv_logging_enable", "music_logging_enable",
|
"ip_logging_enable", "movie_logging_enable", "tv_logging_enable", "music_logging_enable",
|
||||||
"notify_consecutive", "notify_upload_posters", "notify_recently_added", "notify_recently_added_grandparent",
|
"notify_consecutive", "notify_upload_posters", "notify_recently_added", "notify_recently_added_grandparent",
|
||||||
"monitor_pms_updates", "monitor_remote_access", "get_file_sizes", "log_blacklist", "http_hash_password",
|
"monitor_pms_updates", "monitor_remote_access", "get_file_sizes", "log_blacklist", "http_hash_password",
|
||||||
"allow_guest_access", "cache_images", "http_proxy"
|
"allow_guest_access", "cache_images", "http_proxy", "http_basic_auth"
|
||||||
]
|
]
|
||||||
for checked_config in checked_configs:
|
for checked_config in checked_configs:
|
||||||
if checked_config not in kwargs:
|
if checked_config not in kwargs:
|
||||||
@@ -2569,6 +2828,24 @@ class WebInterface(object):
|
|||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
agent_id(str): The id of the notification agent to use
|
agent_id(str): The id of the notification agent to use
|
||||||
|
9 # Boxcar2
|
||||||
|
17 # Browser
|
||||||
|
10 # Email
|
||||||
|
16 # Facebook
|
||||||
|
0 # Growl
|
||||||
|
12 # IFTTT
|
||||||
|
18 # Join
|
||||||
|
4 # NotifyMyAndroid
|
||||||
|
3 # Plex Home Theater
|
||||||
|
1 # Prowl
|
||||||
|
5 # Pushalot
|
||||||
|
6 # Pushbullet
|
||||||
|
7 # Pushover
|
||||||
|
15 # Scripts
|
||||||
|
14 # Slack
|
||||||
|
13 # Telegram
|
||||||
|
11 # Twitter
|
||||||
|
2 # XBMC
|
||||||
subject(str): The subject of the message
|
subject(str): The subject of the message
|
||||||
body(str): The body of the message
|
body(str): The body of the message
|
||||||
|
|
||||||
@@ -2931,13 +3208,17 @@ class WebInterface(object):
|
|||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
def pms_image_proxy(self, img='', rating_key=None, width='0', height='0', fallback=None, **kwargs):
|
def pms_image_proxy(self, img='', rating_key=None, width='0', height='0',
|
||||||
|
fallback=None, refresh=False, **kwargs):
|
||||||
|
|
||||||
""" Gets an image from the PMS and saves it to the image cache directory. """
|
""" Gets an image from the PMS and saves it to the image cache directory. """
|
||||||
|
|
||||||
if not img and not rating_key:
|
if not img and not rating_key:
|
||||||
logger.error('No image input received.')
|
logger.error('No image input received.')
|
||||||
return
|
return
|
||||||
|
|
||||||
|
refresh = True if refresh == 'true' else False
|
||||||
|
|
||||||
if rating_key and not img:
|
if rating_key and not img:
|
||||||
img = '/library/metadata/%s/thumb/1337' % rating_key
|
img = '/library/metadata/%s/thumb/1337' % rating_key
|
||||||
|
|
||||||
@@ -2952,8 +3233,9 @@ class WebInterface(object):
|
|||||||
os.mkdir(c_dir)
|
os.mkdir(c_dir)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if 'indexes' in img:
|
if not plexpy.CONFIG.CACHE_IMAGES or refresh or 'indexes' in img:
|
||||||
raise NotFound
|
raise NotFound
|
||||||
|
|
||||||
return serve_file(path=ffp, content_type='image/jpeg')
|
return serve_file(path=ffp, content_type='image/jpeg')
|
||||||
|
|
||||||
except NotFound:
|
except NotFound:
|
||||||
@@ -2973,7 +3255,7 @@ class WebInterface(object):
|
|||||||
raise Exception(u'PMS image request failed')
|
raise Exception(u'PMS image request failed')
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(u'Failed to get image %s, falling back to %s.' % (img, fallback))
|
logger.warn(u'Failed to get image %s, falling back to %s.' % (img, fallback))
|
||||||
fbi = None
|
fbi = None
|
||||||
if fallback == 'poster':
|
if fallback == 'poster':
|
||||||
fbi = common.DEFAULT_POSTER_THUMB
|
fbi = common.DEFAULT_POSTER_THUMB
|
||||||
@@ -3000,6 +3282,30 @@ class WebInterface(object):
|
|||||||
|
|
||||||
return serve_download(os.path.join(plexpy.CONFIG.LOG_DIR, log_file), name=log_file)
|
return serve_download(os.path.join(plexpy.CONFIG.LOG_DIR, log_file), name=log_file)
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
@requireAuth(member_of("admin"))
|
||||||
|
@addtoapi()
|
||||||
|
def download_plex_log(self, **kwargs):
|
||||||
|
""" Download the Plex log file. """
|
||||||
|
log_type = kwargs.get('log_type', 'server')
|
||||||
|
|
||||||
|
log_file = ""
|
||||||
|
if plexpy.CONFIG.PMS_LOGS_FOLDER:
|
||||||
|
if log_type == "server":
|
||||||
|
log_file = 'Plex Media Server.log'
|
||||||
|
log_file_path = os.path.join(plexpy.CONFIG.PMS_LOGS_FOLDER, log_file)
|
||||||
|
elif log_type == "scanner":
|
||||||
|
log_file = 'Plex Media Scanner.log'
|
||||||
|
log_file_path = os.path.join(plexpy.CONFIG.PMS_LOGS_FOLDER, log_file)
|
||||||
|
else:
|
||||||
|
return "Plex log folder not set in the settings."
|
||||||
|
|
||||||
|
|
||||||
|
if log_file and os.path.isfile(log_file_path):
|
||||||
|
return serve_download(log_file_path, name=log_file)
|
||||||
|
else:
|
||||||
|
return "Plex %s log file not found." % log_type
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@cherrypy.tools.json_out()
|
@cherrypy.tools.json_out()
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@@ -3609,19 +3915,22 @@ class WebInterface(object):
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
pms_connect = pmsconnect.PmsConnect(token=plexpy.CONFIG.PMS_TOKEN)
|
try:
|
||||||
result = pms_connect.get_current_activity()
|
pms_connect = pmsconnect.PmsConnect(token=plexpy.CONFIG.PMS_TOKEN)
|
||||||
|
result = pms_connect.get_current_activity()
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
data_factory = datafactory.DataFactory()
|
data_factory = datafactory.DataFactory()
|
||||||
for session in result['sessions']:
|
for session in result['sessions']:
|
||||||
if not session['ip_address']:
|
if not session['ip_address']:
|
||||||
ip_address = data_factory.get_session_ip(session['session_key'])
|
ip_address = data_factory.get_session_ip(session['session_key'])
|
||||||
session['ip_address'] = ip_address
|
session['ip_address'] = ip_address
|
||||||
|
|
||||||
return result
|
return result
|
||||||
else:
|
else:
|
||||||
logger.warn(u"Unable to retrieve data for get_activity.")
|
logger.warn(u"Unable to retrieve data for get_activity.")
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(u"Unable to retrieve data for get_activity: %s" % e)
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@cherrypy.tools.json_out()
|
@cherrypy.tools.json_out()
|
||||||
|
@@ -66,10 +66,15 @@ def initialize(options):
|
|||||||
|
|
||||||
if options['http_password']:
|
if options['http_password']:
|
||||||
logger.info(u"PlexPy WebStart :: Web server authentication is enabled, username is '%s'", options['http_username'])
|
logger.info(u"PlexPy WebStart :: Web server authentication is enabled, username is '%s'", options['http_username'])
|
||||||
options_dict['tools.sessions.on'] = auth_enabled = session_enabled = True
|
if options['http_basic_auth']:
|
||||||
cherrypy.tools.auth = cherrypy.Tool('before_handler', webauth.check_auth)
|
auth_enabled = session_enabled = False
|
||||||
|
basic_auth_enabled = True
|
||||||
|
else:
|
||||||
|
options_dict['tools.sessions.on'] = auth_enabled = session_enabled = True
|
||||||
|
basic_auth_enabled = False
|
||||||
|
cherrypy.tools.auth = cherrypy.Tool('before_handler', webauth.check_auth)
|
||||||
else:
|
else:
|
||||||
auth_enabled = session_enabled = False
|
auth_enabled = session_enabled = basic_auth_enabled = False
|
||||||
|
|
||||||
if not options['http_root'] or options['http_root'] == '/':
|
if not options['http_root'] or options['http_root'] == '/':
|
||||||
plexpy.HTTP_ROOT = options['http_root'] = '/'
|
plexpy.HTTP_ROOT = options['http_root'] = '/'
|
||||||
@@ -88,7 +93,14 @@ def initialize(options):
|
|||||||
'application/javascript'],
|
'application/javascript'],
|
||||||
'tools.auth.on': auth_enabled,
|
'tools.auth.on': auth_enabled,
|
||||||
'tools.sessions.on': session_enabled,
|
'tools.sessions.on': session_enabled,
|
||||||
'tools.sessions.timeout': 30 * 24 * 60 # 30 days
|
'tools.sessions.timeout': 30 * 24 * 60, # 30 days
|
||||||
|
'tools.auth_basic.on': basic_auth_enabled,
|
||||||
|
'tools.auth_basic.realm': 'PlexPy web server',
|
||||||
|
'tools.auth_basic.checkpassword': cherrypy.lib.auth_basic.checkpassword_dict({
|
||||||
|
options['http_username']: options['http_password']})
|
||||||
|
},
|
||||||
|
'/api': {
|
||||||
|
'tools.auth_basic.on': False
|
||||||
},
|
},
|
||||||
'/interfaces': {
|
'/interfaces': {
|
||||||
'tools.staticdir.on': True,
|
'tools.staticdir.on': True,
|
||||||
@@ -178,17 +190,17 @@ def initialize(options):
|
|||||||
'tools.auth.on': False,
|
'tools.auth.on': False,
|
||||||
'tools.sessions.on': False
|
'tools.sessions.on': False
|
||||||
},
|
},
|
||||||
'/pms_image_proxy': {
|
#'/pms_image_proxy': {
|
||||||
'tools.staticdir.on': True,
|
# 'tools.staticdir.on': True,
|
||||||
'tools.staticdir.dir': os.path.join(plexpy.CONFIG.CACHE_DIR, 'images'),
|
# 'tools.staticdir.dir': os.path.join(plexpy.CONFIG.CACHE_DIR, 'images'),
|
||||||
'tools.caching.on': True,
|
# 'tools.caching.on': True,
|
||||||
'tools.caching.force': True,
|
# 'tools.caching.force': True,
|
||||||
'tools.caching.delay': 0,
|
# 'tools.caching.delay': 0,
|
||||||
'tools.expires.on': True,
|
# 'tools.expires.on': True,
|
||||||
'tools.expires.secs': 60 * 60 * 24 * 30, # 30 days
|
# 'tools.expires.secs': 60 * 60 * 24 * 30, # 30 days
|
||||||
'tools.auth.on': False,
|
# 'tools.auth.on': False,
|
||||||
'tools.sessions.on': False
|
# 'tools.sessions.on': False
|
||||||
},
|
#},
|
||||||
'/favicon.ico': {
|
'/favicon.ico': {
|
||||||
'tools.staticfile.on': True,
|
'tools.staticfile.on': True,
|
||||||
'tools.staticfile.filename': os.path.abspath(os.path.join(plexpy.PROG_DIR, 'data/interfaces/default/images/favicon.ico')),
|
'tools.staticfile.filename': os.path.abspath(os.path.join(plexpy.PROG_DIR, 'data/interfaces/default/images/favicon.ico')),
|
||||||
@@ -199,7 +211,7 @@ def initialize(options):
|
|||||||
'tools.expires.secs': 60 * 60 * 24 * 30, # 30 days
|
'tools.expires.secs': 60 * 60 * 24 * 30, # 30 days
|
||||||
'tools.auth.on': False,
|
'tools.auth.on': False,
|
||||||
'tools.sessions.on': False
|
'tools.sessions.on': False
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Prevent time-outs
|
# Prevent time-outs
|
||||||
|
Reference in New Issue
Block a user