Compare commits
128 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
76893100fc | ||
![]() |
96e8b808da | ||
![]() |
595bff94b4 | ||
![]() |
5661c00497 | ||
![]() |
a98d7bd4eb | ||
![]() |
097203162d | ||
![]() |
823c9b3159 | ||
![]() |
35965a6a1b | ||
![]() |
8d67cc4c5a | ||
![]() |
42e33a0468 | ||
![]() |
b2529db026 | ||
![]() |
e99c4aec4a | ||
![]() |
2d0a97f259 | ||
![]() |
fabb52763b | ||
![]() |
03dd1a6974 | ||
![]() |
ecee50a5e4 | ||
![]() |
cbab7c4cbf | ||
![]() |
257ea14c59 | ||
![]() |
11299291b0 | ||
![]() |
533b8076e4 | ||
![]() |
b0383b4813 | ||
![]() |
96500f75b0 | ||
![]() |
2a3bd3413f | ||
![]() |
8ec136a0ca | ||
![]() |
2bead0fc29 | ||
![]() |
359776d48a | ||
![]() |
05a16bb199 | ||
![]() |
f457704105 | ||
![]() |
5aa59b93b0 | ||
![]() |
47d51f92c7 | ||
![]() |
068cf17d0a | ||
![]() |
3c1b849a5d | ||
![]() |
8384ec7f15 | ||
![]() |
0e7a3962bb | ||
![]() |
3d1bb9975c | ||
![]() |
eed473be15 | ||
![]() |
e23d9bca22 | ||
![]() |
85a952a5c9 | ||
![]() |
5cc36310ba | ||
![]() |
8690d2ced5 | ||
![]() |
f572943a7b | ||
![]() |
89248ad46a | ||
![]() |
517db71916 | ||
![]() |
ad82de010d | ||
![]() |
02fd9edbbf | ||
![]() |
6c84dd7be8 | ||
![]() |
9edbe6af37 | ||
![]() |
37d09e9bad | ||
![]() |
0d0595e9a0 | ||
![]() |
17477455cb | ||
![]() |
43f594709d | ||
![]() |
8885b3e7e0 | ||
![]() |
c060638539 | ||
![]() |
2144d4d7ed | ||
![]() |
4f2e09d733 | ||
![]() |
9d13c29bf6 | ||
![]() |
60d577f95e | ||
![]() |
1dd1c6f67f | ||
![]() |
bcd0691b33 | ||
![]() |
24a2559ab5 | ||
![]() |
22a6bae4cf | ||
![]() |
2c45de1fe5 | ||
![]() |
0ab93d7a7f | ||
![]() |
c8831efb28 | ||
![]() |
0cbde5a2f5 | ||
![]() |
7de82d87f7 | ||
![]() |
751b97a39c | ||
![]() |
7b58bcc279 | ||
![]() |
820a2e688c | ||
![]() |
10a7f540ad | ||
![]() |
31a6c627af | ||
![]() |
aba4cbf9e4 | ||
![]() |
a5624e86e4 | ||
![]() |
5480d09a0b | ||
![]() |
5fad0a1d97 | ||
![]() |
4a7b5bab54 | ||
![]() |
fe0557dcc1 | ||
![]() |
e4b6d61098 | ||
![]() |
73e01ebaaf | ||
![]() |
d752d46676 | ||
![]() |
3932409fb4 | ||
![]() |
f69d4f1c42 | ||
![]() |
96699fc3b0 | ||
![]() |
97ec8f6828 | ||
![]() |
df851e67f9 | ||
![]() |
5d1bc3cf9b | ||
![]() |
81ab9b006d | ||
![]() |
1699fc09cf | ||
![]() |
f8b6a9f1e8 | ||
![]() |
ba465a0d15 | ||
![]() |
af521b4058 | ||
![]() |
27b512611f | ||
![]() |
b79f165a27 | ||
![]() |
716f76baed | ||
![]() |
18c57a4fc6 | ||
![]() |
c26483b4b8 | ||
![]() |
441e39d776 | ||
![]() |
7ecc075c7e | ||
![]() |
2e42663832 | ||
![]() |
075f9f8cbd | ||
![]() |
f3d42e7b53 | ||
![]() |
fa0b547b32 | ||
![]() |
8f19cdccfd | ||
![]() |
5c207aeee6 | ||
![]() |
d48273ef98 | ||
![]() |
a7803dcad7 | ||
![]() |
4fc9b6fdb4 | ||
![]() |
73f8f83658 | ||
![]() |
66a0f953b3 | ||
![]() |
f189eea32b | ||
![]() |
be29d879a7 | ||
![]() |
e3e906c9e5 | ||
![]() |
6fce31e1b9 | ||
![]() |
db1cb3d658 | ||
![]() |
c0d7c5ddff | ||
![]() |
d0cd2672dd | ||
![]() |
ca55900d40 | ||
![]() |
3d65ffc6d3 | ||
![]() |
f94b796c2b | ||
![]() |
66c1fd6593 | ||
![]() |
13a45facf9 | ||
![]() |
26f10b2c3d | ||
![]() |
9aea4c85b0 | ||
![]() |
ee1b0eeeff | ||
![]() |
c6cfb4a020 | ||
![]() |
91da41ff86 | ||
![]() |
a811edb236 | ||
![]() |
66de806b02 |
5
.dockerignore
Normal file
5
.dockerignore
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.git
|
||||||
|
.github
|
||||||
|
.gitignore
|
||||||
|
*.md
|
||||||
|
!CHANGELOG*.md
|
30
.github/workflows/publishdocker-branch.yml
vendored
Normal file
30
.github/workflows/publishdocker-branch.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
name: Publish Docker Branch
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master, beta, nightly]
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@master
|
||||||
|
- name: Get Branch
|
||||||
|
run: echo ::set-env name=BRANCH::${GITHUB_REF#refs/heads/}
|
||||||
|
- name: Publish to Registry
|
||||||
|
uses: elgohr/Publish-Docker-Github-Action@master
|
||||||
|
env:
|
||||||
|
VERSION: ${{ github.sha }}
|
||||||
|
with:
|
||||||
|
name: tautulli/tautulli
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
buildargs: VERSION, BRANCH
|
||||||
|
- name: Post Status to Discord
|
||||||
|
uses: sarisia/actions-status-discord@v1
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
webhook: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
|
status: ${{ job.status }}
|
||||||
|
job: ${{ github.workflow }}
|
||||||
|
nofail: true
|
32
.github/workflows/publishdocker-release.yml
vendored
Normal file
32
.github/workflows/publishdocker-release.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: Publish Docker Release
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@master
|
||||||
|
- name: Get Branch
|
||||||
|
run: echo ::set-env name=BRANCH::${GITHUB_REF/refs\/tags\//}
|
||||||
|
- name: Publish to Registry
|
||||||
|
uses: elgohr/Publish-Docker-Github-Action@master
|
||||||
|
env:
|
||||||
|
VERSION: ${{ github.sha }}
|
||||||
|
with:
|
||||||
|
name: tautulli/tautulli
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
buildargs: VERSION, BRANCH
|
||||||
|
tags: ${{ env.BRANCH }}
|
||||||
|
- name: Post Status to Discord
|
||||||
|
uses: sarisia/actions-status-discord@v1
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
webhook: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
|
status: ${{ job.status }}
|
||||||
|
job: ${{ github.workflow }}
|
||||||
|
nofail: true
|
29
.github/workflows/publishrelease-beta.yml
vendored
Normal file
29
.github/workflows/publishrelease-beta.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
name: Create Pre-Release
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*-beta'
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@master
|
||||||
|
- name: Get Release Version
|
||||||
|
run: echo ::set-env name=RELEASE_VERSION::${GITHUB_REF/refs\/tags\//}
|
||||||
|
- name: Get Changelog
|
||||||
|
run: echo ::set-env name=CHANGELOG::"$( sed -n '/^## /{p; :loop n; p; /^## /q; b loop}' CHANGELOG.md | sed '$d' | sed '$d' | sed '$d' | sed ':a;N;$!ba;s/\n/%0A/g' )"
|
||||||
|
- name: Create Release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.RELEASE_VERSION }}
|
||||||
|
release_name: Tautulli ${{ env.RELEASE_VERSION }}
|
||||||
|
body: |
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
##${{ env.CHANGELOG }}
|
||||||
|
draft: false
|
||||||
|
prerelease: true
|
30
.github/workflows/publishrelease-master.yml
vendored
Normal file
30
.github/workflows/publishrelease-master.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
name: Create Release
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
- '!v*-beta'
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@master
|
||||||
|
- name: Get Release Version
|
||||||
|
run: echo ::set-env name=RELEASE_VERSION::${GITHUB_REF/refs\/tags\//}
|
||||||
|
- name: Get Changelog
|
||||||
|
run: echo ::set-env name=CHANGELOG::"$( sed -n '/^## /{p; :loop n; p; /^## /q; b loop}' CHANGELOG.md | sed '$d' | sed '$d' | sed '$d' | sed ':a;N;$!ba;s/\n/%0A/g' )"
|
||||||
|
- name: Create Release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.RELEASE_VERSION }}
|
||||||
|
release_name: Tautulli ${{ env.RELEASE_VERSION }}
|
||||||
|
body: |
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
##${{ env.CHANGELOG }}
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
121
API.md
121
API.md
@@ -327,6 +327,7 @@ Required parameters:
|
|||||||
|
|
||||||
Optional parameters:
|
Optional parameters:
|
||||||
custom_thumb (str): The URL for the custom library thumbnail
|
custom_thumb (str): The URL for the custom library thumbnail
|
||||||
|
custom_art (str): The URL for the custom library background art
|
||||||
keep_history (int): 0 or 1
|
keep_history (int): 0 or 1
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -395,7 +396,11 @@ Returns:
|
|||||||
"banner": "/library/metadata/1219/banner/1503306930",
|
"banner": "/library/metadata/1219/banner/1503306930",
|
||||||
"bif_thumb": "/library/parts/274169/indexes/sd/1000",
|
"bif_thumb": "/library/parts/274169/indexes/sd/1000",
|
||||||
"bitrate": "10617",
|
"bitrate": "10617",
|
||||||
|
"channel_call_sign": "",
|
||||||
|
"channel_identifier": "",
|
||||||
"channel_stream": 0,
|
"channel_stream": 0,
|
||||||
|
"channel_thumb": "",
|
||||||
|
"children_count": "",
|
||||||
"collections": [],
|
"collections": [],
|
||||||
"container": "mkv",
|
"container": "mkv",
|
||||||
"content_rating": "TV-MA",
|
"content_rating": "TV-MA",
|
||||||
@@ -427,13 +432,15 @@ Returns:
|
|||||||
"ip_address": "10.10.10.1",
|
"ip_address": "10.10.10.1",
|
||||||
"ip_address_public": "64.123.23.111",
|
"ip_address_public": "64.123.23.111",
|
||||||
"is_admin": 1,
|
"is_admin": 1,
|
||||||
"is_allow_sync": null,
|
"is_allow_sync": 1,
|
||||||
"is_home_user": 1,
|
"is_home_user": 1,
|
||||||
"is_restricted": 0,
|
"is_restricted": 0,
|
||||||
"keep_history": 1,
|
"keep_history": 1,
|
||||||
"labels": [],
|
"labels": [],
|
||||||
"last_viewed_at": "1462165717",
|
"last_viewed_at": "1462165717",
|
||||||
"library_name": "TV Shows",
|
"library_name": "TV Shows",
|
||||||
|
"live": 0,
|
||||||
|
"live_uuid": "",
|
||||||
"local": "1",
|
"local": "1",
|
||||||
"location": "lan",
|
"location": "lan",
|
||||||
"machine_id": "lmd93nkn12k29j2lnm",
|
"machine_id": "lmd93nkn12k29j2lnm",
|
||||||
@@ -442,8 +449,8 @@ Returns:
|
|||||||
"optimized_version": 0,
|
"optimized_version": 0,
|
||||||
"optimized_version_profile": "",
|
"optimized_version_profile": "",
|
||||||
"optimized_version_title": "",
|
"optimized_version_title": "",
|
||||||
"originally_available_at": "2016-04-24",
|
|
||||||
"original_title": "",
|
"original_title": "",
|
||||||
|
"originally_available_at": "2016-04-24",
|
||||||
"parent_guid": "com.plexapp.agents.thetvdb://121361/6?lang=en",
|
"parent_guid": "com.plexapp.agents.thetvdb://121361/6?lang=en",
|
||||||
"parent_media_index": "6",
|
"parent_media_index": "6",
|
||||||
"parent_rating_key": "153036",
|
"parent_rating_key": "153036",
|
||||||
@@ -463,6 +470,7 @@ Returns:
|
|||||||
"rating_key": "153037",
|
"rating_key": "153037",
|
||||||
"relay": 0,
|
"relay": 0,
|
||||||
"section_id": "2",
|
"section_id": "2",
|
||||||
|
"secure": 1,
|
||||||
"session_id": "helf15l3rxgw01xxe0jf3l3d",
|
"session_id": "helf15l3rxgw01xxe0jf3l3d",
|
||||||
"session_key": "27",
|
"session_key": "27",
|
||||||
"shared_libraries": [
|
"shared_libraries": [
|
||||||
@@ -501,15 +509,21 @@ Returns:
|
|||||||
"stream_subtitle_location": "",
|
"stream_subtitle_location": "",
|
||||||
"stream_video_bit_depth": "8",
|
"stream_video_bit_depth": "8",
|
||||||
"stream_video_bitrate": "10233",
|
"stream_video_bitrate": "10233",
|
||||||
|
"stream_video_chroma_subsampling": "4:2:0",
|
||||||
"stream_video_codec": "h264",
|
"stream_video_codec": "h264",
|
||||||
"stream_video_codec_level": "41",
|
"stream_video_codec_level": "41",
|
||||||
|
"stream_video_color_primaries": "",
|
||||||
|
"stream_video_color_range": "tv",
|
||||||
|
"stream_video_color_space": "bt709",
|
||||||
|
"stream_video_color_trc": "",
|
||||||
"stream_video_decision": "direct play",
|
"stream_video_decision": "direct play",
|
||||||
|
"stream_video_dynamic_range": "SDR",
|
||||||
"stream_video_framerate": "24p",
|
"stream_video_framerate": "24p",
|
||||||
|
"stream_video_full_resolution": "1080p",
|
||||||
"stream_video_height": "1078",
|
"stream_video_height": "1078",
|
||||||
"stream_video_language": "",
|
"stream_video_language": "",
|
||||||
"stream_video_language_code": "",
|
"stream_video_language_code": "",
|
||||||
"stream_video_ref_frames": "4",
|
"stream_video_ref_frames": "4",
|
||||||
"stream_video_full_resolution": "1080p",
|
|
||||||
"stream_video_resolution": "1080",
|
"stream_video_resolution": "1080",
|
||||||
"stream_video_scan_type": "progressive",
|
"stream_video_scan_type": "progressive",
|
||||||
"stream_video_width": "1920",
|
"stream_video_width": "1920",
|
||||||
@@ -559,9 +573,15 @@ Returns:
|
|||||||
"username": "LordCommanderSnow",
|
"username": "LordCommanderSnow",
|
||||||
"video_bit_depth": "8",
|
"video_bit_depth": "8",
|
||||||
"video_bitrate": "10233",
|
"video_bitrate": "10233",
|
||||||
|
"video_chroma_subsampling": "4:2:0",
|
||||||
"video_codec": "h264",
|
"video_codec": "h264",
|
||||||
"video_codec_level": "41",
|
"video_codec_level": "41",
|
||||||
|
"video_color_primaries": "",
|
||||||
|
"video_color_range": "tv",
|
||||||
|
"video_color_space": "bt709",
|
||||||
|
"video_color_trc": ",
|
||||||
"video_decision": "direct play",
|
"video_decision": "direct play",
|
||||||
|
"video_dynamic_range": "SDR",
|
||||||
"video_frame_rate": "23.976",
|
"video_frame_rate": "23.976",
|
||||||
"video_framerate": "24p",
|
"video_framerate": "24p",
|
||||||
"video_full_resolution": "1080p",
|
"video_full_resolution": "1080p",
|
||||||
@@ -671,8 +691,9 @@ Optional parameters:
|
|||||||
grandparent_rating_key (int): 351
|
grandparent_rating_key (int): 351
|
||||||
start_date (str): "YYYY-MM-DD"
|
start_date (str): "YYYY-MM-DD"
|
||||||
section_id (int): 2
|
section_id (int): 2
|
||||||
media_type (str): "movie", "episode", "track"
|
media_type (str): "movie", "episode", "track", "live"
|
||||||
transcode_decision (str): "direct play", "copy", "transcode",
|
transcode_decision (str): "direct play", "copy", "transcode",
|
||||||
|
guid (str): Plex guid for an item, e.g. "com.plexapp.agents.thetvdb://121361/6/1"
|
||||||
order_column (str): "date", "friendly_name", "ip_address", "platform", "player",
|
order_column (str): "date", "friendly_name", "ip_address", "platform", "player",
|
||||||
"full_title", "started", "paused_counter", "stopped", "duration"
|
"full_title", "started", "paused_counter", "stopped", "duration"
|
||||||
order_dir (str): "desc" or "asc"
|
order_dir (str): "desc" or "asc"
|
||||||
@@ -697,10 +718,13 @@ Returns:
|
|||||||
"original_title": "",
|
"original_title": "",
|
||||||
"group_count": 1,
|
"group_count": 1,
|
||||||
"group_ids": "1124",
|
"group_ids": "1124",
|
||||||
|
"guid": "com.plexapp.agents.thetvdb://121361/6/1?lang=en",
|
||||||
"id": 1124,
|
"id": 1124,
|
||||||
"ip_address": "xxx.xxx.xxx.xxx",
|
"ip_address": "xxx.xxx.xxx.xxx",
|
||||||
|
"live": 0,
|
||||||
"media_index": 17,
|
"media_index": 17,
|
||||||
"media_type": "episode",
|
"media_type": "episode",
|
||||||
|
"originally_available_at": "2016-04-24",
|
||||||
"parent_media_index": 7,
|
"parent_media_index": 7,
|
||||||
"parent_rating_key": 544,
|
"parent_rating_key": 544,
|
||||||
"parent_title": "",
|
"parent_title": "",
|
||||||
@@ -758,8 +782,10 @@ Returns:
|
|||||||
[{"content_rating": "TV-MA",
|
[{"content_rating": "TV-MA",
|
||||||
"friendly_name": "",
|
"friendly_name": "",
|
||||||
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
|
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
|
||||||
|
"guid": "com.plexapp.agents.thetvdb://121361/6/1?lang=en",
|
||||||
"labels": [],
|
"labels": [],
|
||||||
"last_play": 1462380698,
|
"last_play": 1462380698,
|
||||||
|
"live": 0,
|
||||||
"media_type": "episode",
|
"media_type": "episode",
|
||||||
"platform": "",
|
"platform": "",
|
||||||
"platform_type": "",
|
"platform_type": "",
|
||||||
@@ -860,15 +886,18 @@ Returns:
|
|||||||
"do_notify": "Checked",
|
"do_notify": "Checked",
|
||||||
"do_notify_created": "Checked",
|
"do_notify_created": "Checked",
|
||||||
"duration": 1578037,
|
"duration": 1578037,
|
||||||
|
"guid": "com.plexapp.agents.thetvdb://121361/6/1?lang=en",
|
||||||
"id": 1128,
|
"id": 1128,
|
||||||
"keep_history": "Checked",
|
"keep_history": "Checked",
|
||||||
"labels": [],
|
"labels": [],
|
||||||
"last_accessed": 1462693216,
|
"last_accessed": 1462693216,
|
||||||
"last_played": "Game of Thrones - The Red Woman",
|
"last_played": "Game of Thrones - The Red Woman",
|
||||||
"library_art": "/:/resources/show-fanart.jpg",
|
"library_art": "/:/resources/show-fanart.jpg",
|
||||||
"library_thumb": "",
|
"library_thumb": "/:/resources/show.png",
|
||||||
|
"live": 0,
|
||||||
"media_index": 1,
|
"media_index": 1,
|
||||||
"media_type": "episode",
|
"media_type": "episode",
|
||||||
|
"originally_available_at": "2016-04-24",
|
||||||
"parent_count": 240,
|
"parent_count": 240,
|
||||||
"parent_media_index": 6,
|
"parent_media_index": 6,
|
||||||
"parent_title": "",
|
"parent_title": "",
|
||||||
@@ -958,6 +987,7 @@ Returns:
|
|||||||
"rating_key": "1219",
|
"rating_key": "1219",
|
||||||
"section_id": 2,
|
"section_id": 2,
|
||||||
"section_type": "show",
|
"section_type": "show",
|
||||||
|
"sort_title": "Game of Thrones",
|
||||||
"thumb": "/library/metadata/1219/thumb/1436265995",
|
"thumb": "/library/metadata/1219/thumb/1436265995",
|
||||||
"title": "Game of Thrones",
|
"title": "Game of Thrones",
|
||||||
"video_codec": "",
|
"video_codec": "",
|
||||||
@@ -1124,6 +1154,7 @@ Returns:
|
|||||||
"labels": [],
|
"labels": [],
|
||||||
"last_viewed_at": "1462165717",
|
"last_viewed_at": "1462165717",
|
||||||
"library_name": "TV Shows",
|
"library_name": "TV Shows",
|
||||||
|
"live": 0,
|
||||||
"media_index": "1",
|
"media_index": "1",
|
||||||
"media_info": [
|
"media_info": [
|
||||||
{
|
{
|
||||||
@@ -1133,6 +1164,9 @@ Returns:
|
|||||||
"audio_codec": "ac3",
|
"audio_codec": "ac3",
|
||||||
"audio_profile": "",
|
"audio_profile": "",
|
||||||
"bitrate": "10617",
|
"bitrate": "10617",
|
||||||
|
"channel_call_sign": "",
|
||||||
|
"channel_identifier": "",
|
||||||
|
"channel_thumb": "",
|
||||||
"container": "mkv",
|
"container": "mkv",
|
||||||
"height": "1078",
|
"height": "1078",
|
||||||
"id": "257925",
|
"id": "257925",
|
||||||
@@ -1151,6 +1185,10 @@ Returns:
|
|||||||
"video_bitrate": "10233",
|
"video_bitrate": "10233",
|
||||||
"video_codec": "h264",
|
"video_codec": "h264",
|
||||||
"video_codec_level": "41",
|
"video_codec_level": "41",
|
||||||
|
"video_color_primaries": "",
|
||||||
|
"video_color_range": "tv",
|
||||||
|
"video_color_space": "bt709",
|
||||||
|
"video_color_trc": "",
|
||||||
"video_frame_rate": "23.976",
|
"video_frame_rate": "23.976",
|
||||||
"video_height": "1078",
|
"video_height": "1078",
|
||||||
"video_language": "",
|
"video_language": "",
|
||||||
@@ -1210,7 +1248,7 @@ Returns:
|
|||||||
"rating_image": "rottentomatoes://image.rating.ripe",
|
"rating_image": "rottentomatoes://image.rating.ripe",
|
||||||
"rating_key": "153037",
|
"rating_key": "153037",
|
||||||
"section_id": "2",
|
"section_id": "2",
|
||||||
"sort_title": "Game of Thrones",
|
"sort_title": "Red Woman",
|
||||||
"studio": "HBO",
|
"studio": "HBO",
|
||||||
"summary": "Jon Snow is dead. Daenerys meets a strong man. Cersei sees her daughter again.",
|
"summary": "Jon Snow is dead. Daenerys meets a strong man. Cersei sees her daughter again.",
|
||||||
"tagline": "",
|
"tagline": "",
|
||||||
@@ -1506,7 +1544,8 @@ Returns:
|
|||||||
"series":
|
"series":
|
||||||
[{"name": "Movies", "data": [...]}
|
[{"name": "Movies", "data": [...]}
|
||||||
{"name": "TV", "data": [...]},
|
{"name": "TV", "data": [...]},
|
||||||
{"name": "Music", "data": [...]}
|
{"name": "Music", "data": [...]},
|
||||||
|
{"name": "Live TV", "data": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -1532,7 +1571,8 @@ Returns:
|
|||||||
"series":
|
"series":
|
||||||
[{"name": "Movies", "data": [...]}
|
[{"name": "Movies", "data": [...]}
|
||||||
{"name": "TV", "data": [...]},
|
{"name": "TV", "data": [...]},
|
||||||
{"name": "Music", "data": [...]}
|
{"name": "Music", "data": [...]},
|
||||||
|
{"name": "Live TV", "data": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -1558,7 +1598,8 @@ Returns:
|
|||||||
"series":
|
"series":
|
||||||
[{"name": "Movies", "data": [...]}
|
[{"name": "Movies", "data": [...]}
|
||||||
{"name": "TV", "data": [...]},
|
{"name": "TV", "data": [...]},
|
||||||
{"name": "Music", "data": [...]}
|
{"name": "Music", "data": [...]},
|
||||||
|
{"name": "Live TV", "data": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -1662,7 +1703,8 @@ Returns:
|
|||||||
"series":
|
"series":
|
||||||
[{"name": "Movies", "data": [...]}
|
[{"name": "Movies", "data": [...]}
|
||||||
{"name": "TV", "data": [...]},
|
{"name": "TV", "data": [...]},
|
||||||
{"name": "Music", "data": [...]}
|
{"name": "Music", "data": [...]},
|
||||||
|
{"name": "Live TV", "data": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -1688,7 +1730,8 @@ Returns:
|
|||||||
"series":
|
"series":
|
||||||
[{"name": "Movies", "data": [...]}
|
[{"name": "Movies", "data": [...]}
|
||||||
{"name": "TV", "data": [...]},
|
{"name": "TV", "data": [...]},
|
||||||
{"name": "Music", "data": [...]}
|
{"name": "Music", "data": [...]},
|
||||||
|
{"name": "Live TV", "data": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -1714,7 +1757,8 @@ Returns:
|
|||||||
"series":
|
"series":
|
||||||
[{"name": "Movies", "data": [...]}
|
[{"name": "Movies", "data": [...]}
|
||||||
{"name": "TV", "data": [...]},
|
{"name": "TV", "data": [...]},
|
||||||
{"name": "Music", "data": [...]}
|
{"name": "Music", "data": [...]},
|
||||||
|
{"name": "Live TV", "data": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -1802,22 +1846,59 @@ Optional parameters:
|
|||||||
Returns:
|
Returns:
|
||||||
json:
|
json:
|
||||||
{"recently_added":
|
{"recently_added":
|
||||||
[{"added_at": "1461572396",
|
[{"actors": [
|
||||||
|
"Kit Harington",
|
||||||
|
"Emilia Clarke",
|
||||||
|
"Isaac Hempstead-Wright",
|
||||||
|
"Maisie Williams",
|
||||||
|
"Liam Cunningham",
|
||||||
|
],
|
||||||
|
"added_at": "1461572396",
|
||||||
|
"art": "/library/metadata/1219/art/1462175063",
|
||||||
|
"audience_rating": "8",
|
||||||
|
"audience_rating_image": "rottentomatoes://image.rating.upright",
|
||||||
|
"banner": "/library/metadata/1219/banner/1462175063",
|
||||||
|
"directors": [
|
||||||
|
"Jeremy Podeswa"
|
||||||
|
],
|
||||||
|
"duration": "2998290",
|
||||||
|
"full_title": "Game of Thrones - The Red Woman",
|
||||||
|
"genres": [
|
||||||
|
"Adventure",
|
||||||
|
"Drama",
|
||||||
|
"Fantasy"
|
||||||
|
],
|
||||||
"grandparent_rating_key": "1219",
|
"grandparent_rating_key": "1219",
|
||||||
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
|
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
|
||||||
"grandparent_title": "Game of Thrones",
|
"grandparent_title": "Game of Thrones",
|
||||||
"library_name": "",
|
"guid": "com.plexapp.agents.thetvdb://121361/6/1?lang=en",
|
||||||
|
"labels": [],
|
||||||
|
"last_viewed_at": "1462165717",
|
||||||
|
"library_name": "TV Shows",
|
||||||
"media_index": "1",
|
"media_index": "1",
|
||||||
"media_type": "episode",
|
"media_type": "episode",
|
||||||
"original_title": "",
|
"original_title": "",
|
||||||
|
"originally_available_at": "2016-04-24",
|
||||||
"parent_media_index": "6",
|
"parent_media_index": "6",
|
||||||
"parent_rating_key": "153036",
|
"parent_rating_key": "153036",
|
||||||
"parent_thumb": "/library/metadata/153036/thumb/1462175062",
|
"parent_thumb": "/library/metadata/153036/thumb/1462175062",
|
||||||
"parent_title": "",
|
"parent_title": "",
|
||||||
|
"rating": "7.8",
|
||||||
|
"rating_image": "rottentomatoes://image.rating.ripe",
|
||||||
"rating_key": "153037",
|
"rating_key": "153037",
|
||||||
"section_id": "2",
|
"section_id": "2",
|
||||||
|
"sort_title": "Red Woman",
|
||||||
|
"studio": "HBO",
|
||||||
|
"summary": "Jon Snow is dead. Daenerys meets a strong man. Cersei sees her daughter again.",
|
||||||
|
"tagline": "",
|
||||||
"thumb": "/library/metadata/153037/thumb/1462175060",
|
"thumb": "/library/metadata/153037/thumb/1462175060",
|
||||||
"title": "The Red Woman",
|
"title": "The Red Woman",
|
||||||
|
"user_rating": "9.0",
|
||||||
|
"updated_at": "1462175060",
|
||||||
|
"writers": [
|
||||||
|
"David Benioff",
|
||||||
|
"D. B. Weiss"
|
||||||
|
],
|
||||||
"year": "2016"
|
"year": "2016"
|
||||||
},
|
},
|
||||||
{...},
|
{...},
|
||||||
@@ -1999,6 +2080,7 @@ Returns:
|
|||||||
"stream_video_bitrate": 527,
|
"stream_video_bitrate": 527,
|
||||||
"stream_video_codec": "h264",
|
"stream_video_codec": "h264",
|
||||||
"stream_video_decision": "transcode",
|
"stream_video_decision": "transcode",
|
||||||
|
"stream_video_dynamic_range": "SDR",
|
||||||
"stream_video_framerate": "24p",
|
"stream_video_framerate": "24p",
|
||||||
"stream_video_height": 306,
|
"stream_video_height": 306,
|
||||||
"stream_video_resolution": "SD",
|
"stream_video_resolution": "SD",
|
||||||
@@ -2013,6 +2095,7 @@ Returns:
|
|||||||
"video_bitrate": 2500,
|
"video_bitrate": 2500,
|
||||||
"video_codec": "h264",
|
"video_codec": "h264",
|
||||||
"video_decision": "transcode",
|
"video_decision": "transcode",
|
||||||
|
"video_dynamic_range": "SDR",
|
||||||
"video_framerate": "24p",
|
"video_framerate": "24p",
|
||||||
"video_height": 816,
|
"video_height": 816,
|
||||||
"video_resolution": "1080",
|
"video_resolution": "1080",
|
||||||
@@ -2166,12 +2249,15 @@ Returns:
|
|||||||
"recordsFiltered": 10,
|
"recordsFiltered": 10,
|
||||||
"data":
|
"data":
|
||||||
[{"friendly_name": "Jon Snow",
|
[{"friendly_name": "Jon Snow",
|
||||||
|
"guid": "com.plexapp.agents.thetvdb://121361/6/1?lang=en",
|
||||||
"id": 1121,
|
"id": 1121,
|
||||||
"ip_address": "xxx.xxx.xxx.xxx",
|
"ip_address": "xxx.xxx.xxx.xxx",
|
||||||
"last_played": "Game of Thrones - The Red Woman",
|
"last_played": "Game of Thrones - The Red Woman",
|
||||||
"last_seen": 1462591869,
|
"last_seen": 1462591869,
|
||||||
|
"live": 0,
|
||||||
"media_index": 1,
|
"media_index": 1,
|
||||||
"media_type": "episode",
|
"media_type": "episode",
|
||||||
|
"originally_available_at": "2016-04-24",
|
||||||
"parent_media_index": 6,
|
"parent_media_index": 6,
|
||||||
"parent_title": "",
|
"parent_title": "",
|
||||||
"platform": "Chrome",
|
"platform": "Chrome",
|
||||||
@@ -2371,13 +2457,16 @@ Returns:
|
|||||||
"do_notify": "Checked",
|
"do_notify": "Checked",
|
||||||
"duration": 2998290,
|
"duration": 2998290,
|
||||||
"friendly_name": "Jon Snow",
|
"friendly_name": "Jon Snow",
|
||||||
|
"guid": "com.plexapp.agents.thetvdb://121361/6/1?lang=en",
|
||||||
"id": 1121,
|
"id": 1121,
|
||||||
"ip_address": "xxx.xxx.xxx.xxx",
|
"ip_address": "xxx.xxx.xxx.xxx",
|
||||||
"keep_history": "Checked",
|
"keep_history": "Checked",
|
||||||
"last_played": "Game of Thrones - The Red Woman",
|
"last_played": "Game of Thrones - The Red Woman",
|
||||||
"last_seen": 1462591869,
|
"last_seen": 1462591869,
|
||||||
|
"live": 0,
|
||||||
"media_index": 1,
|
"media_index": 1,
|
||||||
"media_type": "episode",
|
"media_type": "episode",
|
||||||
|
"originally_available_at": "2016-04-24",
|
||||||
"parent_media_index": 6,
|
"parent_media_index": 6,
|
||||||
"parent_title": "",
|
"parent_title": "",
|
||||||
"platform": "Chrome",
|
"platform": "Chrome",
|
||||||
@@ -2516,10 +2605,10 @@ Optional parameters:
|
|||||||
width (str): 300
|
width (str): 300
|
||||||
height (str): 450
|
height (str): 450
|
||||||
opacity (str): 25
|
opacity (str): 25
|
||||||
background (str): 282828
|
background (str): Hex color, e.g. 282828
|
||||||
blur (str): 3
|
blur (str): 3
|
||||||
img_format (str): png
|
img_format (str): png
|
||||||
fallback (str): "poster", "cover", "art"
|
fallback (str): "poster", "cover", "art", "poster-live", "art-live", "art-live-full"
|
||||||
refresh (bool): True or False whether to refresh the image cache
|
refresh (bool): True or False whether to refresh the image cache
|
||||||
return_hash (bool): True or False to return the self-hosted image hash instead of the image
|
return_hash (bool): True or False to return the self-hosted image hash instead of the image
|
||||||
|
|
||||||
|
37
CHANGELOG.md
37
CHANGELOG.md
@@ -1,5 +1,42 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v2.2.0 (2020-03-08)
|
||||||
|
|
||||||
|
* Important Note!
|
||||||
|
* All Live TV changes requires Plex Media Server 1.18.7 or higher.
|
||||||
|
* Monitoring:
|
||||||
|
* Fix: Improved IPv6 display on the activity cards. (Thanks @felixbuenemann)
|
||||||
|
* New: Added Live TV metadata and posters to the activity cards.
|
||||||
|
* Change: Show bandwidth in Gbps when greater than 1000 Mbps.
|
||||||
|
* History:
|
||||||
|
* New: Added history logging for Live TV sessions.
|
||||||
|
* New: Added a fake "Live TV" library to collect Live TV history.
|
||||||
|
* Note: This library will show up the first time that Live TV is played.
|
||||||
|
* New: Added the ability to filter history by Live TV.
|
||||||
|
* Graphs:
|
||||||
|
* New: Added Live TV series to the "Plays by Period" and "Play Totals" graphs.
|
||||||
|
* Change: Media type series on the graphs are only shown if the corresponding library type is present.
|
||||||
|
* Notifications:
|
||||||
|
* Fix: Race condition causing stream count to be incorrect for playback stop notifications.
|
||||||
|
* New: Added Live TV channel notification parameters.
|
||||||
|
* New: Added Plex background art notification parameter.
|
||||||
|
* Note: This is the Plex API endpoint to retrieve the background art, not the actual image.
|
||||||
|
* New: Added poster images for clip notifications.
|
||||||
|
* Change: Default Webhook notification method to POST.
|
||||||
|
* UI:
|
||||||
|
* Fix: Windows platform showing up twice on the Most Active Platforms statistics card.
|
||||||
|
* New: Added option to change the background art for library sections when editing a library.
|
||||||
|
* New: Added button to reset Tautulli git installation in settings to fix failed git updates.
|
||||||
|
* API:
|
||||||
|
* New: Added ability to filter history using a "live" media type and by guid for the get_history API command.
|
||||||
|
* New: Added cutsom_art parameter to the edit_library API command.
|
||||||
|
* Other:
|
||||||
|
* Change: Add crossorigin use-credentials attribute to manifest tags. (Thanks @pkoenig10)
|
||||||
|
* Change: Disable automatic updates for Docker containers. Updates are now handled by updating the Docker container.
|
||||||
|
* Note: If you are using an old Docker container created before v2.2.0, then you may need to completely remove and recreate the container to update for the first time.
|
||||||
|
* Note: Use the ":latest" Docker tag for the newest stable release, or the ":beta" or ":nightly" tags to access the beta or nightly branches.
|
||||||
|
|
||||||
|
|
||||||
## v2.1.44 (2020-02-05)
|
## v2.1.44 (2020-02-05)
|
||||||
|
|
||||||
* Monitoring:
|
* Monitoring:
|
||||||
|
31
Dockerfile
Normal file
31
Dockerfile
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
FROM python:2.7.17-slim
|
||||||
|
|
||||||
|
LABEL maintainer="TheMeanCanEHdian"
|
||||||
|
|
||||||
|
ARG VERSION
|
||||||
|
ARG BRANCH
|
||||||
|
|
||||||
|
ENV TAUTULLI_DOCKER=True
|
||||||
|
ENV TZ=UTC
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
apt-get -q -y update --no-install-recommends && \
|
||||||
|
apt-get install -q -y --no-install-recommends \
|
||||||
|
curl && \
|
||||||
|
rm -rf /var/lib/apt/lists/* && \
|
||||||
|
pip install --no-cache-dir --upgrade pip && \
|
||||||
|
pip install --no-cache-dir --upgrade \
|
||||||
|
pycryptodomex \
|
||||||
|
pyopenssl && \
|
||||||
|
echo ${VERSION} > /app/version.txt && \
|
||||||
|
echo ${BRANCH} > /app/branch.txt
|
||||||
|
|
||||||
|
COPY . /app
|
||||||
|
|
||||||
|
CMD [ "python", "Tautulli.py", "--datadir", "/config" ]
|
||||||
|
|
||||||
|
VOLUME /config /plex_logs
|
||||||
|
EXPOSE 8181
|
||||||
|
HEALTHCHECK --start-period=90s CMD curl -ILfSs http://localhost:8181/status > /dev/null || curl -ILfkSs https://localhost:8181/status > /dev/null || exit 1
|
25
README.md
25
README.md
@@ -1,9 +1,5 @@
|
|||||||
# Tautulli
|
# Tautulli
|
||||||
|
|
||||||
[](https://tautulli.com/discord)
|
|
||||||
[](https://www.reddit.com/r/Tautulli/)
|
|
||||||
[](https://forums.plex.tv/t/tautulli-monitor-your-plex-media-server/225242)
|
|
||||||
|
|
||||||
A python based web application for monitoring, analytics and notifications for [Plex Media Server](https://plex.tv).
|
A python based web application for monitoring, analytics and notifications for [Plex Media Server](https://plex.tv).
|
||||||
|
|
||||||
This project is based on code from [Headphones](https://github.com/rembo10/headphones) and [PlexWatchWeb](https://github.com/ecleese/plexWatchWeb).
|
This project is based on code from [Headphones](https://github.com/rembo10/headphones) and [PlexWatchWeb](https://github.com/ecleese/plexWatchWeb).
|
||||||
@@ -31,7 +27,21 @@ This project is based on code from [Headphones](https://github.com/rembo10/headp
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Installation and Support
|
## Installation & Support
|
||||||
|
|
||||||
|
[](https://python.org/downloads/release/python-2717/)
|
||||||
|
[](https://hub.docker.com/r/tautulli/tautulli)
|
||||||
|
[](https://hub.docker.com/r/tautulli/tautulli)
|
||||||
|
|
||||||
|
| Status | Branch: `master` | Branch: `beta` | Branch: `nightly` |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| Release | [](https://github.com/Tautulli/Tautulli/releases/latest) <br> [](https://github.com/Tautulli/Tautulli/releases/latest) | [](https://github.com/Tautulli/Tautulli/releases) <br> [](https://github.com/Tautulli/Tautulli/commits/beta) | [](https://github.com/Tautulli/Tautulli/commits/nightly) <br> [](https://github.com/Tautulli/Tautulli/commits/nightly) |
|
||||||
|
| Docker | [](https://hub.docker.com/r/tautulli/tautulli) <br> [](https://github.com/Tautulli/Tautulli/actions?query=branch%3Amaster) | [](https://hub.docker.com/r/tautulli/tautulli) <br> [](https://github.com/Tautulli/Tautulli/actions?query=branch%3Abeta) | [](https://hub.docker.com/r/tautulli/tautulli) <br> [](https://github.com/Tautulli/Tautulli/actions?query=branch%3Anightly) |
|
||||||
|
|
||||||
|
[](https://github.com/Tautulli/Tautulli-Wiki/wiki)
|
||||||
|
[](https://tautulli.com/discord)
|
||||||
|
[](https://www.reddit.com/r/Tautulli/)
|
||||||
|
[](https://forums.plex.tv/t/tautulli-monitor-your-plex-media-server/225242)
|
||||||
|
|
||||||
* Read the [Installation Guides](https://github.com/Tautulli/Tautulli-Wiki/wiki/Installation) for instructions to install Tautulli.
|
* Read the [Installation Guides](https://github.com/Tautulli/Tautulli-Wiki/wiki/Installation) for instructions to install Tautulli.
|
||||||
* The [Frequently Asked Questions](https://github.com/Tautulli/Tautulli-Wiki/wiki/Frequently-Asked-Questions) in the wiki can help you with common problems.
|
* The [Frequently Asked Questions](https://github.com/Tautulli/Tautulli-Wiki/wiki/Frequently-Asked-Questions) in the wiki can help you with common problems.
|
||||||
@@ -39,10 +49,15 @@ This project is based on code from [Headphones](https://github.com/rembo10/headp
|
|||||||
|
|
||||||
## Issues & Feature Requests
|
## Issues & Feature Requests
|
||||||
|
|
||||||
|
[](https://github.com/Tautulli/Tautulli-Issues)
|
||||||
|
[](https://feathub.com/Tautulli/Tautulli)
|
||||||
|
|
||||||
* Please see the [Issues Repository](https://github.com/Tautulli/Tautulli-Issues).
|
* Please see the [Issues Repository](https://github.com/Tautulli/Tautulli-Issues).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
[](https://github.com/Tautulli/Tautulli/blob/master/LICENSE)
|
||||||
|
|
||||||
This is free software under the GPL v3 open source license. Feel free to do with it what you wish, but any modification must be open sourced. A copy of the license is included.
|
This is free software under the GPL v3 open source license. Feel free to do with it what you wish, but any modification must be open sourced. A copy of the license is included.
|
||||||
|
|
||||||
This software includes Highsoft software libraries which you may freely distribute for non-commercial use. Commerical users must licence this software, for more information visit https://shop.highsoft.com/faq/non-commercial#non-commercial-redistribution.
|
This software includes Highsoft software libraries which you may freely distribute for non-commercial use. Commerical users must licence this software, for more information visit https://shop.highsoft.com/faq/non-commercial#non-commercial-redistribution.
|
@@ -36,7 +36,7 @@ import time
|
|||||||
import tzlocal
|
import tzlocal
|
||||||
|
|
||||||
import plexpy
|
import plexpy
|
||||||
from plexpy import config, database, logger, webstart
|
from plexpy import config, database, helpers, logger, webstart
|
||||||
|
|
||||||
|
|
||||||
# Register signals, such as CTRL + C
|
# Register signals, such as CTRL + C
|
||||||
@@ -117,7 +117,7 @@ def main():
|
|||||||
|
|
||||||
plexpy.SYS_UTC_OFFSET = datetime.datetime.now(plexpy.SYS_TIMEZONE).strftime('%z')
|
plexpy.SYS_UTC_OFFSET = datetime.datetime.now(plexpy.SYS_TIMEZONE).strftime('%z')
|
||||||
|
|
||||||
if os.getenv('TAUTULLI_DOCKER', False) == 'True':
|
if helpers.bool_true(os.getenv('TAUTULLI_DOCKER', False)):
|
||||||
plexpy.DOCKER = True
|
plexpy.DOCKER = True
|
||||||
|
|
||||||
if args.dev:
|
if args.dev:
|
||||||
@@ -263,6 +263,8 @@ def main():
|
|||||||
plexpy.shutdown(restart=True)
|
plexpy.shutdown(restart=True)
|
||||||
elif plexpy.SIGNAL == 'checkout':
|
elif plexpy.SIGNAL == 'checkout':
|
||||||
plexpy.shutdown(restart=True, checkout=True)
|
plexpy.shutdown(restart=True, checkout=True)
|
||||||
|
elif plexpy.SIGNAL == 'reset':
|
||||||
|
plexpy.shutdown(restart=True, reset=True)
|
||||||
else:
|
else:
|
||||||
plexpy.shutdown(restart=True, update=True)
|
plexpy.shutdown(restart=True, update=True)
|
||||||
|
|
||||||
|
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
<!-- ICONS -->
|
<!-- ICONS -->
|
||||||
<!-- Android -->
|
<!-- Android -->
|
||||||
<link rel="manifest" href="${http_root}images/favicon/manifest.json?v=2.0.5">
|
<link rel="manifest" href="${http_root}images/favicon/manifest.json?v=2.0.5" crossorigin="use-credentials">
|
||||||
<meta name="theme-color" content="#282a2d">
|
<meta name="theme-color" content="#282a2d">
|
||||||
<!-- Apple -->
|
<!-- Apple -->
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="${http_root}images/favicon/apple-touch-icon.png?v=2.0.5">
|
<link rel="apple-touch-icon" sizes="180x180" href="${http_root}images/favicon/apple-touch-icon.png?v=2.0.5">
|
||||||
@@ -43,23 +43,23 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div id="ajaxMsg" class="ajaxMsg"></div>
|
<div id="ajaxMsg" class="ajaxMsg"></div>
|
||||||
% if _session['user_group'] == 'admin':
|
% if _session['user_group'] == 'admin':
|
||||||
% if plexpy.CONFIG.CHECK_GITHUB and plexpy.UPDATE_AVAILABLE is None:
|
% if plexpy.CONFIG.CHECK_GITHUB and plexpy.UPDATE_AVAILABLE is not False:
|
||||||
<div id="updatebar" style="display: none;">
|
<div id="updatebar" style="display: none;">
|
||||||
|
% if plexpy.UPDATE_AVAILABLE is None:
|
||||||
You are running an unknown version of Tautulli.<br />
|
You are running an unknown version of Tautulli.<br />
|
||||||
<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>
|
% elif plexpy.UPDATE_AVAILABLE == 'release':
|
||||||
</div>
|
|
||||||
% elif plexpy.CONFIG.CHECK_GITHUB and plexpy.UPDATE_AVAILABLE == 'release':
|
|
||||||
<div id="updatebar" style="display: none;">
|
|
||||||
A <a href="${anon_url('https://github.com/%s/%s/releases/tag/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.LATEST_RELEASE))}" target="_blank">
|
A <a href="${anon_url('https://github.com/%s/%s/releases/tag/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.LATEST_RELEASE))}" target="_blank">
|
||||||
new release (${plexpy.LATEST_RELEASE})</a> of Tautulli is available!<br />
|
new release (${plexpy.LATEST_RELEASE})</a> of Tautulli is available!<br />
|
||||||
<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>
|
% elif plexpy.UPDATE_AVAILABLE == 'commit':
|
||||||
</div>
|
|
||||||
% elif plexpy.CONFIG.CHECK_GITHUB and plexpy.UPDATE_AVAILABLE == 'commit':
|
|
||||||
<div id="updatebar" style="display: none;">
|
|
||||||
A <a href="${anon_url('https://github.com/%s/%s/compare/%s...%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.CURRENT_VERSION, plexpy.LATEST_VERSION))}" target="_blank">
|
A <a href="${anon_url('https://github.com/%s/%s/compare/%s...%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.CURRENT_VERSION, plexpy.LATEST_VERSION))}" target="_blank">
|
||||||
newer version</a> of Tautulli is available!<br />
|
newer version</a> of Tautulli is available!<br />
|
||||||
You are ${plexpy.COMMITS_BEHIND} commit${'s' if plexpy.COMMITS_BEHIND > 1 else ''} behind.<br />
|
You are ${plexpy.COMMITS_BEHIND} commit${'s' if plexpy.COMMITS_BEHIND > 1 else ''} behind.<br />
|
||||||
|
% endif
|
||||||
|
% if plexpy.DOCKER:
|
||||||
|
Update your Docker container or <a href="#" id="updateDismiss">Dismiss</a>
|
||||||
|
% else:
|
||||||
<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>
|
<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>
|
||||||
|
% endif
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div id="updatebar" style="display: none;"></div>
|
<div id="updatebar" style="display: none;"></div>
|
||||||
@@ -291,6 +291,7 @@ ${next.modalIncludes()}
|
|||||||
<script src="${http_root}js/bootstrap-hover-dropdown.min.js"></script>
|
<script src="${http_root}js/bootstrap-hover-dropdown.min.js"></script>
|
||||||
<script src="${http_root}js/pnotify.custom.min.js"></script>
|
<script src="${http_root}js/pnotify.custom.min.js"></script>
|
||||||
<script src="${http_root}js/platform.min.js"></script>
|
<script src="${http_root}js/platform.min.js"></script>
|
||||||
|
<script src="${http_root}js/ipaddr.min.js"></script>
|
||||||
<script src="${http_root}js/script.js${cache_param}"></script>
|
<script src="${http_root}js/script.js${cache_param}"></script>
|
||||||
<script src="${http_root}js/jquery.tripleclick.min.js"></script>
|
<script src="${http_root}js/jquery.tripleclick.min.js"></script>
|
||||||
% if _session['user_group'] == 'admin' and BROWSER_NOTIFIERS:
|
% if _session['user_group'] == 'admin' and BROWSER_NOTIFIERS:
|
||||||
@@ -318,21 +319,23 @@ ${next.modalIncludes()}
|
|||||||
complete: function (xhr, status) {
|
complete: function (xhr, status) {
|
||||||
var result = $.parseJSON(xhr.responseText);
|
var result = $.parseJSON(xhr.responseText);
|
||||||
var msg = '';
|
var msg = '';
|
||||||
|
if (result.update === false) {
|
||||||
|
showMsg('<i class="fa fa-check"></i> ' + result.message, false, true, 2000);
|
||||||
|
} else {
|
||||||
if (result.update === null) {
|
if (result.update === null) {
|
||||||
msg = 'You are running an unknown version of Tautulli.<br />' +
|
msg = 'You are running an unknown version of Tautulli.<br />';
|
||||||
'<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>';
|
|
||||||
$('#updatebar').html(msg).fadeIn();
|
|
||||||
} else if (result.update === true && result.release === true) {
|
} else if (result.update === true && result.release === true) {
|
||||||
msg = 'A <a href="' + result.release_url + '" target="_blank">new release (' + result.latest_release + ')</a> of Tautulli is available!<br />' +
|
msg = 'A <a href="' + result.release_url + '" target="_blank">new release (' + result.latest_release + ')</a> of Tautulli is available!<br />';
|
||||||
'<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>';
|
|
||||||
$('#updatebar').html(msg).fadeIn();
|
|
||||||
} else if (result.update === true && result.release === false) {
|
} else if (result.update === true && result.release === false) {
|
||||||
msg = 'A <a href="' + result.compare_url + '" target="_blank">newer version</a> of Tautulli is available!<br />' +
|
msg = 'A <a href="' + result.compare_url + '" target="_blank">newer version</a> of Tautulli is available!<br />' +
|
||||||
'You are '+ result.commits_behind + ' commit' + (result.commits_behind > 1 ? 's' : '') + ' behind.<br />' +
|
'You are '+ result.commits_behind + ' commit' + (result.commits_behind > 1 ? 's' : '') + ' behind.<br />';
|
||||||
'<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>';
|
}
|
||||||
|
if (result.docker) {
|
||||||
|
msg += 'Update your Docker container or <a href="#" id="updateDismiss">Dismiss</a>';
|
||||||
|
} else {
|
||||||
|
msg += '<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>';
|
||||||
|
}
|
||||||
$('#updatebar').html(msg).fadeIn();
|
$('#updatebar').html(msg).fadeIn();
|
||||||
} else if (result.update === false) {
|
|
||||||
showMsg('<i class="fa fa-check"></i> ' + result.message, false, true, 2000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_callback) {
|
if (_callback) {
|
||||||
|
@@ -21,7 +21,7 @@ ul.ColVis_collection li {
|
|||||||
|
|
||||||
.ColVis_Button:hover,
|
.ColVis_Button:hover,
|
||||||
ul.ColVis_collection li:hover {
|
ul.ColVis_collection li:hover {
|
||||||
color: #F9AA03;
|
color: #E5A00D;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.ColVis_Button {
|
button.ColVis_Button {
|
||||||
|
@@ -101,7 +101,7 @@ table.display tr:hover a {
|
|||||||
text-decoration:none;
|
text-decoration:none;
|
||||||
}
|
}
|
||||||
table.display td:hover a {
|
table.display td:hover a {
|
||||||
color: #F9AA03;
|
color: #E5A00D;
|
||||||
}
|
}
|
||||||
table.display thead tr:hover {
|
table.display thead tr:hover {
|
||||||
background-color: #212121;
|
background-color: #212121;
|
||||||
|
@@ -523,7 +523,7 @@ fieldset[disabled] .btn-bright.active {
|
|||||||
color: #eee;
|
color: #eee;
|
||||||
}
|
}
|
||||||
.modal-body i {
|
.modal-body i {
|
||||||
color: #F9AA03;
|
color: #E5A00D;
|
||||||
}
|
}
|
||||||
.modal-body i.fa {
|
.modal-body i.fa {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@@ -534,7 +534,7 @@ fieldset[disabled] .btn-bright.active {
|
|||||||
}
|
}
|
||||||
.modal-body strong,
|
.modal-body strong,
|
||||||
.modal-body strong i.fa {
|
.modal-body strong i.fa {
|
||||||
color: #F9AA03;
|
color: #E5A00D;
|
||||||
}
|
}
|
||||||
.modal-footer {
|
.modal-footer {
|
||||||
padding: 15px 20px;
|
padding: 15px 20px;
|
||||||
@@ -673,7 +673,7 @@ textarea.form-control:focus {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
.form-control-feedback {
|
.form-control-feedback {
|
||||||
color: #F9AA03;
|
color: #E5A00D;
|
||||||
margin: 5px 40px 5px 0;
|
margin: 5px 40px 5px 0;
|
||||||
}
|
}
|
||||||
.form-control[disabled],
|
.form-control[disabled],
|
||||||
@@ -973,7 +973,7 @@ a .users-poster-face:hover {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
max-width: 140px;
|
max-width: 125px;
|
||||||
}
|
}
|
||||||
.dashboard-activity-info-time {
|
.dashboard-activity-info-time {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -2177,7 +2177,7 @@ li.advanced-setting {
|
|||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
padding-top: 27px;
|
padding-top: 27px;
|
||||||
padding-left: 110px;
|
padding-left: 105px;
|
||||||
}
|
}
|
||||||
.user-info-nav {
|
.user-info-nav {
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
@@ -3102,6 +3102,7 @@ div.dataTables_info {
|
|||||||
border-left-color: #fff;
|
border-left-color: #fff;
|
||||||
}
|
}
|
||||||
.tooltip-inner {
|
.tooltip-inner {
|
||||||
|
max-width: 250px;
|
||||||
color: #000;
|
color: #000;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border: 0;
|
border: 0;
|
||||||
@@ -3134,6 +3135,37 @@ div.dataTables_info {
|
|||||||
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||||
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||||
}
|
}
|
||||||
|
.channel-thumbnail-popover {
|
||||||
|
z-index: 2000;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.channel-thumbnail-popover.popover.left {
|
||||||
|
margin-left: -15px;
|
||||||
|
}
|
||||||
|
.channel-thumbnail-popover.popover.right {
|
||||||
|
margin-left: 15px;
|
||||||
|
}
|
||||||
|
.channel-thumbnail-popover .popover-content {
|
||||||
|
color: #000;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.channel-thumbnail {
|
||||||
|
background-color: #868b8b;
|
||||||
|
background-position: center;
|
||||||
|
background-size: contain;
|
||||||
|
background-origin: content-box;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
height: 50px;
|
||||||
|
width: 50px;
|
||||||
|
padding: 3px;
|
||||||
|
-webkit-border-radius: 3px;
|
||||||
|
-moz-border-radius: 3px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
.channel-thumbnail-popover .arrow:after {
|
||||||
|
border-right-color: #868b8b !important;
|
||||||
|
}
|
||||||
.edit-user-toggles,
|
.edit-user-toggles,
|
||||||
.edit-library-toggles {
|
.edit-library-toggles {
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
@@ -3983,6 +4015,9 @@ a:hover .overlay-refresh-image:hover {
|
|||||||
.library-video {
|
.library-video {
|
||||||
background-image: url(../images/libraries/video.svg);
|
background-image: url(../images/libraries/video.svg);
|
||||||
}
|
}
|
||||||
|
.library-live {
|
||||||
|
background-image: url(../images/libraries/live.svg);
|
||||||
|
}
|
||||||
.stats-most_concurrent {
|
.stats-most_concurrent {
|
||||||
background-image: url(../images/icons/most-concurrent-streams.svg);
|
background-image: url(../images/icons/most-concurrent-streams.svg);
|
||||||
}
|
}
|
||||||
@@ -4033,7 +4068,7 @@ a:hover .overlay-refresh-image:hover {
|
|||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
}
|
}
|
||||||
.stream-info .heading {
|
.stream-info .heading {
|
||||||
color: #F9AA03;
|
color: #E5A00D;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-weight: bold !important;
|
font-weight: bold !important;
|
||||||
|
@@ -62,8 +62,7 @@ DOCUMENTATION :: END
|
|||||||
% if session is not None:
|
% if session is not None:
|
||||||
<%
|
<%
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from urllib import quote
|
from plexpy.helpers import cast_to_int, page
|
||||||
from plexpy import helpers
|
|
||||||
from plexpy.common import VIDEO_RESOLUTION_OVERRIDES, AUDIO_CODEC_OVERRIDES, EXTRA_TYPES
|
from plexpy.common import VIDEO_RESOLUTION_OVERRIDES, AUDIO_CODEC_OVERRIDES, EXTRA_TYPES
|
||||||
import plexpy
|
import plexpy
|
||||||
%>
|
%>
|
||||||
@@ -71,62 +70,67 @@ DOCUMENTATION :: END
|
|||||||
data = defaultdict(lambda: 'Unknown', **session)
|
data = defaultdict(lambda: 'Unknown', **session)
|
||||||
sk = data['session_key']
|
sk = data['session_key']
|
||||||
|
|
||||||
href = 'info?rating_key={}'.format(data['rating_key']) if data['rating_key'] else '#'
|
href = page('info', data['rating_key'])
|
||||||
parent_href = 'info?rating_key={}'.format(data['parent_rating_key']) if data['parent_rating_key'] else '#'
|
parent_href = page('info', data['parent_rating_key'])
|
||||||
grandparent_href = 'info?rating_key={}'.format(data['grandparent_rating_key']) if data['grandparent_rating_key'] else '#'
|
grandparent_href = page('info', data['grandparent_rating_key'])
|
||||||
user_href = 'user?user_id={}'.format(data['user_id']) if data['user_id'] else '#'
|
user_href = page('user', data['user_id']) if data['user_id'] else '#'
|
||||||
%>
|
%>
|
||||||
<div class="dashboard-activity-instance" id="activity-instance-${sk}" data-key="${sk}" data-id="${data['session_id']}"
|
<div class="dashboard-activity-instance" id="activity-instance-${sk}" data-key="${sk}" data-id="${data['session_id']}"
|
||||||
data-rating_key="${data['rating_key']}" data-parent_rating_key="${data['parent_rating_key']}" data-grandparent_rating_key="${data['grandparent_rating_key']}">
|
data-rating_key="${data['rating_key']}" data-parent_rating_key="${data['parent_rating_key']}" data-grandparent_rating_key="${data['grandparent_rating_key']}"
|
||||||
|
data-guid="${data['guid']}">
|
||||||
<div class="dashboard-activity-container">
|
<div class="dashboard-activity-container">
|
||||||
<%
|
<%
|
||||||
if data['live'] == 1:
|
if data['live']:
|
||||||
background_url = 'images/art-live.png'
|
background_url = page('pms_image_proxy', data['art'], data['rating_key'], 500, 280, 40, '282828', 3, fallback='art-live', refresh=True)
|
||||||
elif data['channel_stream'] == 0:
|
elif data['channel_stream'] == 0:
|
||||||
background_url = 'pms_image_proxy?img=' + data['art'] + '&width=500&height=280&opacity=40&background=282828&blur=3&fallback=art&refresh=true'
|
background_url = page('pms_image_proxy', data['art'], data['rating_key'], 500, 280, 40, '282828', 3, fallback='art', refresh=True)
|
||||||
else:
|
else:
|
||||||
if (data['art'] and data['art'].startswith('http')) or (data['thumb'] and data['thumb'].startswith('http')):
|
background_url = page('pms_image_proxy', data['art'] or data['thumb'], data['rating_key'], 500, 280, 40, '282828', 3, fallback='art', refresh=True, clip=True)
|
||||||
background_url = data['art']
|
|
||||||
else:
|
|
||||||
background_url = 'pms_image_proxy?img=' + quote(data['art'] or data['thumb']) + '&width=500&height=280&fallback=art&refresh=true&clip=true'
|
|
||||||
%>
|
%>
|
||||||
<div id="background-${sk}" class="dashboard-activity-background" style="background-image: url(${background_url});">
|
<div id="background-${sk}" class="dashboard-activity-background" style="background-image: url(${background_url});">
|
||||||
<div class="dashboard-activity-poster-container hidden-xs">
|
<div class="dashboard-activity-poster-container hidden-xs">
|
||||||
% if data['media_type'] == 'track':
|
% if data['media_type'] == 'track':
|
||||||
<div id="poster-${sk}-bg" class="dashboard-activity-poster" style="background-image: url(pms_image_proxy?img=${data['parent_thumb']}&width=300&height=300&opacity=60&background=282828&blur=3&fallback=cover&refresh=true);"></div>
|
<div id="poster-${sk}-bg" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['parent_thumb'], data['parent_rating_key'], 300, 300, 60, '282828', 3, fallback='cover', refresh=True)});"></div>
|
||||||
|
% endif
|
||||||
|
% if data['live']:
|
||||||
|
% if data['media_type'] == 'movie':
|
||||||
|
<a id="poster-url-${sk}" href="${href}" title="${data['title']}">
|
||||||
|
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['thumb'], data['rating_key'], 300, 450, fallback='poster-live', refresh=True)});"></div>
|
||||||
|
</a>
|
||||||
|
% elif data['media_type'] == 'episode':
|
||||||
|
<a id="poster-url-${sk}" href="${href}" title="${data['grandparent_title']}">
|
||||||
|
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['grandparent_thumb'], data['rating_key'], 300, 450, fallback='poster-live', refresh=True)});"></div>
|
||||||
|
</a>
|
||||||
|
% else:
|
||||||
|
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['grandparent_thumb'] or data['thumb'], data['rating_key'], 300, 450, fallback='poster-live', refresh=True)});"></div>
|
||||||
% endif
|
% endif
|
||||||
% if data['live'] == 1:
|
|
||||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(images/poster-live.png);"></div>
|
|
||||||
% elif data['channel_stream'] == 0:
|
% elif data['channel_stream'] == 0:
|
||||||
% if data['media_type'] == 'movie':
|
% if data['media_type'] == 'movie':
|
||||||
<a id="poster-url-${sk}" href="${href}" title="${data['title']}">
|
<a id="poster-url-${sk}" href="${href}" title="${data['title']}">
|
||||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=300&height=450&fallback=poster&refresh=true);"></div>
|
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['thumb'], data['rating_key'], 300, 450, fallback='poster', refresh=True)});"></div>
|
||||||
</a>
|
</a>
|
||||||
% elif data['media_type'] == 'episode':
|
% elif data['media_type'] == 'episode':
|
||||||
<a id="poster-url-${sk}" href="${grandparent_href}" title="${data['grandparent_title']}">
|
<a id="poster-url-${sk}" href="${grandparent_href}" title="${data['grandparent_title']}">
|
||||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(pms_image_proxy?img=${data['grandparent_thumb']}&width=300&height=450&fallback=poster&refresh=true);"></div>
|
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['grandparent_thumb'], data['grandparent_rating_key'], 300, 450, fallback='poster', refresh=True)});"></div>
|
||||||
</a>
|
</a>
|
||||||
% elif data['media_type'] == 'track':
|
% elif data['media_type'] == 'track':
|
||||||
<a id="poster-url-${sk}" href="${parent_href}" title="${data['parent_title']}">
|
<a id="poster-url-${sk}" href="${parent_href}" title="${data['parent_title']}">
|
||||||
<div id="poster-${sk}" class="dashboard-activity-cover" style="background-image: url(pms_image_proxy?img=${data['parent_thumb']}&width=300&height=300&fallback=cover&refresh=true);"></div>
|
<div id="poster-${sk}" class="dashboard-activity-cover" style="background-image: url(${page('pms_image_proxy', data['parent_thumb'], data['parent_rating_key'], 300, 300, fallback='cover', refresh=True)});"></div>
|
||||||
</a>
|
</a>
|
||||||
% elif data['media_type'] in ('photo', 'clip'):
|
% elif data['media_type'] in ('photo', 'clip'):
|
||||||
% if data['extra_type']:
|
% if data['extra_type']:
|
||||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(pms_image_proxy?img=${data['art'].replace('/art', '/thumb') or data['thumb']}&width=300&height=450&fallback=poster&refresh=true);"></div>
|
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['art'].replace('/art', '/thumb') or data['thumb'], data['rating_key'], 300, 450, fallback='poster', refresh=True)});"></div>
|
||||||
|
% elif data['parent_thumb']:
|
||||||
|
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['parent_thumb'], data['parent_rating_key'], 300, 450, fallback='poster', refresh=True)});"></div>
|
||||||
% else:
|
% else:
|
||||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(pms_image_proxy?img=${data['parent_thumb'] or data['thumb']}&width=300&height=450&fallback=poster&refresh=true);"></div>
|
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['thumb'], data['rating_key'], 300, 450, fallback='poster', refresh=True)});"></div>
|
||||||
% endif
|
% endif
|
||||||
% else:
|
% else:
|
||||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(images/poster.png);"></div>
|
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(images/poster.png);"></div>
|
||||||
% endif
|
% endif
|
||||||
% else:
|
% else:
|
||||||
% if data['channel_icon'].startswith('http'):
|
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['channel_icon'], data['rating_key'], 300, 300, 60, '282828', 3, fallback='cover', refresh=True)});"></div>
|
||||||
<div id="poster-${sk}" class="dashboard-activity-poster-blur" style="background-image: url(${data['channel_icon']});"></div>
|
<div id="poster-${sk}" class="dashboard-activity-cover" style="background-image: url(${page('pms_image_proxy', data['channel_icon'], data['rating_key'], 300, 300, fallback='cover', refresh=True)});"></div>
|
||||||
<div id="poster-${sk}" class="dashboard-activity-cover" style="background-image: url(${data['channel_icon']});"></div>
|
|
||||||
% else:
|
|
||||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(pms_image_proxy?img=${data['channel_icon']}&width=300&height=300&opacity=60&background=282828&blur=3&fallback=cover&refresh=true);"></div>
|
|
||||||
<div id="poster-${sk}" class="dashboard-activity-cover" style="background-image: url(pms_image_proxy?img=${data['channel_icon']}&width=300&height=300&fallback=cover&refresh=true);"></div>
|
|
||||||
% endif
|
|
||||||
% endif
|
% endif
|
||||||
</div>
|
</div>
|
||||||
<div class="dashboard-activity-info-icon">
|
<div class="dashboard-activity-info-icon">
|
||||||
@@ -160,7 +164,7 @@ DOCUMENTATION :: END
|
|||||||
<div class="sub-value platform-right" id="stream_quality-${sk}">
|
<div class="sub-value platform-right" id="stream_quality-${sk}">
|
||||||
% if data['media_type'] != 'photo' and data['quality_profile'] != 'Unknown':
|
% if data['media_type'] != 'photo' and data['quality_profile'] != 'Unknown':
|
||||||
<%
|
<%
|
||||||
br = helpers.cast_to_int(data['stream_bitrate']) or ''
|
br = cast_to_int(data['stream_bitrate']) or ''
|
||||||
if br:
|
if br:
|
||||||
if br > 1000:
|
if br > 1000:
|
||||||
br = '(' + str(round(br / 1000.0, 1)) + ' Mbps)'
|
br = '(' + str(round(br / 1000.0, 1)) + ' Mbps)'
|
||||||
@@ -301,7 +305,11 @@ DOCUMENTATION :: END
|
|||||||
% endif
|
% endif
|
||||||
<span id="location-${sk}">${data['location'].upper()}</span>:
|
<span id="location-${sk}">${data['location'].upper()}</span>:
|
||||||
% if data['ip_address'] != 'N/A':
|
% if data['ip_address'] != 'N/A':
|
||||||
|
% if len(data['ip_address']) > 20:
|
||||||
|
<span class="ip-container"><span class="ip-address" data-toggle="tooltip" title="${data['ip_address']}">${data['ip_address']}</span></span>
|
||||||
|
% else:
|
||||||
<span class="ip-container"><span class="ip-address">${data['ip_address']}</span></span>
|
<span class="ip-container"><span class="ip-address">${data['ip_address']}</span></span>
|
||||||
|
% endif
|
||||||
% if data['relayed']:
|
% if data['relayed']:
|
||||||
<span data-toggle="tooltip" title="Plex Relay"><i class="fa fa-exclamation-circle"></i></span>
|
<span data-toggle="tooltip" title="Plex Relay"><i class="fa fa-exclamation-circle"></i></span>
|
||||||
% else:
|
% else:
|
||||||
@@ -326,8 +334,10 @@ DOCUMENTATION :: END
|
|||||||
<div class="sub-value time-right">
|
<div class="sub-value time-right">
|
||||||
% if data['media_type'] != 'photo' and data['bandwidth'] != 'Unknown':
|
% if data['media_type'] != 'photo' and data['bandwidth'] != 'Unknown':
|
||||||
<%
|
<%
|
||||||
bw = helpers.cast_to_int(data['bandwidth'])
|
bw = cast_to_int(data['bandwidth'])
|
||||||
if bw > 1000:
|
if bw > 1000000:
|
||||||
|
bw = str(round(bw / 1000000.0, 1)) + ' Gbps'
|
||||||
|
elif bw > 1000:
|
||||||
bw = str(round(bw / 1000.0, 1)) + ' Mbps'
|
bw = str(round(bw / 1000.0, 1)) + ' Mbps'
|
||||||
else:
|
else:
|
||||||
bw = str(bw) + ' kbps'
|
bw = str(bw) + ' kbps'
|
||||||
@@ -346,8 +356,8 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
% if data['media_type'] != 'photo':
|
% if data['media_type'] != 'photo':
|
||||||
<div class="dashboard-activity-info-time">
|
<div class="dashboard-activity-info-time">
|
||||||
% if data['live'] == 1:
|
% if data['live']:
|
||||||
<br />Live
|
<br /><span class="thumb-tooltip" data-toggle="popover" data-img="${data['channel_thumb']}" data-height="40" data-width="40">${data['channel_call_sign']} ${data['channel_identifier']}</span>
|
||||||
% elif data['view_offset']:
|
% elif data['view_offset']:
|
||||||
ETA:
|
ETA:
|
||||||
<span id="stream-eta-${sk}">
|
<span id="stream-eta-${sk}">
|
||||||
@@ -376,8 +386,8 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
<div class="dashboard-activity-progress">
|
<div class="dashboard-activity-progress">
|
||||||
<div class="dashboard-activity-progress-bar">
|
<div class="dashboard-activity-progress-bar">
|
||||||
% if data['live'] == 1:
|
% if data['live']:
|
||||||
<div id="progress-bar-${sk}" class="progress-bar" style="width: 100%" data-toggle="tooltip" title="Stream Progress Live">Live</div>
|
<div id="progress-bar-${sk}" class="progress-bar" style="width: 100%" data-state="live" data-toggle="tooltip" title="Stream Progress Live">Live</div>
|
||||||
% else:
|
% else:
|
||||||
<div id="buffer-bar-${sk}" class="buffer-bar" style="width: ${data['transcode_progress']}%" data-toggle="tooltip" title="Transcoder Progress ${data['transcode_progress']}%">${data['transcode_progress']}%</div>
|
<div id="buffer-bar-${sk}" class="buffer-bar" style="width: ${data['transcode_progress']}%" data-toggle="tooltip" title="Transcoder Progress ${data['transcode_progress']}%">${data['transcode_progress']}%</div>
|
||||||
<div id="progress-bar-${sk}" class="progress-bar" style="width: ${data['progress_percent']}%" data-last_view_offset="${data['view_offset']}" data-view_offset="${data['view_offset']}" data-stream_duration="${data['stream_duration']}" data-state="${data['state']}" data-toggle="tooltip" title="Stream Progress ${data['progress_percent']}%">${data['progress_percent']}%</div>
|
<div id="progress-bar-${sk}" class="progress-bar" style="width: ${data['progress_percent']}%" data-last_view_offset="${data['view_offset']}" data-view_offset="${data['view_offset']}" data-stream_duration="${data['stream_duration']}" data-state="${data['state']}" data-toggle="tooltip" title="Stream Progress ${data['progress_percent']}%">${data['progress_percent']}%</div>
|
||||||
@@ -400,7 +410,16 @@ DOCUMENTATION :: END
|
|||||||
% endif
|
% endif
|
||||||
</div>
|
</div>
|
||||||
<div class="dashboard-activity-metadata-title">
|
<div class="dashboard-activity-metadata-title">
|
||||||
% if data['channel_stream'] == 0:
|
% if data['live']:
|
||||||
|
% if data['media_type'] == 'movie':
|
||||||
|
<a href="${href}" title="${data['title']}">${data['title']}</a>
|
||||||
|
% elif data['media_type'] == 'episode':
|
||||||
|
<a href="${href}" title="${data['grandparent_title']}">${data['grandparent_title']}</a>
|
||||||
|
- <a href="${href}" title="${data['title']}">${data['title']}</a>
|
||||||
|
% else:
|
||||||
|
<span title="${data['title']}">${data['title']}</span>
|
||||||
|
% endif
|
||||||
|
% elif data['channel_stream'] == 0:
|
||||||
% if data['media_type'] == 'movie':
|
% if data['media_type'] == 'movie':
|
||||||
<a href="${href}" title="${data['title']}">${data['title']}</a>
|
<a href="${href}" title="${data['title']}">${data['title']}</a>
|
||||||
% elif data['media_type'] == 'episode':
|
% elif data['media_type'] == 'episode':
|
||||||
@@ -425,9 +444,9 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="dashboard-activity-metadata-subtitle-container">
|
<div class="dashboard-activity-metadata-subtitle-container">
|
||||||
% if data['live'] == 1:
|
% if data['live']:
|
||||||
<div id="media-type-${sk}" class="dashboard-activity-metadata-media_type-icon" title="Plex Live TV">
|
<div id="media-type-${sk}" class="dashboard-activity-metadata-media_type-icon" title="Live TV">
|
||||||
<i class="fa fa-fw fa-television"></i>
|
<i class="fa fa-fw fa-broadcast-tower"></i>
|
||||||
</div>
|
</div>
|
||||||
% elif data['channel_stream'] == 0:
|
% elif data['channel_stream'] == 0:
|
||||||
<div id="media-type-${sk}" class="dashboard-activity-metadata-media_type-icon" title="${data['media_type'].capitalize()}">
|
<div id="media-type-${sk}" class="dashboard-activity-metadata-media_type-icon" title="${data['media_type'].capitalize()}">
|
||||||
@@ -449,8 +468,19 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
% endif
|
% endif
|
||||||
<div class="dashboard-activity-metadata-subtitle">
|
<div class="dashboard-activity-metadata-subtitle">
|
||||||
% if data['live'] == 1:
|
% if data['live']:
|
||||||
<span title="Plex Live TV" class="sub-heading">Plex Live TV</span>
|
% if data['media_type'] == 'movie':
|
||||||
|
<span title="${data['year']}" class="sub-heading">${data['year']}</span>
|
||||||
|
% elif data['media_type'] == 'episode':
|
||||||
|
% if data['media_index']:
|
||||||
|
<a href="${href}" title="Season ${data['parent_media_index']}" class="sub-heading">S${data['parent_media_index']}</a>
|
||||||
|
· <a href="${href}" title="Episode ${data['media_index']}" class="sub-heading">E${data['media_index']}</a>
|
||||||
|
% else:
|
||||||
|
<a href="${href}" title="${data['originally_available_at']}" class="sub-heading">${data['originally_available_at']}</a>
|
||||||
|
% endif
|
||||||
|
% else:
|
||||||
|
<span title="Live TV" class="sub-heading">Live TV</span>
|
||||||
|
% endif
|
||||||
% elif data['channel_stream'] == 0:
|
% elif data['channel_stream'] == 0:
|
||||||
% if data['media_type'] == 'movie':
|
% if data['media_type'] == 'movie':
|
||||||
<span title="${data['year']}" class="sub-heading">${data['year']}</span>
|
<span title="${data['year']}" class="sub-heading">${data['year']}</span>
|
||||||
|
@@ -40,13 +40,22 @@ DOCUMENTATION :: END
|
|||||||
<div class="modal-body" id="modal-text">
|
<div class="modal-body" id="modal-text">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="profile_url">Library Picture URL</label>
|
<label for="profile_url">Library Thumbnail URL</label>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<input type="text" class="form-control" id="custom_thumb_url" name="custom_thumb_url" value="${data['library_thumb']}">
|
<input type="text" class="form-control" id="custom_thumb_url" name="custom_thumb_url" value="${data['library_thumb']}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">Change the library's picture in Tautulli. To reset to default, leave this field empty and save.</p>
|
<p class="help-block">Change the library's thumbnail in Tautulli. To reset to default, leave this field empty and save.</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="profile_url">Library Background Art URL</label>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<input type="text" class="form-control" id="custom_art_url" name="custom_art_url" value="${data['library_art']}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="help-block">Change the library's background art in Tautulli. To reset to default, leave this field empty and save.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
@@ -80,6 +89,7 @@ DOCUMENTATION :: END
|
|||||||
// Save library options
|
// Save library options
|
||||||
$("#save_library").on('click', function () {
|
$("#save_library").on('click', function () {
|
||||||
var custom_thumb = $("#custom_thumb_url").val();
|
var custom_thumb = $("#custom_thumb_url").val();
|
||||||
|
var custom_art = $("#custom_art_url").val();
|
||||||
var keep_history = 0;
|
var keep_history = 0;
|
||||||
if ($("#keep_history").is(":checked")) {
|
if ($("#keep_history").is(":checked")) {
|
||||||
keep_history = 1;
|
keep_history = 1;
|
||||||
@@ -90,6 +100,7 @@ DOCUMENTATION :: END
|
|||||||
data: {
|
data: {
|
||||||
section_id: '${data["section_id"]}',
|
section_id: '${data["section_id"]}',
|
||||||
custom_thumb: custom_thumb,
|
custom_thumb: custom_thumb,
|
||||||
|
custom_art: custom_art,
|
||||||
keep_history: keep_history
|
keep_history: keep_history
|
||||||
},
|
},
|
||||||
cache: false,
|
cache: false,
|
||||||
|
@@ -252,6 +252,7 @@
|
|||||||
case "TV": media_type = 'episode'; break;
|
case "TV": media_type = 'episode'; break;
|
||||||
case "Movies": media_type = 'movie'; break;
|
case "Movies": media_type = 'movie'; break;
|
||||||
case "Music": media_type = 'track'; break;
|
case "Music": media_type = 'track'; break;
|
||||||
|
case "Live TV": media_type = 'live'; break;
|
||||||
case "Direct Play": transcode_decision = 'direct play'; break;
|
case "Direct Play": transcode_decision = 'direct play'; break;
|
||||||
case "Direct Stream": transcode_decision = 'copy'; break;
|
case "Direct Stream": transcode_decision = 'copy'; break;
|
||||||
case "Transcode": transcode_decision = 'transcode'; break;
|
case "Transcode": transcode_decision = 'transcode'; break;
|
||||||
@@ -304,6 +305,23 @@
|
|||||||
|
|
||||||
setLocalStorage(chart_key, JSON.stringify(chart_visibility));
|
setLocalStorage(chart_key, JSON.stringify(chart_visibility));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getGraphColors(data_series) {
|
||||||
|
var colors = {
|
||||||
|
'TV': '#E5A00D',
|
||||||
|
'Movies': '#FFFFFF',
|
||||||
|
'Music': '#F06464',
|
||||||
|
'Live TV': '#19A0D7',
|
||||||
|
'Direct Play': '#E5A00D',
|
||||||
|
'Direct Stream': '#FFFFFF',
|
||||||
|
'Transcode': '#F06464'
|
||||||
|
};
|
||||||
|
var series_colors = [];
|
||||||
|
$.each(data_series, function(index, series) {
|
||||||
|
series_colors.push(colors[series.name]);
|
||||||
|
});
|
||||||
|
return series_colors;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="${http_root}js/graphs/plays_by_day.js${cache_param}"></script>
|
<script src="${http_root}js/graphs/plays_by_day.js${cache_param}"></script>
|
||||||
<script src="${http_root}js/graphs/plays_by_dayofweek.js${cache_param}"></script>
|
<script src="${http_root}js/graphs/plays_by_dayofweek.js${cache_param}"></script>
|
||||||
@@ -390,6 +408,7 @@
|
|||||||
hc_plays_by_day_options.yAxis.min = 0;
|
hc_plays_by_day_options.yAxis.min = 0;
|
||||||
hc_plays_by_day_options.xAxis.categories = dateArray;
|
hc_plays_by_day_options.xAxis.categories = dateArray;
|
||||||
hc_plays_by_day_options.series = getGraphVisibility(hc_plays_by_day_options.chart.renderTo, data.series);
|
hc_plays_by_day_options.series = getGraphVisibility(hc_plays_by_day_options.chart.renderTo, data.series);
|
||||||
|
hc_plays_by_day_options.colors = getGraphColors(data.series);
|
||||||
var hc_plays_by_day = new Highcharts.Chart(hc_plays_by_day_options);
|
var hc_plays_by_day = new Highcharts.Chart(hc_plays_by_day_options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -403,6 +422,7 @@
|
|||||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||||
hc_plays_by_dayofweek_options.xAxis.categories = data.categories;
|
hc_plays_by_dayofweek_options.xAxis.categories = data.categories;
|
||||||
hc_plays_by_dayofweek_options.series = getGraphVisibility(hc_plays_by_dayofweek_options.chart.renderTo, data.series);
|
hc_plays_by_dayofweek_options.series = getGraphVisibility(hc_plays_by_dayofweek_options.chart.renderTo, data.series);
|
||||||
|
hc_plays_by_dayofweek_options.colors = getGraphColors(data.series);
|
||||||
var hc_plays_by_dayofweek = new Highcharts.Chart(hc_plays_by_dayofweek_options);
|
var hc_plays_by_dayofweek = new Highcharts.Chart(hc_plays_by_dayofweek_options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -416,6 +436,7 @@
|
|||||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||||
hc_plays_by_hourofday_options.xAxis.categories = data.categories;
|
hc_plays_by_hourofday_options.xAxis.categories = data.categories;
|
||||||
hc_plays_by_hourofday_options.series = getGraphVisibility(hc_plays_by_hourofday_options.chart.renderTo, data.series);
|
hc_plays_by_hourofday_options.series = getGraphVisibility(hc_plays_by_hourofday_options.chart.renderTo, data.series);
|
||||||
|
hc_plays_by_hourofday_options.colors = getGraphColors(data.series);
|
||||||
var hc_plays_by_hourofday = new Highcharts.Chart(hc_plays_by_hourofday_options);
|
var hc_plays_by_hourofday = new Highcharts.Chart(hc_plays_by_hourofday_options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -429,6 +450,7 @@
|
|||||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||||
hc_plays_by_platform_options.xAxis.categories = data.categories;
|
hc_plays_by_platform_options.xAxis.categories = data.categories;
|
||||||
hc_plays_by_platform_options.series = getGraphVisibility(hc_plays_by_platform_options.chart.renderTo, data.series);
|
hc_plays_by_platform_options.series = getGraphVisibility(hc_plays_by_platform_options.chart.renderTo, data.series);
|
||||||
|
hc_plays_by_platform_options.colors = getGraphColors(data.series);
|
||||||
var hc_plays_by_platform = new Highcharts.Chart(hc_plays_by_platform_options);
|
var hc_plays_by_platform = new Highcharts.Chart(hc_plays_by_platform_options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -442,6 +464,7 @@
|
|||||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||||
hc_plays_by_user_options.xAxis.categories = data.categories;
|
hc_plays_by_user_options.xAxis.categories = data.categories;
|
||||||
hc_plays_by_user_options.series = getGraphVisibility(hc_plays_by_user_options.chart.renderTo, data.series);
|
hc_plays_by_user_options.series = getGraphVisibility(hc_plays_by_user_options.chart.renderTo, data.series);
|
||||||
|
hc_plays_by_user_options.colors = getGraphColors(data.series);
|
||||||
var hc_plays_by_user = new Highcharts.Chart(hc_plays_by_user_options);
|
var hc_plays_by_user = new Highcharts.Chart(hc_plays_by_user_options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -478,6 +501,7 @@
|
|||||||
hc_plays_by_stream_type_options.yAxis.min = 0;
|
hc_plays_by_stream_type_options.yAxis.min = 0;
|
||||||
hc_plays_by_stream_type_options.xAxis.categories = dateArray;
|
hc_plays_by_stream_type_options.xAxis.categories = dateArray;
|
||||||
hc_plays_by_stream_type_options.series = getGraphVisibility(hc_plays_by_stream_type_options.chart.renderTo, data.series);
|
hc_plays_by_stream_type_options.series = getGraphVisibility(hc_plays_by_stream_type_options.chart.renderTo, data.series);
|
||||||
|
hc_plays_by_stream_type_options.colors = getGraphColors(data.series);
|
||||||
var hc_plays_by_stream_type = new Highcharts.Chart(hc_plays_by_stream_type_options);
|
var hc_plays_by_stream_type = new Highcharts.Chart(hc_plays_by_stream_type_options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -491,6 +515,7 @@
|
|||||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||||
hc_plays_by_source_resolution_options.xAxis.categories = data.categories;
|
hc_plays_by_source_resolution_options.xAxis.categories = data.categories;
|
||||||
hc_plays_by_source_resolution_options.series = getGraphVisibility(hc_plays_by_source_resolution_options.chart.renderTo, data.series);
|
hc_plays_by_source_resolution_options.series = getGraphVisibility(hc_plays_by_source_resolution_options.chart.renderTo, data.series);
|
||||||
|
hc_plays_by_source_resolution_options.colors = getGraphColors(data.series);
|
||||||
var hc_plays_by_source_resolution = new Highcharts.Chart(hc_plays_by_source_resolution_options);
|
var hc_plays_by_source_resolution = new Highcharts.Chart(hc_plays_by_source_resolution_options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -504,6 +529,7 @@
|
|||||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||||
hc_plays_by_stream_resolution_options.xAxis.categories = data.categories;
|
hc_plays_by_stream_resolution_options.xAxis.categories = data.categories;
|
||||||
hc_plays_by_stream_resolution_options.series = getGraphVisibility(hc_plays_by_stream_resolution_options.chart.renderTo, data.series);
|
hc_plays_by_stream_resolution_options.series = getGraphVisibility(hc_plays_by_stream_resolution_options.chart.renderTo, data.series);
|
||||||
|
hc_plays_by_stream_resolution_options.colors = getGraphColors(data.series);
|
||||||
var hc_plays_by_stream_resolution = new Highcharts.Chart(hc_plays_by_stream_resolution_options);
|
var hc_plays_by_stream_resolution = new Highcharts.Chart(hc_plays_by_stream_resolution_options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -517,6 +543,7 @@
|
|||||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||||
hc_plays_by_platform_by_stream_type_options.xAxis.categories = data.categories;
|
hc_plays_by_platform_by_stream_type_options.xAxis.categories = data.categories;
|
||||||
hc_plays_by_platform_by_stream_type_options.series = getGraphVisibility(hc_plays_by_platform_by_stream_type_options.chart.renderTo, data.series);
|
hc_plays_by_platform_by_stream_type_options.series = getGraphVisibility(hc_plays_by_platform_by_stream_type_options.chart.renderTo, data.series);
|
||||||
|
hc_plays_by_platform_by_stream_type_options.colors = getGraphColors(data.series);
|
||||||
var hc_plays_by_platform_by_stream_type = new Highcharts.Chart(hc_plays_by_platform_by_stream_type_options);
|
var hc_plays_by_platform_by_stream_type = new Highcharts.Chart(hc_plays_by_platform_by_stream_type_options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -530,6 +557,7 @@
|
|||||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||||
hc_plays_by_user_by_stream_type_options.xAxis.categories = data.categories;
|
hc_plays_by_user_by_stream_type_options.xAxis.categories = data.categories;
|
||||||
hc_plays_by_user_by_stream_type_options.series = getGraphVisibility(hc_plays_by_user_by_stream_type_options.chart.renderTo, data.series);
|
hc_plays_by_user_by_stream_type_options.series = getGraphVisibility(hc_plays_by_user_by_stream_type_options.chart.renderTo, data.series);
|
||||||
|
hc_plays_by_user_by_stream_type_options.colors = getGraphColors(data.series);
|
||||||
var hc_plays_by_user_by_stream_type = new Highcharts.Chart(hc_plays_by_user_by_stream_type_options);
|
var hc_plays_by_user_by_stream_type = new Highcharts.Chart(hc_plays_by_user_by_stream_type_options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -553,6 +581,7 @@
|
|||||||
hc_plays_by_month_options.yAxis.min = 0;
|
hc_plays_by_month_options.yAxis.min = 0;
|
||||||
hc_plays_by_month_options.xAxis.categories = data.categories;
|
hc_plays_by_month_options.xAxis.categories = data.categories;
|
||||||
hc_plays_by_month_options.series = getGraphVisibility(hc_plays_by_month_options.chart.renderTo, data.series);
|
hc_plays_by_month_options.series = getGraphVisibility(hc_plays_by_month_options.chart.renderTo, data.series);
|
||||||
|
hc_plays_by_month_options.colors = getGraphColors(data.series);
|
||||||
var hc_plays_by_month = new Highcharts.Chart(hc_plays_by_month_options);
|
var hc_plays_by_month = new Highcharts.Chart(hc_plays_by_month_options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -44,6 +44,9 @@
|
|||||||
<label class="btn btn-dark">
|
<label class="btn btn-dark">
|
||||||
<input type="radio" name="media_type-filter" id="history-track" value="track" autocomplete="off"> Music
|
<input type="radio" name="media_type-filter" id="history-track" value="track" autocomplete="off"> Music
|
||||||
</label>
|
</label>
|
||||||
|
<label class="btn btn-dark">
|
||||||
|
<input type="radio" name="media_type-filter" id="history-live" value="live" autocomplete="off"> Live TV
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button class="btn btn-dark refresh-history-button" id="refresh-history-list"><i class="fa fa-refresh"></i> Refresh history</button>
|
<button class="btn btn-dark refresh-history-button" id="refresh-history-list"><i class="fa fa-refresh"></i> Refresh history</button>
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
<h4 class="modal-title" id="myModalLabel">
|
<h4 class="modal-title" id="myModalLabel">
|
||||||
<strong><span id="modal_header_ip_address">
|
<strong><span id="modal_header_ip_address">
|
||||||
% if data.get('media_type'):
|
% if data.get('media_type'):
|
||||||
<% h = {'episode': 'TV Show', 'track': 'Music'} %>
|
<% h = {'episode': 'TV Show', 'track': 'Music', 'live': 'Live TV'} %>
|
||||||
<i class="fa fa-history"></i> ${h.get(data['media_type'], data['media_type'].title())} History for <span id="date-header">${data['start_date']}</span>
|
<i class="fa fa-history"></i> ${h.get(data['media_type'], data['media_type'].title())} History for <span id="date-header">${data['start_date']}</span>
|
||||||
% elif data.get('transcode_decision'):
|
% elif data.get('transcode_decision'):
|
||||||
<% h = {'copy': 'Direct Stream'} %>
|
<% h = {'copy': 'Direct Stream'} %>
|
||||||
|
@@ -53,11 +53,11 @@ DOCUMENTATION :: END
|
|||||||
</%doc>
|
</%doc>
|
||||||
|
|
||||||
<%!
|
<%!
|
||||||
from plexpy import helpers
|
from plexpy.helpers import cast_to_int, page
|
||||||
|
|
||||||
# Human readable duration
|
# Human readable duration
|
||||||
def hd(seconds):
|
def hd(seconds):
|
||||||
m, s = divmod(helpers.cast_to_int(seconds), 60)
|
m, s = divmod(cast_to_int(seconds), 60)
|
||||||
h, m = divmod(m, 60)
|
h, m = divmod(m, 60)
|
||||||
return str(h).zfill(1) + ':' + str(m).zfill(2)
|
return str(h).zfill(1) + ':' + str(m).zfill(2)
|
||||||
%>
|
%>
|
||||||
@@ -72,11 +72,8 @@ DOCUMENTATION :: END
|
|||||||
<div class="dashboard-stats-instance" id="stats-instance-${stat_id}" data-stat_id="${stat_id}">
|
<div class="dashboard-stats-instance" id="stats-instance-${stat_id}" data-stat_id="${stat_id}">
|
||||||
<div class="dashboard-stats-container">
|
<div class="dashboard-stats-container">
|
||||||
% if stat_id in ('top_movies', 'popular_movies', 'top_tv', 'popular_tv', 'top_music', 'popular_music', 'last_watched'):
|
% if stat_id in ('top_movies', 'popular_movies', 'top_tv', 'popular_tv', 'top_music', 'popular_music', 'last_watched'):
|
||||||
% if row0['art']:
|
<% fallback = 'art-live' if row0['live'] else 'art' %>
|
||||||
<div id="stats-background-${stat_id}" class="dashboard-stats-background" style="background-image: url(pms_image_proxy?img=${row0['art']}&width=500&height=280&opacity=40&background=282828&blur=3&fallback=art);">
|
<div id="stats-background-${stat_id}" class="dashboard-stats-background" style="background-image: url(${page('pms_image_proxy', row0['art'], row0['rating_key'], 500, 280, 40, '282828', 3, fallback=fallback)});">
|
||||||
% else:
|
|
||||||
<div id="stats-background-${stat_id}" class="dashboard-stats-background" style="background-image: url(images/art.png);">
|
|
||||||
% endif
|
|
||||||
% elif stat_id == 'top_platforms':
|
% elif stat_id == 'top_platforms':
|
||||||
<div id="stats-background-${stat_id}" class="dashboard-stats-background platform-${row0['platform_name']}-rgba no-image">
|
<div id="stats-background-${stat_id}" class="dashboard-stats-background platform-${row0['platform_name']}-rgba no-image">
|
||||||
% else:
|
% else:
|
||||||
@@ -85,20 +82,28 @@ DOCUMENTATION :: END
|
|||||||
% if stat_id in ('top_movies', 'popular_movies', 'top_tv', 'popular_tv', 'top_music', 'popular_music', 'last_watched'):
|
% if stat_id in ('top_movies', 'popular_movies', 'top_tv', 'popular_tv', 'top_music', 'popular_music', 'last_watched'):
|
||||||
<div class="dashboard-stats-poster-container hidden-xs">
|
<div class="dashboard-stats-poster-container hidden-xs">
|
||||||
% if stat_id in ('top_music', 'popular_music'):
|
% if stat_id in ('top_music', 'popular_music'):
|
||||||
<div id="stats-thumb-${stat_id}-bg" class="dashboard-stats-poster" style="background-image: url(pms_image_proxy?img=${row0['thumb']}&width=300&height=300&opacity=60&background=282828&blur=3&fallback=cover);"></div>
|
<div id="stats-thumb-${stat_id}-bg" class="dashboard-stats-poster" style="background-image: url(${page('pms_image_proxy', row0['thumb'], row0['rating_key'], 300, 300, 60, '282828', 3, fallback='cover')});"></div>
|
||||||
% endif
|
% endif
|
||||||
<% height, type = ('300', 'cover') if stat_id in ('top_music', 'popular_music') else ('450', 'poster') %>
|
<%
|
||||||
<% href = 'info?rating_key={}'.format(row0['rating_key']) if row0['rating_key'] else '#' %>
|
height, fallback = ('450', 'poster')
|
||||||
|
if stat_id in ('top_music', 'popular_music'):
|
||||||
|
height, fallback = ('300', 'cover')
|
||||||
|
elif row0['live']:
|
||||||
|
height, fallback = ('450', 'poster-live')
|
||||||
|
|
||||||
|
href = '#'
|
||||||
|
if row0['rating_key']:
|
||||||
|
if row0['live']:
|
||||||
|
href = page('info', row0['rating_key'], row0['guid'], history=True, live=row0['live'])
|
||||||
|
else:
|
||||||
|
href = page('info', row0['rating_key'])
|
||||||
|
%>
|
||||||
<a id="stats-thumb-url-${stat_id}" href="${href}" title="${row0['title']}">
|
<a id="stats-thumb-url-${stat_id}" href="${href}" title="${row0['title']}">
|
||||||
% if row0['thumb']:
|
<div id="stats-thumb-${stat_id}" class="dashboard-stats-${fallback.split('-')[0]}" style="background-image: url(${page('pms_image_proxy', row0['thumb'], row0['rating_key'], 300, height, fallback=fallback)});"></div>
|
||||||
<div id="stats-thumb-${stat_id}" class="dashboard-stats-${type}" style="background-image: url(pms_image_proxy?img=${row0['thumb']}&width=300&height=${height}&fallback=${type});"></div>
|
|
||||||
% else:
|
|
||||||
<div id="stats-thumb-${stat_id}" class="dashboard-stats-${type}" style="background-image: url(images/${type}.png);"></div>
|
|
||||||
% endif
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
% elif stat_id == 'top_users':
|
% elif stat_id == 'top_users':
|
||||||
<% user_href = 'user?user_id={}'.format(row0['user_id']) if row0['user_id'] else '#' %>
|
<% user_href = page('user', row0['user_id']) if row0['user_id'] else '#' %>
|
||||||
<a id="stats-thumb-url-${stat_id}" href="${user_href}" title="${row0['friendly_name']}" class="hidden-xs">
|
<a id="stats-thumb-url-${stat_id}" href="${user_href}" title="${row0['friendly_name']}" class="hidden-xs">
|
||||||
<div id="stats-thumb-${stat_id}" class="dashboard-stats-circle" style="background-image: url(${row0['user_thumb'] or 'images/gravatar-default.png'})"></div>
|
<div id="stats-thumb-${stat_id}" class="dashboard-stats-circle" style="background-image: url(${row0['user_thumb'] or 'images/gravatar-default.png'})"></div>
|
||||||
</a>
|
</a>
|
||||||
@@ -126,19 +131,27 @@ DOCUMENTATION :: END
|
|||||||
<div class="dashboard-stats-info scoller-content">
|
<div class="dashboard-stats-info scoller-content">
|
||||||
<ul class="list-unstyled dashboard-stats-info-list">
|
<ul class="list-unstyled dashboard-stats-info-list">
|
||||||
% for row in top_stat['rows']:
|
% for row in top_stat['rows']:
|
||||||
<li class="dashboard-stats-info-item ${'expanded' if loop.index == 0 else ''}" data-stat_id="${stat_id}" data-rating_key="${row.get('rating_key')}" data-title="${row.get('title')}"
|
<li class="dashboard-stats-info-item ${'expanded' if loop.index == 0 else ''}" data-stat_id="${stat_id}"
|
||||||
|
data-rating_key="${row.get('rating_key')}" data-guid="${row.get('guid')}" data-title="${row.get('title')}"
|
||||||
data-art="${row.get('art')}" data-thumb="${row.get('thumb')}" data-platform="${row.get('platform_name')}"
|
data-art="${row.get('art')}" data-thumb="${row.get('thumb')}" data-platform="${row.get('platform_name')}"
|
||||||
data-user_id="${row.get('user_id')}" data-friendly_name="${row.get('friendly_name')}" data-user_thumb="${row.get('user_thumb')}"
|
data-user_id="${row.get('user_id')}" data-friendly_name="${row.get('friendly_name')}" data-user_thumb="${row.get('user_thumb')}"
|
||||||
data-last_watch="${row.get('last_watch')}" data-started="${row.get('started')}">
|
data-last_watch="${row.get('last_watch')}" data-started="${row.get('started')}" data-live="${row.get('live')}">
|
||||||
<div class="sub-list">${loop.index + 1}</div>
|
<div class="sub-list">${loop.index + 1}</div>
|
||||||
<div class="sub-value">
|
<div class="sub-value">
|
||||||
% if stat_id in ('top_movies', 'popular_movies', 'top_tv', 'popular_tv', 'top_music', 'popular_music', 'last_watched'):
|
% if stat_id in ('top_movies', 'popular_movies', 'top_tv', 'popular_tv', 'top_music', 'popular_music', 'last_watched'):
|
||||||
<% href = 'info?rating_key={}'.format(row['rating_key']) if row['rating_key'] else '#' %>
|
<%
|
||||||
|
href = '#'
|
||||||
|
if row['rating_key']:
|
||||||
|
if row['live']:
|
||||||
|
href = page('info', row['rating_key'], row['guid'], history=True, live=row['live'])
|
||||||
|
else:
|
||||||
|
href = page('info', row['rating_key'])
|
||||||
|
%>
|
||||||
<a href="${href}" title="${row['title']}">
|
<a href="${href}" title="${row['title']}">
|
||||||
${row['title']}
|
${row['title']}
|
||||||
</a>
|
</a>
|
||||||
% elif stat_id == 'top_users':
|
% elif stat_id == 'top_users':
|
||||||
<% user_href = 'user?user_id={}'.format(row['user_id']) if row['user_id'] else '#' %>
|
<% user_href = page('user', row['user_id']) if row['user_id'] else '#' %>
|
||||||
<a href="${user_href}" title="${row['friendly_name']}">
|
<a href="${user_href}" title="${row['friendly_name']}">
|
||||||
${row['friendly_name']}
|
${row['friendly_name']}
|
||||||
</a>
|
</a>
|
||||||
@@ -170,78 +183,6 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
% endif
|
% endif
|
||||||
% endfor
|
% endfor
|
||||||
<script>
|
|
||||||
$('.dashboard-stats-instance .dashboard-stats-info-scroller').scrollbar()
|
|
||||||
|
|
||||||
function changeImages(elem) {
|
|
||||||
var stat_id = $(elem).data('stat_id');
|
|
||||||
var art = $(elem).data('art');
|
|
||||||
var thumb = $(elem).data('thumb');
|
|
||||||
var user_id = $(elem).data('user_id');
|
|
||||||
var user_thumb = $(elem).data('user_thumb');
|
|
||||||
var rating_key = $(elem).data('rating_key');
|
|
||||||
var [height, fallback] = ($.inArray(stat_id, ['top_music', 'popular_music']) > -1) ? [300, 'cover'] : [450, 'poster'];
|
|
||||||
var href;
|
|
||||||
|
|
||||||
if (stat_id == 'most_concurrent') {
|
|
||||||
return
|
|
||||||
} else if (stat_id == 'top_users') {
|
|
||||||
$('#stats-thumb-' + stat_id).css('background-image', 'url(' + (user_thumb || 'images/gravatar-default.png') + ')');
|
|
||||||
if (user_id) {
|
|
||||||
href = 'user?user_id=' + user_id;
|
|
||||||
} else {
|
|
||||||
href = '#';
|
|
||||||
}
|
|
||||||
$('#stats-thumb-url-' + stat_id).attr('href', href).prop('title', $(elem).data('friendly_name'));
|
|
||||||
} else if (stat_id == 'top_platforms') {
|
|
||||||
$('#stats-thumb-' + stat_id).removeClass(function (index, className) {
|
|
||||||
return (className.match (/(^|\s)platform-\S+/g) || []).join(' ');
|
|
||||||
}).addClass('platform-' + $(elem).data('platform'));
|
|
||||||
$('#stats-background-' + stat_id).removeClass(function (index, className) {
|
|
||||||
return (className.match (/(^|\s)platform-\S+/g) || []).join(' ');
|
|
||||||
}).addClass('platform-' + $(elem).data('platform') + '-rgba');
|
|
||||||
} else {
|
|
||||||
if (rating_key) {
|
|
||||||
href = 'info?rating_key=' + rating_key;
|
|
||||||
} else {
|
|
||||||
href = '#';
|
|
||||||
}
|
|
||||||
$('#stats-thumb-url-' + stat_id).attr('href', href).prop('title', $(elem).data('title'));
|
|
||||||
if (art) {
|
|
||||||
$('#stats-background-' + stat_id).css('background-image', 'url(pms_image_proxy?img=' + art + '&width=500&height=280&opacity=40&background=282828&blur=3&fallback=art)');
|
|
||||||
} else {
|
|
||||||
$('#stats-background-' + stat_id).css('background-image', 'url(images/art.png)');
|
|
||||||
}
|
|
||||||
if (thumb) {
|
|
||||||
$('#stats-thumb-' + stat_id).css('background-image', 'url(pms_image_proxy?img=' + thumb + '&width=300&height=' + height + '&fallback=' + fallback + ')');
|
|
||||||
$('#stats-thumb-' + stat_id + '-bg').css('background-image', 'url(pms_image_proxy?img=' + thumb + '&width=300&height=' + height + '&opacity=60&background=282828&blur=3&fallback=' + fallback + ')');
|
|
||||||
} else {
|
|
||||||
$('#stats-thumb-' + stat_id).css('background-image', 'url(images/' + fallback + '.png)');
|
|
||||||
$('#stats-thumb-' + stat_id + '-bg').css('background-image', 'url(images/' + fallback + '.png)');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$('.dashboard-stats-info-item').mouseenter(function () {
|
|
||||||
changeImages(this)
|
|
||||||
if ($(this).data('stat_id') == 'last_watched') {
|
|
||||||
var friendly_name = $(this).data('friendly_name');
|
|
||||||
var last_watch = moment($(this).data('last_watch'), 'X').format(date_format);
|
|
||||||
$('#last-watched-header-info').html(friendly_name);
|
|
||||||
} else if ($(this).data('stat_id') == 'most_concurrent') {
|
|
||||||
var started = moment($(this).data('started'), 'X').format(date_format + ' ' + time_format);
|
|
||||||
$('#most-concurrent-header-info').html(started);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$('.dashboard-stats-instance').mouseleave(function () {
|
|
||||||
changeImages($(this).find('.dashboard-stats-info-item').first())
|
|
||||||
if ($(this).data('stat_id') == 'last_watched') {
|
|
||||||
$('#last-watched-header-info').text($(this).find('.dashboard-stats-info-item').first().data('friendly_name'));
|
|
||||||
} else if ($(this).data('stat_id') == 'most_concurrent') {
|
|
||||||
$('#most-concurrent-header-info').text('streams');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
% else:
|
% else:
|
||||||
<div class="text-muted">No stats to show for the selected period.</div><br>
|
<div class="text-muted">No stats to show for the selected period.</div><br>
|
||||||
% endif
|
% endif
|
BIN
data/interfaces/default/images/art-live-full.png
Normal file
BIN
data/interfaces/default/images/art-live-full.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 786 KiB |
BIN
data/interfaces/default/images/libraries/live.png
Normal file
BIN
data/interfaces/default/images/libraries/live.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
9
data/interfaces/default/images/libraries/live.svg
Normal file
9
data/interfaces/default/images/libraries/live.svg
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<!-- Generated by IcoMoon.io -->
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||||
|
<title>live</title>
|
||||||
|
<path fill="#fff" d="M9.636 10.115c-0.829 0.544-1.243 0.816-2.072 1.361-2.331-3.547-2.331-6.195 0-9.749 0.829 0.546 1.244 0.819 2.072 1.361-1.68 2.557-1.68 4.464 0 7.027z"></path>
|
||||||
|
<path fill="#fff" d="M4.374 11.662c-0.828 0.542-1.243 0.815-2.072 1.359-3.069-4.676-3.069-8.159 0-12.838 0.829 0.546 1.244 0.817 2.072 1.362-2.418 3.684-2.418 6.426 0 10.117z"></path>
|
||||||
|
<path fill="#fff" d="M22.365 10.115c0.826 0.544 1.242 0.816 2.070 1.361 2.334-3.547 2.334-6.195 0-9.749-0.828 0.546-1.244 0.819-2.070 1.361 1.677 2.557 1.677 4.464 0 7.027z"></path>
|
||||||
|
<path fill="#fff" d="M27.627 11.662c0.827 0.542 1.243 0.815 2.070 1.359 3.070-4.676 3.070-8.159 0-12.838-0.827 0.546-1.243 0.817-2.070 1.362 2.419 3.684 2.419 6.426 0 10.117z"></path>
|
||||||
|
<path fill="#fff" d="M25.211 31.982l2.611-0.95-8.172-22.45c0.32-0.589 0.502-1.263 0.502-1.979 0-2.293-1.859-4.152-4.152-4.152s-4.151 1.858-4.151 4.152c0 0.672 0.16 1.305 0.443 1.868l-8.212 22.561 2.612 0.95 1.952-5.362h14.616l1.951 5.362zM17.396 10.513l3.945 10.834-7.903-7.9 1.080-2.966c0.46 0.176 0.96 0.272 1.481 0.272 0.49 0.001 0.961-0.084 1.397-0.24zM12.39 16.329l7.51 7.512h-10.245l2.735-7.512z"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
@@ -334,13 +334,13 @@
|
|||||||
streams_header = streams_header.replace(/, $/, '') + ')';
|
streams_header = streams_header.replace(/, $/, '') + ')';
|
||||||
$('#currentActivityHeader-streams').text(streams_header);
|
$('#currentActivityHeader-streams').text(streams_header);
|
||||||
|
|
||||||
var bandwidth_header = ((total_bw > 1000) ? ((total_bw / 1000).toFixed(1) + ' Mbps') : (total_bw + ' kbps'));
|
var bandwidth_header = ((total_bw > 1000000) ? ((total_bw / 1000000).toFixed(1) + ' Gbps') : ((total_bw > 1000) ? ((total_bw / 1000).toFixed(1) + ' Mbps') : (total_bw + ' kbps')));
|
||||||
var lan_wan_bandwidth_header = '';
|
var lan_wan_bandwidth_header = '';
|
||||||
if (lan_bw) {
|
if (lan_bw) {
|
||||||
lan_wan_bandwidth_header += 'LAN: ' + ((lan_bw > 1000) ? ((lan_bw / 1000).toFixed(1) + ' Mbps') : (lan_bw + ' kbps')) + ', ';
|
lan_wan_bandwidth_header += 'LAN: ' + ((lan_bw > 1000000) ? ((lan_bw / 1000000).toFixed(1) + ' Gbps') : ((lan_bw > 1000) ? ((lan_bw / 1000).toFixed(1) + ' Mbps') : (lan_bw + ' kbps'))) + ', ';
|
||||||
}
|
}
|
||||||
if (wan_bw) {
|
if (wan_bw) {
|
||||||
lan_wan_bandwidth_header += 'WAN: ' + ((wan_bw > 1000) ? ((wan_bw / 1000).toFixed(1) + ' Mbps') : (wan_bw + ' kbps')) + ', ';
|
lan_wan_bandwidth_header += 'WAN: ' + ((wan_bw > 1000000) ? ((wan_bw / 1000000).toFixed(1) + ' Gbps') : ((wan_bw > 1000) ? ((wan_bw / 1000).toFixed(1) + ' Mbps') : (wan_bw + ' kbps'))) + ', ';
|
||||||
}
|
}
|
||||||
if (lan_wan_bandwidth_header) {
|
if (lan_wan_bandwidth_header) {
|
||||||
bandwidth_header += ' (' + lan_wan_bandwidth_header.replace(/, $/, '') + ')';
|
bandwidth_header += ' (' + lan_wan_bandwidth_header.replace(/, $/, '') + ')';
|
||||||
@@ -356,8 +356,10 @@
|
|||||||
var instance = $('#activity-instance-' + key);
|
var instance = $('#activity-instance-' + key);
|
||||||
|
|
||||||
// Create a new instance if it doesn't exist or recreate the entire instance
|
// Create a new instance if it doesn't exist or recreate the entire instance
|
||||||
// if the rating key changed (for movies or episodes) with the same session key
|
// if the rating key changed (for movies or episodes) of guid changed (for live tv) with the same session key
|
||||||
if (!(instance.length) || (s.media_type !== 'track' && s.rating_key !== instance.data('rating_key').toString())) {
|
if (!(instance.length) ||
|
||||||
|
(s.media_type !== 'track' && s.rating_key !== instance.data('rating_key').toString()) ||
|
||||||
|
(s.live === 1 && s.guid !== instance.data('guid'))) {
|
||||||
create_instances.push(key);
|
create_instances.push(key);
|
||||||
getActivityInstance(key);
|
getActivityInstance(key);
|
||||||
return;
|
return;
|
||||||
@@ -384,32 +386,32 @@
|
|||||||
if (s.media_type === 'track') {
|
if (s.media_type === 'track') {
|
||||||
// Update if artist changed
|
// Update if artist changed
|
||||||
if (s.grandparent_rating_key !== instance.data('grandparent_rating_key').toString()) {
|
if (s.grandparent_rating_key !== instance.data('grandparent_rating_key').toString()) {
|
||||||
$('#background-' + key).css('background-image', 'url(pms_image_proxy?img=' + s.art + '&width=500&height=280&opacity=40&background=282828&blur=3&fallback=art&refresh=true)');
|
$('#background-' + key).css('background-image', 'url(' + page('pms_image_proxy', s.art, s.rating_key, 500, 280, 40, '282828', 3, 'art', true) + ')');
|
||||||
$('#metadata-grandparent_title-' + key)
|
$('#metadata-grandparent_title-' + key)
|
||||||
.attr('href', 'info?rating_key=' + s.grandparent_rating_key)
|
.attr('href', page('info', s.grandparent_rating_key))
|
||||||
.attr('title', s.original_title || s.grandparent_title)
|
.attr('title', s.original_title || s.grandparent_title)
|
||||||
.text(s.original_title || s.grandparent_title);
|
.text(s.original_title || s.grandparent_title);
|
||||||
}
|
}
|
||||||
// Update cover if album changed
|
// Update cover if album changed
|
||||||
if (s.parent_rating_key !== instance.data('parent_rating_key').toString()) {
|
if (s.parent_rating_key !== instance.data('parent_rating_key').toString()) {
|
||||||
$('#poster-' + key).css('background-image', 'url(pms_image_proxy?img=' + s.parent_thumb + '&width=300&height=300&fallback=poster&refresh=true)');
|
$('#poster-' + key).css('background-image', 'url(' + page('pms_image_proxy', s.parent_thumb, s.parent_rating_key, 300, 300, null, null, null, 'poster', true) + ')');
|
||||||
$('#poster-' + key + '-bg').css('background-image', 'url(pms_image_proxy?img=' + s.parent_thumb + '&width=300&height=300&opacity=60&background=282828&blur=3&fallback=poster&refresh=true)');
|
$('#poster-' + key + '-bg').css('background-image', 'url(' + page('pms_image_proxy', s.parent_thumb, s.parent_rating_key, 300, 300, 60, '282828', 3, 'poster', true) + ')');
|
||||||
$('#poster-url-' + key)
|
$('#poster-url-' + key)
|
||||||
.attr('href', 'info?rating_key=' + s.parent_rating_key)
|
.attr('href', page('info', s.parent_rating_key))
|
||||||
.attr('title', s.parent_title);
|
.attr('title', s.parent_title);
|
||||||
$('#metadata-parent_title-' + key)
|
$('#metadata-parent_title-' + key)
|
||||||
.attr('href', 'info?rating_key=' + s.parent_rating_key)
|
.attr('href', page('info', s.parent_rating_key))
|
||||||
.attr('title', s.parent_title)
|
.attr('title', s.parent_title)
|
||||||
.text(s.parent_title);
|
.text(s.parent_title);
|
||||||
}
|
}
|
||||||
// Update cover if track changed
|
// Update cover if track changed
|
||||||
if (s.rating_key !== instance.data('rating_key').toString()) {
|
if (s.rating_key !== instance.data('rating_key').toString()) {
|
||||||
$('#metadata-grandparent_title-' + key)
|
$('#metadata-grandparent_title-' + key)
|
||||||
.attr('href', 'info?rating_key=' + s.grandparent_rating_key)
|
.attr('href', page('info', s.grandparent_rating_key))
|
||||||
.attr('title', s.original_title || s.grandparent_title)
|
.attr('title', s.original_title || s.grandparent_title)
|
||||||
.text(s.original_title || s.grandparent_title);
|
.text(s.original_title || s.grandparent_title);
|
||||||
$('#metadata-title-' + key)
|
$('#metadata-title-' + key)
|
||||||
.attr('href', 'info?rating_key=' + s.rating_key)
|
.attr('href', page('info', s.rating_key))
|
||||||
.attr('title', s.title)
|
.attr('title', s.title)
|
||||||
.text(s.title);
|
.text(s.title);
|
||||||
}
|
}
|
||||||
@@ -524,7 +526,9 @@
|
|||||||
|
|
||||||
if (s.media_type !== 'photo' && s.bandwidth !== 'Unknown') {
|
if (s.media_type !== 'photo' && s.bandwidth !== 'Unknown') {
|
||||||
var bw = parseInt(s.bandwidth) || 0;
|
var bw = parseInt(s.bandwidth) || 0;
|
||||||
if (bw > 1000) {
|
if (bw > 1000000) {
|
||||||
|
bw = (bw / 1000000).toFixed(1) + ' Gbps';
|
||||||
|
} else if (bw > 1000) {
|
||||||
bw = (bw / 1000).toFixed(1) + ' Mbps';
|
bw = (bw / 1000).toFixed(1) + ' Mbps';
|
||||||
} else {
|
} else {
|
||||||
bw = bw + ' kbps'
|
bw = bw + ' kbps'
|
||||||
@@ -543,11 +547,13 @@
|
|||||||
// Update the progress bars, percent - 3 because of 3px padding-right
|
// Update the progress bars, percent - 3 because of 3px padding-right
|
||||||
$('#buffer-bar-' + key).width(parseInt(s.transcode_progress) - 3 + '%').html(s.transcode_progress + '%')
|
$('#buffer-bar-' + key).width(parseInt(s.transcode_progress) - 3 + '%').html(s.transcode_progress + '%')
|
||||||
.attr('data-original-title', 'Transcoder Progress ' + s.transcode_progress + '%');
|
.attr('data-original-title', 'Transcoder Progress ' + s.transcode_progress + '%');
|
||||||
|
if (s.live !== 1) {
|
||||||
var progress_bar = $('#progress-bar-' + key);
|
var progress_bar = $('#progress-bar-' + key);
|
||||||
progress_bar.data('state', s.state);
|
progress_bar.data('state', s.state);
|
||||||
if (progress_bar.data('last_view_offset') !== s.view_offset) {
|
if (progress_bar.data('last_view_offset') !== s.view_offset) {
|
||||||
progress_bar.data('last_view_offset', s.view_offset).data('view_offset', s.view_offset);
|
progress_bar.data('last_view_offset', s.view_offset).data('view_offset', s.view_offset);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add temporary class so we know which instances are still active
|
// Add temporary class so we know which instances are still active
|
||||||
instance.addClass('updated-temp');
|
instance.addClass('updated-temp');
|
||||||
@@ -559,6 +565,7 @@
|
|||||||
$(instance).removeClass('updated-temp');
|
$(instance).removeClass('updated-temp');
|
||||||
} else {
|
} else {
|
||||||
$(instance).find('[data-toggle=tooltip]').tooltip('destroy');
|
$(instance).find('[data-toggle=tooltip]').tooltip('destroy');
|
||||||
|
$(instance).find('[data-toggle=popover]').popover('destroy');
|
||||||
$(instance).remove();
|
$(instance).remove();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -593,6 +600,17 @@
|
|||||||
|
|
||||||
$('#activity-instance-' + session_key + ' .dashboard-activity-info-scroller').scrollbar();
|
$('#activity-instance-' + session_key + ' .dashboard-activity-info-scroller').scrollbar();
|
||||||
$('#activity-instance-' + session_key + ' [data-toggle=tooltip]').tooltip({ container: 'body', placement: 'right', delay: 50 });
|
$('#activity-instance-' + session_key + ' [data-toggle=tooltip]').tooltip({ container: 'body', placement: 'right', delay: 50 });
|
||||||
|
$('#activity-instance-' + session_key + ' [data-toggle=popover]').popover({
|
||||||
|
html: true,
|
||||||
|
container: 'body',
|
||||||
|
trigger: 'hover',
|
||||||
|
placement: 'right',
|
||||||
|
delay: 50,
|
||||||
|
template: '<div class="popover channel-thumbnail-popover" role="tooltip"><div class="arrow" style="top: 50%;"></div><div class="popover-content"></div></div>',
|
||||||
|
content: function () {
|
||||||
|
return '<div class="channel-thumbnail" style="background-image: url(' + $(this).data('img') + ');" />';
|
||||||
|
}
|
||||||
|
});
|
||||||
$('#terminate-button-' + session_key).tooltip('destroy').tooltip({ container: 'body', placement: 'left', delay: 50 });
|
$('#terminate-button-' + session_key).tooltip('destroy').tooltip({ container: 'body', placement: 'left', delay: 50 });
|
||||||
lockScroll('#activity-instance-' + session_key + ' .dashboard-activity-info-scroller');
|
lockScroll('#activity-instance-' + session_key + ' .dashboard-activity-info-scroller');
|
||||||
|
|
||||||
@@ -708,6 +726,88 @@
|
|||||||
% endif
|
% endif
|
||||||
</script>
|
</script>
|
||||||
% endif
|
% endif
|
||||||
|
% if 'watch_stats' in config['home_sections'] or 'library_stats' in config['home_sections']:
|
||||||
|
<script>
|
||||||
|
function statsCardCallback() {
|
||||||
|
$('.dashboard-stats-instance .dashboard-stats-info-scroller').scrollbar();
|
||||||
|
|
||||||
|
function changeImages(elem) {
|
||||||
|
var stat_id = $(elem).data('stat_id');
|
||||||
|
var art = $(elem).data('art');
|
||||||
|
var thumb = $(elem).data('thumb');
|
||||||
|
var user_id = $(elem).data('user_id');
|
||||||
|
var user_thumb = $(elem).data('user_thumb');
|
||||||
|
var rating_key = $(elem).data('rating_key');
|
||||||
|
var guid = $(elem).data('guid');
|
||||||
|
var live = $(elem).data('live');
|
||||||
|
var [height, fallback_poster, fallback_art] = [450, 'poster', 'art'];
|
||||||
|
if ($.inArray(stat_id, ['top_music', 'popular_music']) > -1) {
|
||||||
|
[height, fallback_poster, fallback_art] = [300, 'cover', 'art'];
|
||||||
|
} else if (live) {
|
||||||
|
[height, fallback_poster, fallback_art] = [450, 'poster-live', 'art-live'];
|
||||||
|
}
|
||||||
|
var href = '#';
|
||||||
|
|
||||||
|
if (stat_id === 'most_concurrent') {
|
||||||
|
return
|
||||||
|
} else if (stat_id === 'top_users') {
|
||||||
|
$('#stats-thumb-' + stat_id).css('background-image', 'url(' + (user_thumb || 'images/gravatar-default.png') + ')');
|
||||||
|
if (user_id) {
|
||||||
|
href = page('user', user_id);
|
||||||
|
}
|
||||||
|
$('#stats-thumb-url-' + stat_id).attr('href', href).prop('title', $(elem).data('friendly_name'));
|
||||||
|
} else if (stat_id === 'top_platforms') {
|
||||||
|
$('#stats-thumb-' + stat_id).removeClass(function (index, className) {
|
||||||
|
return (className.match (/(^|\s)platform-\S+/g) || []).join(' ');
|
||||||
|
}).addClass('platform-' + $(elem).data('platform'));
|
||||||
|
$('#stats-background-' + stat_id).removeClass(function (index, className) {
|
||||||
|
return (className.match (/(^|\s)platform-\S+/g) || []).join(' ');
|
||||||
|
}).addClass('platform-' + $(elem).data('platform') + '-rgba');
|
||||||
|
} else {
|
||||||
|
if (rating_key) {
|
||||||
|
if (live) {
|
||||||
|
href = page('info', rating_key, guid, true, live);
|
||||||
|
} else {
|
||||||
|
href = page('info', rating_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('#stats-thumb-url-' + stat_id).attr('href', href).prop('title', $(elem).data('title'));
|
||||||
|
$('#stats-background-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', art, rating_key, 500, 280, 40, '282828', 3, fallback_art) + ')');
|
||||||
|
$('#stats-thumb-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', thumb, rating_key, 300, height, null, null, null, fallback_poster) + ')');
|
||||||
|
$('#stats-thumb-' + stat_id + '-bg').css('background-image', 'url(' + page('pms_image_proxy', thumb, rating_key, 300, height, 60, '282828', 3, fallback_poster) + ')');
|
||||||
|
$('#library-stats-background-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', art, rating_key, 500, 280, 40, '282828', 3, fallback_art) + ')');
|
||||||
|
if (thumb.startsWith('http')) {
|
||||||
|
$('#library-stats-thumb-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', thumb, rating_key, 300, 300, null, null, null, 'cover') + ')')
|
||||||
|
.removeClass('svg-icon library-' + stat_id);
|
||||||
|
} else {
|
||||||
|
$('#library-stats-thumb-' + stat_id).css('background-image', '')
|
||||||
|
.addClass('svg-icon library-' + stat_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$('.dashboard-stats-info-item').mouseenter(function () {
|
||||||
|
changeImages(this);
|
||||||
|
if ($(this).data('stat_id') === 'last_watched') {
|
||||||
|
var friendly_name = $(this).data('friendly_name');
|
||||||
|
var last_watch = moment($(this).data('last_watch'), 'X').format(date_format);
|
||||||
|
$('#last-watched-header-info').html(friendly_name);
|
||||||
|
} else if ($(this).data('stat_id') === 'most_concurrent') {
|
||||||
|
var started = moment($(this).data('started'), 'X').format(date_format + ' ' + time_format);
|
||||||
|
$('#most-concurrent-header-info').html(started);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$('.dashboard-stats-instance').mouseleave(function () {
|
||||||
|
changeImages($(this).find('.dashboard-stats-info-item').first());
|
||||||
|
if ($(this).data('stat_id') === 'last_watched') {
|
||||||
|
$('#last-watched-header-info').text($(this).find('.dashboard-stats-info-item').first().data('friendly_name'));
|
||||||
|
} else if ($(this).data('stat_id') === 'most_concurrent') {
|
||||||
|
$('#most-concurrent-header-info').text('streams');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
% endif
|
||||||
% if 'watch_stats' in config['home_sections']:
|
% if 'watch_stats' in config['home_sections']:
|
||||||
<script>
|
<script>
|
||||||
function getHomeStats(time_range, stats_type) {
|
function getHomeStats(time_range, stats_type) {
|
||||||
@@ -726,6 +826,7 @@
|
|||||||
$("#home-stats").html(xhr.responseText);
|
$("#home-stats").html(xhr.responseText);
|
||||||
$('#ajaxMsg').fadeOut();
|
$('#ajaxMsg').fadeOut();
|
||||||
lockScroll('#home-stats .dashboard-stats-info-scroller');
|
lockScroll('#home-stats .dashboard-stats-info-scroller');
|
||||||
|
statsCardCallback();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -765,6 +866,7 @@
|
|||||||
data: { },
|
data: { },
|
||||||
complete: function (xhr, status) {
|
complete: function (xhr, status) {
|
||||||
$("#library-stats").html(xhr.responseText);
|
$("#library-stats").html(xhr.responseText);
|
||||||
|
statsCardCallback();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -36,10 +36,12 @@ DOCUMENTATION :: END
|
|||||||
</%doc>
|
</%doc>
|
||||||
|
|
||||||
<%!
|
<%!
|
||||||
|
from collections import defaultdict
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from plexpy import notifiers
|
from plexpy import notifiers
|
||||||
from plexpy.common import MEDIA_TYPE_HEADERS, MEDIA_FLAGS_AUDIO, MEDIA_FLAGS_VIDEO
|
from plexpy.common import MEDIA_TYPE_HEADERS, MEDIA_FLAGS_AUDIO, MEDIA_FLAGS_VIDEO
|
||||||
|
from plexpy.helpers import page
|
||||||
|
|
||||||
# Get audio codec file
|
# Get audio codec file
|
||||||
def af(codec):
|
def af(codec):
|
||||||
@@ -48,13 +50,20 @@ DOCUMENTATION :: END
|
|||||||
return file_type
|
return file_type
|
||||||
return codec
|
return codec
|
||||||
|
|
||||||
# Get audio codec file
|
# Get video codec file
|
||||||
def vf(codec):
|
def vf(codec):
|
||||||
for pattern, file_type in MEDIA_FLAGS_VIDEO.iteritems():
|
for pattern, file_type in MEDIA_FLAGS_VIDEO.iteritems():
|
||||||
if re.match(pattern, codec):
|
if re.match(pattern, codec):
|
||||||
return file_type
|
return file_type
|
||||||
return codec
|
return codec
|
||||||
|
|
||||||
|
# Get video resolution file
|
||||||
|
def vr(resolution):
|
||||||
|
if resolution in ('1080i', '576i', '480i'):
|
||||||
|
return resolution
|
||||||
|
else:
|
||||||
|
return resolution.lower().rstrip('ip')
|
||||||
|
|
||||||
def br(text):
|
def br(text):
|
||||||
return text.replace('\n', '<br /><br />')
|
return text.replace('\n', '<br /><br />')
|
||||||
%>
|
%>
|
||||||
@@ -68,11 +77,15 @@ DOCUMENTATION :: END
|
|||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="body()">
|
<%def name="body()">
|
||||||
% if data:
|
% if metadata:
|
||||||
<% media_info = data['media_info'][0] if data['media_info'] else {} %>
|
<%
|
||||||
|
data = defaultdict(lambda: None, **metadata)
|
||||||
|
media_info = defaultdict(lambda: None, **(data['media_info'][0] if data['media_info'] else {}))
|
||||||
|
%>
|
||||||
<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>
|
<% fallback = 'art-live-full' if data['live'] else None %>
|
||||||
|
<div class="art-face" style="background-image:url(${page('pms_image_proxy', data['art'], data['rating_key'], 1920, 1080, fallback=fallback)})"></div>
|
||||||
% if _session['user_group'] == 'admin':
|
% if _session['user_group'] == 'admin':
|
||||||
<span class="overlay-refresh-image info-art" title="Refresh background image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
<span class="overlay-refresh-image info-art" title="Refresh background image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
@@ -81,44 +94,60 @@ DOCUMENTATION :: END
|
|||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="summary-navbar-list">
|
<div class="summary-navbar-list">
|
||||||
<ul class="list-unstyled breadcrumb">
|
<ul class="list-unstyled breadcrumb">
|
||||||
% if data['media_type'] in ('movie', 'collection'):
|
% if data['live']:
|
||||||
<li><a href="library?section_id=${data['section_id']}">${data['library_name']}</a></li>
|
<li><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||||
|
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||||
|
% if data['media_type'] == 'movie':
|
||||||
|
<li class="active metadata-xml">${data['title']}</li>
|
||||||
|
% elif data['media_type'] == 'episode':
|
||||||
|
<li class="hidden-xs hidden-sm">${data['grandparent_title']}</li>
|
||||||
|
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||||
|
% if data['media_index']:
|
||||||
|
<li>Season ${data['parent_media_index']}</li>
|
||||||
|
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||||
|
<li class="active metadata-xml">Episode ${data['media_index']} - ${data['title']}</li>
|
||||||
|
% else:
|
||||||
|
<li class="active metadata-xml">${data['title']}</li>
|
||||||
|
% endif
|
||||||
|
% endif
|
||||||
|
% elif data['media_type'] in ('movie', 'collection'):
|
||||||
|
<li><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||||
<li class="active metadata-xml">${data['title']}</li>
|
<li class="active metadata-xml">${data['title']}</li>
|
||||||
% elif data['media_type'] == 'show':
|
% elif data['media_type'] == 'show':
|
||||||
<li><a href="library?section_id=${data['section_id']}">${data['library_name']}</a></li>
|
<li><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||||
<li class="active metadata-xml">${data['title']}</li>
|
<li class="active metadata-xml">${data['title']}</li>
|
||||||
% elif data['media_type'] == 'season':
|
% elif data['media_type'] == 'season':
|
||||||
<li class="hidden-xs hidden-sm"><a href="library?section_id=${data['section_id']}">${data['library_name']}</a></li>
|
<li class="hidden-xs hidden-sm"><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||||
<li><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a></li>
|
<li><a href="${page('info', data['parent_rating_key'])}">${data['parent_title']}</a></li>
|
||||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||||
<li class="active metadata-xml">Season ${data['media_index']}</li>
|
<li class="active metadata-xml">Season ${data['media_index']}</li>
|
||||||
% elif data['media_type'] == 'episode':
|
% elif data['media_type'] == 'episode':
|
||||||
<li class="hidden-xs hidden-sm"><a href="library?section_id=${data['section_id']}">${data['library_name']}</a></li>
|
<li class="hidden-xs hidden-sm"><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||||
<li class="hidden-xs hidden-sm"><a href="info?rating_key=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></li>
|
<li class="hidden-xs hidden-sm"><a href="${page('info', data['grandparent_rating_key'])}">${data['grandparent_title']}</a></li>
|
||||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||||
<li><a href="info?rating_key=${data['parent_rating_key']}">Season ${data['parent_media_index']}</a></li>
|
<li><a href="${page('info', data['parent_rating_key'])}">Season ${data['parent_media_index']}</a></li>
|
||||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||||
<li class="active metadata-xml">Episode ${data['media_index']} - ${data['title']}</li>
|
<li class="active metadata-xml">Episode ${data['media_index']} - ${data['title']}</li>
|
||||||
% elif data['media_type'] == 'artist':
|
% elif data['media_type'] == 'artist':
|
||||||
<li><a href="library?section_id=${data['section_id']}">${data['library_name']}</a></li>
|
<li><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||||
<li class="active metadata-xml">${data['title']}</li>
|
<li class="active metadata-xml">${data['title']}</li>
|
||||||
% elif data['media_type'] == 'album':
|
% elif data['media_type'] == 'album':
|
||||||
<li class="hidden-xs hidden-sm"><a href="library?section_id=${data['section_id']}">${data['library_name']}</a></li>
|
<li class="hidden-xs hidden-sm"><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||||
<li><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a></li>
|
<li><a href="${page('info', data['parent_rating_key'])}">${data['parent_title']}</a></li>
|
||||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||||
<li class="active metadata-xml">${data['title']}</li>
|
<li class="active metadata-xml">${data['title']}</li>
|
||||||
% elif data['media_type'] == 'track':
|
% elif data['media_type'] == 'track':
|
||||||
<li class="hidden-xs hidden-sm"><a href="library?section_id=${data['section_id']}">${data['library_name']}</a></li>
|
<li class="hidden-xs hidden-sm"><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||||
<li class="hidden-xs hidden-sm"><a href="info?rating_key=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></li>
|
<li class="hidden-xs hidden-sm"><a href="${page('info', data['grandparent_rating_key'])}">${data['grandparent_title']}</a></li>
|
||||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||||
<li><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a></li>
|
<li><a href="${page('info', data['parent_rating_key'])}">${data['parent_title']}</a></li>
|
||||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||||
<li class="active metadata-xml">Track ${data['media_index']} - ${data['title']}</li>
|
<li class="active metadata-xml">Track ${data['media_index']} - ${data['title']}</li>
|
||||||
% endif
|
% endif
|
||||||
@@ -131,11 +160,18 @@ DOCUMENTATION :: END
|
|||||||
<div class="summary-content-poster hidden-xs hidden-sm">
|
<div class="summary-content-poster hidden-xs hidden-sm">
|
||||||
% if data['media_type'] == 'track':
|
% if data['media_type'] == 'track':
|
||||||
<a href="${config['pms_web_url']}#!/server/${config['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${data['parent_rating_key']}" target="_blank" title="View on Plex Web">
|
<a href="${config['pms_web_url']}#!/server/${config['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${data['parent_rating_key']}" target="_blank" title="View on Plex Web">
|
||||||
% else:
|
% elif not data['live']:
|
||||||
<a href="${config['pms_web_url']}#!/server/${config['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${data['rating_key']}" target="_blank" title="View on Plex Web">
|
<a href="${config['pms_web_url']}#!/server/${config['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${data['rating_key']}" target="_blank" title="View on Plex Web">
|
||||||
% endif
|
% endif
|
||||||
|
% if data['live']:
|
||||||
|
<div class="summary-poster-face" style="background-image: url(${page('pms_image_proxy', data['grandparent_thumb'] or data['thumb'], data['rating_key'], 300, 450, fallback='poster-live')});">
|
||||||
|
<div class="summary-poster-face-overlay">
|
||||||
|
<span></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
% else:
|
||||||
% if data['media_type'] == 'episode':
|
% if data['media_type'] == 'episode':
|
||||||
<div class="summary-poster-face-episode" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=500&height=280&fallback=art);">
|
<div class="summary-poster-face-episode" style="background-image: url(${page('pms_image_proxy', data['thumb'], data['rating_key'], 500, 280, fallback='art')});">
|
||||||
<div class="summary-poster-face-overlay">
|
<div class="summary-poster-face-overlay">
|
||||||
<span></span>
|
<span></span>
|
||||||
</div>
|
</div>
|
||||||
@@ -144,7 +180,7 @@ DOCUMENTATION :: END
|
|||||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
% 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(${page('pms_image_proxy', data['thumb'], data['rating_key'], 500, 500, fallback='cover')});">
|
||||||
<div class="summary-poster-face-overlay">
|
<div class="summary-poster-face-overlay">
|
||||||
<span></span>
|
<span></span>
|
||||||
</div>
|
</div>
|
||||||
@@ -153,7 +189,7 @@ DOCUMENTATION :: END
|
|||||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
% 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(${page('pms_image_proxy', data['thumb'], data['rating_key'], 300, 450, fallback='poster')});">
|
||||||
<div class="summary-poster-face-overlay">
|
<div class="summary-poster-face-overlay">
|
||||||
<span></span>
|
<span></span>
|
||||||
</div>
|
</div>
|
||||||
@@ -162,24 +198,37 @@ DOCUMENTATION :: END
|
|||||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
% endif
|
% endif
|
||||||
|
% endif
|
||||||
|
% if not data['live']:
|
||||||
</a>
|
</a>
|
||||||
|
% endif
|
||||||
</div>
|
</div>
|
||||||
<div class="summary-content-title">
|
<div class="summary-content-title">
|
||||||
% if data['media_type'] in ('movie', 'show', 'artist', 'collection'):
|
% if data['live']:
|
||||||
|
% if data['media_type'] == 'movie':
|
||||||
|
<h1> </h1><h1>${data['title']}</h1>
|
||||||
|
% elif data['media_type'] == 'episode':
|
||||||
|
<h1>${data['grandparent_title']}</h1>
|
||||||
|
<h2>${data['title']}</h2>
|
||||||
|
% if data['media_index']:
|
||||||
|
<h3 class="hidden-xs">S${data['parent_media_index']} · E${data['media_index']}</h3>
|
||||||
|
% endif
|
||||||
|
% endif
|
||||||
|
% elif data['media_type'] in ('movie', 'show', 'artist', 'collection'):
|
||||||
<h1> </h1><h1>${data['title']}</h1>
|
<h1> </h1><h1>${data['title']}</h1>
|
||||||
% elif data['media_type'] == 'season':
|
% elif data['media_type'] == 'season':
|
||||||
<h1> </h1><h1><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a></h1>
|
<h1> </h1><h1><a href="${page('info', data['parent_rating_key'])}">${data['parent_title']}</a></h1>
|
||||||
<h3 class="hidden-xs">S${data['media_index']}</h3>
|
<h3 class="hidden-xs">S${data['media_index']}</h3>
|
||||||
% elif data['media_type'] == 'episode':
|
% elif data['media_type'] == 'episode':
|
||||||
<h1><a href="info?rating_key=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></h1>
|
<h1><a href="${page('info', data['grandparent_rating_key'])}">${data['grandparent_title']}</a></h1>
|
||||||
<h2>${data['title']}</h2>
|
<h2>${data['title']}</h2>
|
||||||
<h3 class="hidden-xs">S${data['parent_media_index']} · E${data['media_index']}</h3>
|
<h3 class="hidden-xs">S${data['parent_media_index']} · E${data['media_index']}</h3>
|
||||||
% elif data['media_type'] == 'album':
|
% elif data['media_type'] == 'album':
|
||||||
<h1><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a></h1>
|
<h1><a href="${page('info', data['parent_rating_key'])}">${data['parent_title']}</a></h1>
|
||||||
<h2>${data['title']}</h2>
|
<h2>${data['title']}</h2>
|
||||||
% elif data['media_type'] == 'track':
|
% elif data['media_type'] == 'track':
|
||||||
<h1><a href="info?rating_key=${data['grandparent_rating_key']}">${data['original_title'] or data['grandparent_title']}</a></h1>
|
<h1><a href="${page('info', data['grandparent_rating_key'])}">${data['original_title'] or data['grandparent_title']}</a></h1>
|
||||||
<h2><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a> - ${data['title']}</h2>
|
<h2><a href="${page('info', data['parent_rating_key'])}">${data['parent_title']}</a> - ${data['title']}</h2>
|
||||||
<h3 class="hidden-xs">T${data['media_index']}</h3>
|
<h3 class="hidden-xs">T${data['media_index']}</h3>
|
||||||
% endif
|
% endif
|
||||||
</div>
|
</div>
|
||||||
@@ -187,7 +236,7 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
<div class="summary-content-wrapper">
|
<div class="summary-content-wrapper">
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
% if data['media_type'] == 'movie':
|
% if data['media_type'] == 'movie' or data['live']:
|
||||||
<div class="summary-content-padding hidden-xs hidden-sm" style="height: 305px;">
|
<div class="summary-content-padding hidden-xs hidden-sm" style="height: 305px;">
|
||||||
% elif data['media_type'] in ('show', 'season', 'collection'):
|
% elif data['media_type'] in ('show', 'season', 'collection'):
|
||||||
<div class="summary-content-padding hidden-xs hidden-sm" style="height: 270px;">
|
<div class="summary-content-padding hidden-xs hidden-sm" style="height: 270px;">
|
||||||
@@ -206,7 +255,7 @@ DOCUMENTATION :: END
|
|||||||
<img class="summary-content-media-flag" title="${media_info['video_codec']}" src="${http_root}images/media_flags/video_codec/${media_info['video_codec'] | vf}.png" />
|
<img class="summary-content-media-flag" title="${media_info['video_codec']}" src="${http_root}images/media_flags/video_codec/${media_info['video_codec'] | vf}.png" />
|
||||||
% endif
|
% endif
|
||||||
% if data['media_type'] != 'track' and media_info['video_resolution']:
|
% if data['media_type'] != 'track' and media_info['video_resolution']:
|
||||||
<img class="summary-content-media-flag" title="${media_info['video_resolution']}" src="${http_root}images/media_flags/video_resolution/${media_info['video_resolution']}.png" />
|
<img class="summary-content-media-flag" title="${media_info['video_resolution']}" src="${http_root}images/media_flags/video_resolution/${media_info['video_full_resolution'] | vr}.png" />
|
||||||
% endif
|
% endif
|
||||||
% if media_info['audio_codec']:
|
% if media_info['audio_codec']:
|
||||||
<img class="summary-content-media-flag" title="${media_info['audio_codec']}" src="${http_root}images/media_flags/audio_codec/${media_info['audio_codec'] | af}.png" />
|
<img class="summary-content-media-flag" title="${media_info['audio_codec']}" src="${http_root}images/media_flags/audio_codec/${media_info['audio_codec'] | af}.png" />
|
||||||
@@ -251,6 +300,8 @@ DOCUMENTATION :: END
|
|||||||
Released <strong> ${data['year']}</strong>
|
Released <strong> ${data['year']}</strong>
|
||||||
% elif data['media_type'] == 'collection':
|
% elif data['media_type'] == 'collection':
|
||||||
Year <strong> ${data['min_year']} - ${data['max_year']}</strong>
|
Year <strong> ${data['min_year']} - ${data['max_year']}</strong>
|
||||||
|
% elif data['year']:
|
||||||
|
Year <strong> ${data['year']}</strong>
|
||||||
% endif
|
% endif
|
||||||
</div>
|
</div>
|
||||||
<div class="summary-content-details-tag">
|
<div class="summary-content-details-tag">
|
||||||
@@ -263,6 +314,11 @@ DOCUMENTATION :: END
|
|||||||
Rated <strong> ${data['content_rating']} </strong>
|
Rated <strong> ${data['content_rating']} </strong>
|
||||||
% endif
|
% endif
|
||||||
</div>
|
</div>
|
||||||
|
<div class="summary-content-details-tag" id="channel-icon">
|
||||||
|
% if media_info['channel_identifier']:
|
||||||
|
Channel <strong> <span class="thumb-tooltip" data-toggle="popover" data-img="${media_info['channel_thumb']}" data-height="40" data-width="40">${media_info['channel_call_sign']} ${media_info['channel_identifier']}</span> </strong>
|
||||||
|
% endif
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
% if data['tagline']:
|
% if data['tagline']:
|
||||||
<div class="summary-content-summary">
|
<div class="summary-content-summary">
|
||||||
@@ -415,7 +471,7 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
% endif
|
% endif
|
||||||
% if data.get('poster_url'):
|
% if data.get('poster_url'):
|
||||||
<div class="btn-group">
|
<div class="btn-group" id="hosted-poster">
|
||||||
% if data['media_type'] == 'artist' or data['media_type'] == 'album' or data['media_type'] == 'track':
|
% if data['media_type'] == 'artist' or data['media_type'] == 'album' or data['media_type'] == 'track':
|
||||||
<span class="hosted-poster-tooltip" data-toggle="popover" data-img="${data['poster_url']}" data-height="80" data-width="80" style="display: inline-flex;">
|
<span class="hosted-poster-tooltip" data-toggle="popover" data-img="${data['poster_url']}" data-height="80" data-width="80" style="display: inline-flex;">
|
||||||
% else:
|
% else:
|
||||||
@@ -429,6 +485,7 @@ DOCUMENTATION :: END
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
% endif
|
% endif
|
||||||
|
% if not data['live']:
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button class="btn btn-dark" data-toggle="modal" aria-pressed="false" autocomplete="off" id="send-recently-added-notification"
|
<button class="btn btn-dark" data-toggle="modal" aria-pressed="false" autocomplete="off" id="send-recently-added-notification"
|
||||||
data-id="${data['rating_key']}">
|
data-id="${data['rating_key']}">
|
||||||
@@ -436,6 +493,7 @@ DOCUMENTATION :: END
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
% endif
|
% endif
|
||||||
|
% endif
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button class="btn btn-dark refresh-history-button" id="refresh-history-list"><i class="fa fa-refresh"></i> Refresh history</button>
|
<button class="btn btn-dark refresh-history-button" id="refresh-history-list"><i class="fa fa-refresh"></i> Refresh history</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -474,6 +532,10 @@ DOCUMENTATION :: END
|
|||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="modalIncludes()">
|
<%def name="modalIncludes()">
|
||||||
|
% if metadata:
|
||||||
|
<%
|
||||||
|
data = defaultdict(None, **metadata)
|
||||||
|
%>
|
||||||
<div class="modal fade" id="info-modal" tabindex="-1" role="dialog" aria-labelledby="info-modal">
|
<div class="modal fade" id="info-modal" tabindex="-1" role="dialog" aria-labelledby="info-modal">
|
||||||
</div>
|
</div>
|
||||||
<div class="modal fade" id="ip-info-modal" tabindex="-1" role="dialog" aria-labelledby="ip-info-modal">
|
<div class="modal fade" id="ip-info-modal" tabindex="-1" role="dialog" aria-labelledby="ip-info-modal">
|
||||||
@@ -549,6 +611,7 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="javascriptIncludes()">
|
<%def name="javascriptIncludes()">
|
||||||
@@ -558,9 +621,28 @@ DOCUMENTATION :: END
|
|||||||
<script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
|
<script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
|
||||||
<script src="${http_root}js/moment-with-locale.js"></script>
|
<script src="${http_root}js/moment-with-locale.js"></script>
|
||||||
|
|
||||||
% if data:
|
% if metadata:
|
||||||
|
<%
|
||||||
|
data = defaultdict(None, **metadata)
|
||||||
|
%>
|
||||||
<script src="${http_root}js/tables/history_table.js${cache_param}"></script>
|
<script src="${http_root}js/tables/history_table.js${cache_param}"></script>
|
||||||
% if data['media_type'] in ('show', 'artist'):
|
% if data['live']:
|
||||||
|
<script>
|
||||||
|
function get_history() {
|
||||||
|
history_table_options.ajax = {
|
||||||
|
url: 'get_history',
|
||||||
|
type: 'POST',
|
||||||
|
data: function ( d ) {
|
||||||
|
return {
|
||||||
|
json_data: JSON.stringify( d ),
|
||||||
|
guid: "${data['guid']}",
|
||||||
|
user_id: "${_session['user_group']}" == "admin" ? null : "${_session['user_id']}"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
% elif data['media_type'] in ('show', 'artist'):
|
||||||
<script>
|
<script>
|
||||||
function get_history() {
|
function get_history() {
|
||||||
history_table_options.ajax = {
|
history_table_options.ajax = {
|
||||||
@@ -724,10 +806,22 @@ DOCUMENTATION :: END
|
|||||||
$("#airdate").html(moment($("#airdate").text()).format('MMM DD, YYYY'));
|
$("#airdate").html(moment($("#airdate").text()).format('MMM DD, YYYY'));
|
||||||
$("#runtime").html(millisecondsToMinutes($("#runtime").text(), true));
|
$("#runtime").html(millisecondsToMinutes($("#runtime").text(), true));
|
||||||
$('div.art-face').animate({ opacity: 0.2 }, { duration: 1000 });
|
$('div.art-face').animate({ opacity: 0.2 }, { duration: 1000 });
|
||||||
|
$('#channel-icon').popover({
|
||||||
|
selector: '[data-toggle=popover]',
|
||||||
|
html: true,
|
||||||
|
container: 'body',
|
||||||
|
trigger: 'hover',
|
||||||
|
placement: 'right',
|
||||||
|
template: '<div class="popover channel-thumbnail-popover" role="tooltip"><div class="arrow" style="top: 50%;"></div><div class="popover-content"></div></div>',
|
||||||
|
content: function () {
|
||||||
|
return '<div class="channel-thumbnail" style="background-image: url(' + $(this).data('img') + ');" />';
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
% if data.get('poster_url'):
|
% if data.get('poster_url'):
|
||||||
<script>
|
<script>
|
||||||
$('.hosted-poster-tooltip').popover({
|
$('#hosted-poster').popover({
|
||||||
|
selector: '[data-toggle=popover]',
|
||||||
html: true,
|
html: true,
|
||||||
container: 'body',
|
container: 'body',
|
||||||
trigger: 'hover',
|
trigger: 'hover',
|
||||||
|
@@ -27,6 +27,9 @@ DOCUMENTATION :: END
|
|||||||
</%doc>
|
</%doc>
|
||||||
|
|
||||||
% if data != None:
|
% if data != None:
|
||||||
|
<%
|
||||||
|
from plexpy.helpers import page
|
||||||
|
%>
|
||||||
% if data['children_count'] > 0:
|
% if data['children_count'] > 0:
|
||||||
<div class="item-children-wrapper">
|
<div class="item-children-wrapper">
|
||||||
<ul class="item-children-instance list-unstyled">
|
<ul class="item-children-instance list-unstyled">
|
||||||
@@ -38,9 +41,9 @@ DOCUMENTATION :: END
|
|||||||
<li>
|
<li>
|
||||||
% endif
|
% endif
|
||||||
% if data['children_type'] == 'movie':
|
% if data['children_type'] == 'movie':
|
||||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">
|
<a href="${page('info', child['rating_key'])}" title="${child['title']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')});"></div>
|
||||||
% if _session['user_group'] == 'admin':
|
% if _session['user_group'] == 'admin':
|
||||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
@@ -48,14 +51,14 @@ DOCUMENTATION :: END
|
|||||||
</a>
|
</a>
|
||||||
<div class="item-children-instance-text-wrapper poster-item">
|
<div class="item-children-instance-text-wrapper poster-item">
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
<a href="${page('info', child['rating_key'])}" title="${child['title']}">${child['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted">${child['year']}</h3>
|
<h3 class="text-muted">${child['year']}</h3>
|
||||||
</div>
|
</div>
|
||||||
% elif data['children_type'] == 'show':
|
% elif data['children_type'] == 'show':
|
||||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">
|
<a href="${page('info', child['rating_key'])}" title="${child['title']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')});"></div>
|
||||||
% if _session['user_group'] == 'admin':
|
% if _session['user_group'] == 'admin':
|
||||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
@@ -63,16 +66,16 @@ DOCUMENTATION :: END
|
|||||||
</a>
|
</a>
|
||||||
<div class="item-children-instance-text-wrapper poster-item">
|
<div class="item-children-instance-text-wrapper poster-item">
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
<a href="${page('info', child['rating_key'])}" title="${child['title']}">${child['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
% elif data['children_type'] == 'season':
|
% elif data['children_type'] == 'season':
|
||||||
<a href="info?rating_key=${child['rating_key']}" title="Season ${child['media_index']}">
|
<a href="${page('info', child['rating_key'])}" title="Season ${child['media_index']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
% if child['thumb']:
|
% if child['thumb']:
|
||||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);">
|
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')});">
|
||||||
% else:
|
% else:
|
||||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['parent_thumb']}&width=300&height=450&fallback=poster);">
|
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['parent_thumb'], child['parent_rating_key'], 300, 450, fallback='poster')});">
|
||||||
% endif
|
% endif
|
||||||
<div class="item-children-card-overlay">
|
<div class="item-children-card-overlay">
|
||||||
<div class="item-children-overlay-text">
|
<div class="item-children-overlay-text">
|
||||||
@@ -86,9 +89,9 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
% elif data['children_type'] == 'episode':
|
% elif data['children_type'] == 'episode':
|
||||||
<a href="info?rating_key=${child['rating_key']}" title="Episode ${child['media_index']}">
|
<a href="${page('info', child['rating_key'])}" title="Episode ${child['media_index']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face episode-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=500&height=250&fallback=art);">
|
<div class="item-children-poster-face episode-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 500, 280, fallback='art')});">
|
||||||
<div class="item-children-card-overlay">
|
<div class="item-children-card-overlay">
|
||||||
<div class="item-children-overlay-text">
|
<div class="item-children-overlay-text">
|
||||||
Episode ${child['media_index'] or child['originally_available_at']}
|
Episode ${child['media_index'] or child['originally_available_at']}
|
||||||
@@ -102,13 +105,13 @@ DOCUMENTATION :: END
|
|||||||
</a>
|
</a>
|
||||||
<div class="item-children-instance-text-wrapper episode-item">
|
<div class="item-children-instance-text-wrapper episode-item">
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
<a href="${page('info', child['rating_key'])}" title="${child['title']}">${child['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
% elif data['children_type'] == 'album':
|
% elif data['children_type'] == 'album':
|
||||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">
|
<a href="${page('info', child['rating_key'])}" title="${child['title']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face cover-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=300&fallback=cover);"></div>
|
<div class="item-children-poster-face cover-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 300, fallback='cover')});"></div>
|
||||||
% if _session['user_group'] == 'admin':
|
% if _session['user_group'] == 'admin':
|
||||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
@@ -116,14 +119,14 @@ DOCUMENTATION :: END
|
|||||||
</a>
|
</a>
|
||||||
<div class="item-children-instance-text-wrapper cover-item">
|
<div class="item-children-instance-text-wrapper cover-item">
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
<a href="${page('info', child['rating_key'])}" title="${child['title']}">${child['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
% elif data['children_type'] == 'track':
|
% elif data['children_type'] == 'track':
|
||||||
% if loop.index % 2 == 0:
|
% if loop.index % 2 == 0:
|
||||||
<div class="item-children-list-item-even">
|
<div class="item-children-list-item-even">
|
||||||
<span class="item-children-list-item-index"> ${child['media_index']}</span>
|
<span class="item-children-list-item-index"> ${child['media_index']}</span>
|
||||||
<span class="item-children-list-item-title"><a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
<span class="item-children-list-item-title"><a href="${page('info', child['rating_key'])}" title="${child['title']}">${child['title']}</a>
|
||||||
% if child['original_title']:
|
% if child['original_title']:
|
||||||
<span class="text-muted"> - ${child['original_title']}</span>
|
<span class="text-muted"> - ${child['original_title']}</span>
|
||||||
% endif
|
% endif
|
||||||
@@ -135,7 +138,7 @@ DOCUMENTATION :: END
|
|||||||
% else:
|
% else:
|
||||||
<div class="item-children-list-item-odd">
|
<div class="item-children-list-item-odd">
|
||||||
<span class="item-children-list-item-index"> ${child['media_index']}</span>
|
<span class="item-children-list-item-index"> ${child['media_index']}</span>
|
||||||
<span class="item-children-list-item-title"><a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
<span class="item-children-list-item-title"><a href="${page('info', child['rating_key'])}" title="${child['title']}">${child['title']}</a>
|
||||||
% if child['original_title']:
|
% if child['original_title']:
|
||||||
<span class="text-muted"> - ${child['original_title']}</span>
|
<span class="text-muted"> - ${child['original_title']}</span>
|
||||||
% endif
|
% endif
|
||||||
|
@@ -29,6 +29,7 @@ DOCUMENTATION :: END
|
|||||||
% if data != None:
|
% if data != None:
|
||||||
<%
|
<%
|
||||||
from plexpy.common import MEDIA_TYPE_HEADERS
|
from plexpy.common import MEDIA_TYPE_HEADERS
|
||||||
|
from plexpy.helpers import page
|
||||||
types = ('movie', 'show', 'artist', 'album')
|
types = ('movie', 'show', 'artist', 'album')
|
||||||
%>
|
%>
|
||||||
% for media_type in types:
|
% for media_type in types:
|
||||||
@@ -45,12 +46,12 @@ DOCUMENTATION :: END
|
|||||||
<ul class="item-children-instance list-unstyled">
|
<ul class="item-children-instance list-unstyled">
|
||||||
% for child in data['results_list'][media_type]:
|
% for child in data['results_list'][media_type]:
|
||||||
<li>
|
<li>
|
||||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">
|
<a href="${page('info', child['rating_key'])}" title="${child['title']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
% if media_type in ('artist', 'album'):
|
% if media_type in ('artist', 'album'):
|
||||||
<div class="item-children-poster-face cover-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=300&fallback=cover);"></div>
|
<div class="item-children-poster-face cover-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 300, fallback='cover')});"></div>
|
||||||
% else:
|
% else:
|
||||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')});"></div>
|
||||||
% endif
|
% endif
|
||||||
% if _session['user_group'] == 'admin':
|
% if _session['user_group'] == 'admin':
|
||||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
@@ -60,22 +61,22 @@ DOCUMENTATION :: END
|
|||||||
% if media_type == 'artist':
|
% if media_type == 'artist':
|
||||||
<div class="item-children-instance-text-wrapper cover-item">
|
<div class="item-children-instance-text-wrapper cover-item">
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
<a href="${page('info', child['rating_key'])}" title="${child['title']}">${child['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
% elif media_type == 'album':
|
% elif media_type == 'album':
|
||||||
<div class="item-children-instance-text-wrapper cover-item">
|
<div class="item-children-instance-text-wrapper cover-item">
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${child['parent_rating_key']}" title="${child['parent_title']}">${child['parent_title']}</a>
|
<a href="${page('info', child['parent_rating_key'])}" title="${child['parent_title']}">${child['parent_title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
<a href="${page('info', child['rating_key'])}" title="${child['title']}">${child['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="item-children-instance-text-wrapper poster-item">
|
<div class="item-children-instance-text-wrapper poster-item">
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
<a href="${page('info', child['rating_key'])}" title="${child['title']}">${child['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted">${child['year']}</h3>
|
<h3 class="text-muted">${child['year']}</h3>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -53,6 +53,9 @@ DOCUMENTATION :: END
|
|||||||
</%doc>
|
</%doc>
|
||||||
|
|
||||||
% if data != None:
|
% if data != None:
|
||||||
|
<%
|
||||||
|
from plexpy.helpers import page
|
||||||
|
%>
|
||||||
% if data['results_count'] > 0:
|
% if data['results_count'] > 0:
|
||||||
% if 'collection' in data['results_list'] and data['results_list']['collection']:
|
% if 'collection' in data['results_list'] and data['results_list']['collection']:
|
||||||
<div class="item-children-wrapper">
|
<div class="item-children-wrapper">
|
||||||
@@ -62,9 +65,9 @@ DOCUMENTATION :: END
|
|||||||
<ul class="item-children-instance list-unstyled">
|
<ul class="item-children-instance list-unstyled">
|
||||||
% for child in data['results_list']['collection']:
|
% for child in data['results_list']['collection']:
|
||||||
<li>
|
<li>
|
||||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
<a href="${page('info', child['rating_key'])}" id="${child['rating_key']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')});"></div>
|
||||||
% if _session['user_group'] == 'admin':
|
% if _session['user_group'] == 'admin':
|
||||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
@@ -87,9 +90,9 @@ DOCUMENTATION :: END
|
|||||||
<ul class="item-children-instance list-unstyled">
|
<ul class="item-children-instance list-unstyled">
|
||||||
% for child in data['results_list']['movie']:
|
% for child in data['results_list']['movie']:
|
||||||
<li>
|
<li>
|
||||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
<a href="${page('info', child['rating_key'])}" id="${child['rating_key']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')});"></div>
|
||||||
% if _session['user_group'] == 'admin':
|
% if _session['user_group'] == 'admin':
|
||||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
@@ -112,9 +115,9 @@ DOCUMENTATION :: END
|
|||||||
<ul class="item-children-instance list-unstyled">
|
<ul class="item-children-instance list-unstyled">
|
||||||
% for child in data['results_list']['show']:
|
% for child in data['results_list']['show']:
|
||||||
<li>
|
<li>
|
||||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
<a href="${page('info', child['rating_key'])}" id="${child['rating_key']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')});"></div>
|
||||||
% if _session['user_group'] == 'admin':
|
% if _session['user_group'] == 'admin':
|
||||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
@@ -137,9 +140,9 @@ DOCUMENTATION :: END
|
|||||||
<ul class="item-children-instance list-unstyled">
|
<ul class="item-children-instance list-unstyled">
|
||||||
% for child in data['results_list']['season']:
|
% for child in data['results_list']['season']:
|
||||||
<li>
|
<li>
|
||||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
<a href="${page('info', child['rating_key'])}" id="${child['rating_key']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')});"></div>
|
||||||
% if _session['user_group'] == 'admin':
|
% if _session['user_group'] == 'admin':
|
||||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
@@ -162,9 +165,9 @@ DOCUMENTATION :: END
|
|||||||
<ul class="item-children-instance list-unstyled">
|
<ul class="item-children-instance list-unstyled">
|
||||||
% for child in data['results_list']['episode']:
|
% for child in data['results_list']['episode']:
|
||||||
<li>
|
<li>
|
||||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
<a href="${page('info', child['rating_key'])}" id="${child['rating_key']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face episode-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=500&height=250&fallback=art);"></div>
|
<div class="item-children-poster-face episode-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 500, 280, fallback='art')});"></div>
|
||||||
% if _session['user_group'] == 'admin':
|
% if _session['user_group'] == 'admin':
|
||||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
@@ -188,9 +191,9 @@ DOCUMENTATION :: END
|
|||||||
<ul class="item-children-instance list-unstyled">
|
<ul class="item-children-instance list-unstyled">
|
||||||
% for child in data['results_list']['artist']:
|
% for child in data['results_list']['artist']:
|
||||||
<li>
|
<li>
|
||||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
<a href="${page('info', child['rating_key'])}" id="${child['rating_key']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face cover-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=300&fallback=cover);"></div>
|
<div class="item-children-poster-face cover-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 300, fallback='cover')});"></div>
|
||||||
% if _session['user_group'] == 'admin':
|
% if _session['user_group'] == 'admin':
|
||||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
@@ -212,9 +215,9 @@ DOCUMENTATION :: END
|
|||||||
<ul class="item-children-instance list-unstyled">
|
<ul class="item-children-instance list-unstyled">
|
||||||
% for child in data['results_list']['album']:
|
% for child in data['results_list']['album']:
|
||||||
<li>
|
<li>
|
||||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
<a href="${page('info', child['rating_key'])}" id="${child['rating_key']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face cover-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=300&fallback=cover);"></div>
|
<div class="item-children-poster-face cover-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 300, fallback='cover')});"></div>
|
||||||
% if _session['user_group'] == 'admin':
|
% if _session['user_group'] == 'admin':
|
||||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
@@ -237,9 +240,9 @@ DOCUMENTATION :: END
|
|||||||
<ul class="item-children-instance list-unstyled">
|
<ul class="item-children-instance list-unstyled">
|
||||||
% for child in data['results_list']['track']:
|
% for child in data['results_list']['track']:
|
||||||
<li>
|
<li>
|
||||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
<a href="${page('info', child['rating_key'])}" id="${child['rating_key']}">
|
||||||
<div class="item-children-poster">
|
<div class="item-children-poster">
|
||||||
<div class="item-children-poster-face cover-item" style="background-image: url(pms_image_proxy?img=${child['parent_thumb']}&width=300&height=300&fallback=cover);">
|
<div class="item-children-poster-face cover-item" style="background-image: url(${page('pms_image_proxy', child['parent_thumb'], child['parent_rating_key'], 300, 300, fallback='cover')});">
|
||||||
<div class="item-children-card-overlay">
|
<div class="item-children-card-overlay">
|
||||||
<div class="item-children-overlay-text">
|
<div class="item-children-overlay-text">
|
||||||
Track ${child['media_index']}
|
Track ${child['media_index']}
|
||||||
|
@@ -40,7 +40,6 @@ var hc_plays_by_day_options = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: 'datetime',
|
type: 'datetime',
|
||||||
labels: {
|
labels: {
|
||||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_dayofweek_options = {
|
|||||||
credits: {
|
credits: {
|
||||||
enabled: false
|
enabled: false
|
||||||
},
|
},
|
||||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
|
||||||
xAxis: {
|
xAxis: {
|
||||||
categories: [{}],
|
categories: [{}],
|
||||||
labels: {
|
labels: {
|
||||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_hourofday_options = {
|
|||||||
credits: {
|
credits: {
|
||||||
enabled: false
|
enabled: false
|
||||||
},
|
},
|
||||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
|
||||||
xAxis: {
|
xAxis: {
|
||||||
categories: [{}],
|
categories: [{}],
|
||||||
labels: {
|
labels: {
|
||||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_month_options = {
|
|||||||
credits: {
|
credits: {
|
||||||
enabled: false
|
enabled: false
|
||||||
},
|
},
|
||||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
|
||||||
xAxis: {
|
xAxis: {
|
||||||
labels: {
|
labels: {
|
||||||
style: {
|
style: {
|
||||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_platform_options = {
|
|||||||
credits: {
|
credits: {
|
||||||
enabled: false
|
enabled: false
|
||||||
},
|
},
|
||||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
|
||||||
xAxis: {
|
xAxis: {
|
||||||
categories: [{}],
|
categories: [{}],
|
||||||
labels: {
|
labels: {
|
||||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_platform_by_stream_type_options = {
|
|||||||
credits: {
|
credits: {
|
||||||
enabled: false
|
enabled: false
|
||||||
},
|
},
|
||||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
|
||||||
xAxis: {
|
xAxis: {
|
||||||
categories: [{}],
|
categories: [{}],
|
||||||
labels: {
|
labels: {
|
||||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_source_resolution_options = {
|
|||||||
credits: {
|
credits: {
|
||||||
enabled: false
|
enabled: false
|
||||||
},
|
},
|
||||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
|
||||||
xAxis: {
|
xAxis: {
|
||||||
categories: [{}],
|
categories: [{}],
|
||||||
labels: {
|
labels: {
|
||||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_stream_resolution_options = {
|
|||||||
credits: {
|
credits: {
|
||||||
enabled: false
|
enabled: false
|
||||||
},
|
},
|
||||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
|
||||||
xAxis: {
|
xAxis: {
|
||||||
categories: [{}],
|
categories: [{}],
|
||||||
labels: {
|
labels: {
|
||||||
|
@@ -40,7 +40,6 @@ var hc_plays_by_stream_type_options = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: 'datetime',
|
type: 'datetime',
|
||||||
labels: {
|
labels: {
|
||||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_user_options = {
|
|||||||
credits: {
|
credits: {
|
||||||
enabled: false
|
enabled: false
|
||||||
},
|
},
|
||||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
|
||||||
xAxis: {
|
xAxis: {
|
||||||
categories: [{}],
|
categories: [{}],
|
||||||
labels: {
|
labels: {
|
||||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_user_by_stream_type_options = {
|
|||||||
credits: {
|
credits: {
|
||||||
enabled: false
|
enabled: false
|
||||||
},
|
},
|
||||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
|
||||||
xAxis: {
|
xAxis: {
|
||||||
categories: [{}],
|
categories: [{}],
|
||||||
labels: {
|
labels: {
|
||||||
|
@@ -258,7 +258,6 @@ $.cachedScript = function (url) {
|
|||||||
function isPrivateIP(ip_address) {
|
function isPrivateIP(ip_address) {
|
||||||
var defer = $.Deferred();
|
var defer = $.Deferred();
|
||||||
|
|
||||||
$.cachedScript('js/ipaddr.min.js').done(function () {
|
|
||||||
if (ipaddr.isValid(ip_address)) {
|
if (ipaddr.isValid(ip_address)) {
|
||||||
var addr = ipaddr.process(ip_address);
|
var addr = ipaddr.process(ip_address);
|
||||||
|
|
||||||
@@ -284,7 +283,6 @@ function isPrivateIP(ip_address) {
|
|||||||
} else {
|
} else {
|
||||||
defer.resolve('n/a');
|
defer.resolve('n/a');
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
return defer.promise();
|
return defer.promise();
|
||||||
}
|
}
|
||||||
@@ -717,3 +715,69 @@ function encodeData(data) {
|
|||||||
return [key, data[key]].map(encodeURIComponent).join("=");
|
return [key, data[key]].map(encodeURIComponent).join("=");
|
||||||
}).join("&");
|
}).join("&");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function page(endpoint, ...args) {
|
||||||
|
let endpoints = {
|
||||||
|
'pms_image_proxy': pms_image_proxy,
|
||||||
|
'info': info_page,
|
||||||
|
'library': library_page,
|
||||||
|
'user': user_page
|
||||||
|
};
|
||||||
|
|
||||||
|
var params = {};
|
||||||
|
|
||||||
|
if (endpoint in endpoints) {
|
||||||
|
params = endpoints[endpoint](...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return endpoint + '?' + $.param(params).replace(/'/g, '%27');
|
||||||
|
}
|
||||||
|
|
||||||
|
function pms_image_proxy(img, rating_key, width, height, opacity, background, blur, fallback, refresh, clip, img_format) {
|
||||||
|
var params = {};
|
||||||
|
|
||||||
|
if (img != null) { params.img = img; }
|
||||||
|
if (rating_key != null) { params.rating_key = rating_key; }
|
||||||
|
if (width != null) { params.width = width; }
|
||||||
|
if (height != null) { params.height = height; }
|
||||||
|
if (opacity != null) { params.opacity = opacity; }
|
||||||
|
if (background != null) { params.background = background; }
|
||||||
|
if (blur != null) { params.blur = blur; }
|
||||||
|
if (fallback != null) { params.fallback = fallback; }
|
||||||
|
if (refresh != null) { params.refresh = true; }
|
||||||
|
if (clip != null) { params.clip = true; }
|
||||||
|
if (img_format != null) { params.img_format = img_format; }
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
function info_page(rating_key, guid, history, live) {
|
||||||
|
var params = {};
|
||||||
|
|
||||||
|
if (live && history) {
|
||||||
|
params.guid = guid;
|
||||||
|
} else {
|
||||||
|
params.rating_key = rating_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (history) { params.source = 'history'; }
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
function library_page(section_id) {
|
||||||
|
var params = {};
|
||||||
|
|
||||||
|
if (section_id != null) { params.section_id = section_id; }
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
function user_page(user_id, user) {
|
||||||
|
var params = {};
|
||||||
|
|
||||||
|
if (user_id != null) { params.user_id = user_id; }
|
||||||
|
if (user != null) { params.user = user; }
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
@@ -81,9 +81,9 @@ history_table_options = {
|
|||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== '') {
|
if (cellData !== '') {
|
||||||
if (rowData['user_id']) {
|
if (rowData['user_id']) {
|
||||||
$(td).html('<a href="user?user_id=' + rowData['user_id'] + '">' + cellData + '</a>');
|
$(td).html('<a href="' + page('user', rowData['user_id']) + '">' + cellData + '</a>');
|
||||||
} else {
|
} else {
|
||||||
$(td).html('<a href="user?user=' + rowData['user'] + '">' + cellData + '</a>');
|
$(td).html('<a href="' + page('user', null, rowData['user']) + '">' + cellData + '</a>');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$(td).html(cellData);
|
$(td).html(cellData);
|
||||||
@@ -156,29 +156,37 @@ history_table_options = {
|
|||||||
"data": "full_title",
|
"data": "full_title",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== '') {
|
if (cellData !== '') {
|
||||||
|
var icon = '';
|
||||||
|
var icon_title = '';
|
||||||
var parent_info = '';
|
var parent_info = '';
|
||||||
var media_type = '';
|
var media_type = '';
|
||||||
var thumb_popover = '';
|
var thumb_popover = '';
|
||||||
var source = (rowData['state'] === null) ? 'source=history&' : '';
|
var fallback = (rowData['live']) ? 'poster-live' : 'poster';
|
||||||
|
var history = (rowData['state'] === null);
|
||||||
if (rowData['media_type'] === 'movie') {
|
if (rowData['media_type'] === 'movie') {
|
||||||
|
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-film';
|
||||||
|
icon_title = (rowData['live']) ? 'Live TV' : 'Movie';
|
||||||
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Movie"><i class="fa fa-film fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?' + source + 'rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], history, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type'] === 'episode') {
|
} else if (rowData['media_type'] === 'episode') {
|
||||||
|
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-television';
|
||||||
|
icon_title = (rowData['live']) ? 'Live TV' : 'Episode';
|
||||||
if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (S' + rowData['parent_media_index'] + ' · E' + rowData['media_index'] + ')'; }
|
if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (S' + rowData['parent_media_index'] + ' · E' + rowData['media_index'] + ')'; }
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
|
else if (rowData['live'] && rowData['originally_available_at']) { parent_info = ' (' + rowData['originally_available_at'] + ')'; }
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?' + source + 'rating_key=' + rowData['rating_key'] + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||||
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], history, rowData['live']) + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type'] === 'track') {
|
} else if (rowData['media_type'] === 'track') {
|
||||||
if (rowData['parent_title']) { parent_info = ' (' + rowData['parent_title'] + ')'; }
|
if (rowData['parent_title']) { parent_info = ' (' + rowData['parent_title'] + ')'; }
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=cover" data-height="80" data-width="80">' + cellData + parent_info + '</span>'
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 300, null, null, null, 'cover') + '" data-height="80" data-width="80">' + cellData + parent_info + '</span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?' + source + 'rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], history, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type'] === 'clip') {
|
} else if (rowData['media_type'] === 'clip') {
|
||||||
$(td).html(cellData);
|
$(td).html(cellData);
|
||||||
} else {
|
} else {
|
||||||
$(td).html('<a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a>');
|
$(td).html('<a href="' + page('info', rowData['rating_key']) + '">' + cellData + '</a>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@@ -63,9 +63,9 @@ history_table_modal_options = {
|
|||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== '') {
|
if (cellData !== '') {
|
||||||
if (rowData['user_id']) {
|
if (rowData['user_id']) {
|
||||||
$(td).html('<a href="user?user_id=' + rowData['user_id'] + '">' + cellData + '</a>');
|
$(td).html('<a href="' + page('user', rowData['user_id']) + '">' + cellData + '</a>');
|
||||||
} else {
|
} else {
|
||||||
$(td).html('<a href="user?user=' + rowData['user'] + '">' + cellData + '</a>');
|
$(td).html('<a href="' + page('user', null, rowData['user']) + '">' + cellData + '</a>');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$(td).html(cellData);
|
$(td).html(cellData);
|
||||||
@@ -98,26 +98,34 @@ history_table_modal_options = {
|
|||||||
"data":"full_title",
|
"data":"full_title",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== '') {
|
if (cellData !== '') {
|
||||||
|
var icon = '';
|
||||||
|
var icon_title = '';
|
||||||
var parent_info = '';
|
var parent_info = '';
|
||||||
var media_type = '';
|
var media_type = '';
|
||||||
var thumb_popover = '';
|
var thumb_popover = '';
|
||||||
|
var fallback = (rowData['live']) ? 'poster-live' : 'poster';
|
||||||
if (rowData['media_type'] === 'movie') {
|
if (rowData['media_type'] === 'movie') {
|
||||||
|
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-film';
|
||||||
|
icon_title = (rowData['live']) ? 'Live TV' : 'Movie';
|
||||||
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Movie"><i class="fa fa-film fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type'] === 'episode') {
|
} else if (rowData['media_type'] === 'episode') {
|
||||||
|
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-television';
|
||||||
|
icon_title = (rowData['live']) ? 'Live TV' : 'Episode';
|
||||||
if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (S' + rowData['parent_media_index'] + ' · E' + rowData['media_index'] + ')'; }
|
if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (S' + rowData['parent_media_index'] + ' · E' + rowData['media_index'] + ')'; }
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
|
else if (rowData['live'] && rowData['originally_available_at']) { parent_info = ' (' + rowData['originally_available_at'] + ')'; }
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||||
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type'] === 'track') {
|
} else if (rowData['media_type'] === 'track') {
|
||||||
if (rowData['parent_title']) { parent_info = ' (' + rowData['parent_title'] + ')'; }
|
if (rowData['parent_title']) { parent_info = ' (' + rowData['parent_title'] + ')'; }
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=cover" data-height="80" data-width="80">' + cellData + parent_info + '</span>'
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 300, null, null, null, 'cover') + '" data-height="80" data-width="80">' + cellData + parent_info + '</span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else {
|
} else {
|
||||||
$(td).html('<a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a>');
|
$(td).html('<a href="' + page('info', rowData['rating_key']) + '">' + cellData + '</a>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@@ -137,45 +137,34 @@ libraries_list_table_options = {
|
|||||||
"data":"last_played",
|
"data":"last_played",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== null && cellData !== '') {
|
if (cellData !== null && cellData !== '') {
|
||||||
|
var icon = '';
|
||||||
|
var icon_title = '';
|
||||||
var parent_info = '';
|
var parent_info = '';
|
||||||
var media_type = '';
|
var media_type = '';
|
||||||
var thumb_popover = '';
|
var thumb_popover = '';
|
||||||
|
var fallback = (rowData['live']) ? 'poster-live' : 'poster';
|
||||||
if (rowData['media_type'] === 'movie') {
|
if (rowData['media_type'] === 'movie') {
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Movie"><i class="fa fa-film fa-fw"></i></span>';
|
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-film';
|
||||||
if (rowData['rating_key']) {
|
icon_title = (rowData['live']) ? 'Live TV' : 'Movie';
|
||||||
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||||
} else {
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="images/poster.png" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
|
||||||
$(td).html('<div class="history-title"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></div>');
|
|
||||||
}
|
|
||||||
} else if (rowData['media_type'] === 'episode') {
|
} else if (rowData['media_type'] === 'episode') {
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
|
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-television';
|
||||||
if (rowData['rating_key']) {
|
icon_title = (rowData['live']) ? 'Live TV' : 'Episode';
|
||||||
if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (S' + rowData['parent_media_index'] + ' · E' + rowData['media_index'] + ')'; }
|
if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (S' + rowData['parent_media_index'] + ' · E' + rowData['media_index'] + ')'; }
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
else if (rowData['live'] && rowData['originally_available_at']) { parent_info = ' (' + rowData['originally_available_at'] + ')'; }
|
||||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||||
} else {
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="images/poster.png" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
$(td).html('<div class="history-title"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></div>');
|
|
||||||
}
|
|
||||||
} else if (rowData['media_type'] === 'track') {
|
} else if (rowData['media_type'] === 'track') {
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
|
||||||
if (rowData['rating_key']) {
|
|
||||||
if (rowData['parent_title']) { parent_info = ' (' + rowData['parent_title'] + ')'; }
|
if (rowData['parent_title']) { parent_info = ' (' + rowData['parent_title'] + ')'; }
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=cover" data-height="80" data-width="80">' + cellData + parent_info + '</span>'
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 300, null, null, null, 'cover') + '" data-height="80" data-width="80">' + cellData + parent_info + '</span>';
|
||||||
} else {
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="images/cover.png" data-height="80" data-width="80">' + cellData + parent_info + '</span>'
|
|
||||||
$(td).html('<div class="history-title"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></div>');
|
|
||||||
}
|
|
||||||
} else if (rowData['media_type']) {
|
} else if (rowData['media_type']) {
|
||||||
if (rowData['rating_key']) {
|
$(td).html('<a href="' + page('info', rowData['rating_key']) + '">' + cellData + '</a>');
|
||||||
$(td).html('<a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a>');
|
|
||||||
} else {
|
|
||||||
$(td).html(cellData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$(td).html('n/a');
|
$(td).html('n/a');
|
||||||
|
@@ -78,43 +78,43 @@ media_info_table_options = {
|
|||||||
if (rowData['media_type'] === 'movie') {
|
if (rowData['media_type'] === 'movie') {
|
||||||
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Movie"><i class="fa fa-film fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Movie"><i class="fa fa-film fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + rowData['title'] + parent_info + '</span>';
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, 'poster') + '" data-height="120" data-width="80">' + rowData['title'] + parent_info + '</span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type'] === 'show') {
|
} else if (rowData['media_type'] === 'show') {
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="TV Show"><i class="fa fa-television fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="TV Show"><i class="fa fa-television fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, 'poster') + '" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type'] === 'season') {
|
} else if (rowData['media_type'] === 'season') {
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Season"><i class="fa fa-television fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Season"><i class="fa fa-television fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, 'poster') + '" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?rating_key=' + rowData['rating_key'] + '"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type'] === 'episode') {
|
} else if (rowData['media_type'] === 'episode') {
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=art" data-height="80" data-width="140">E' + rowData['media_index'] + ' - ' + rowData['title'] + '</span>';
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 500, 280, null, null, null, 'art') + '" data-height="80" data-width="140">E' + rowData['media_index'] + ' - ' + rowData['title'] + '</span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?rating_key=' + rowData['rating_key'] + '"><div style="float: left; padding-left: 30px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left; padding-left: 30px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type'] === 'artist') {
|
} else if (rowData['media_type'] === 'artist') {
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Artist"><i class="fa fa-music fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Artist"><i class="fa fa-music fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=cover" data-height="80" data-width="80">' + rowData['title'] + '</span>';
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 300, null, null, null, 'cover') + '" data-height="80" data-width="80">' + rowData['title'] + '</span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type'] === 'album') {
|
} else if (rowData['media_type'] === 'album') {
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Album"><i class="fa fa-music fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Album"><i class="fa fa-music fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=cover" data-height="80" data-width="80">' + rowData['title'] + '</span>';
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 300, null, null, null, 'cover') + '" data-height="80" data-width="80">' + rowData['title'] + '</span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?rating_key=' + rowData['rating_key'] + '"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type'] === 'track') {
|
} else if (rowData['media_type'] === 'track') {
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=cover" data-height="80" data-width="80">T' + rowData['media_index'] + ' - ' + rowData['title'] + '</span>';
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 300, null, null, null, 'cover') + '" data-height="80" data-width="80">T' + rowData['media_index'] + ' - ' + rowData['title'] + '</span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?rating_key=' + rowData['rating_key'] + '"><div style="float: left; padding-left: 30px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left; padding-left: 30px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type'] === 'photo_album') {
|
} else if (rowData['media_type'] === 'photo_album') {
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Photo Album"><i class="fa fa-camera fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Photo Album"><i class="fa fa-camera fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, 'poster') + '" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
||||||
$(td).html('<div class="history-title"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></div>');
|
$(td).html('<div class="history-title"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></div>');
|
||||||
} else if (rowData['media_type'] === 'photo') {
|
} else if (rowData['media_type'] === 'photo') {
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Photo"><i class="fa fa-picture-o fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Photo"><i class="fa fa-picture-o fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, 'poster') + '" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
||||||
$(td).html('<div class="history-title"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></div>');
|
$(td).html('<div class="history-title"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></div>');
|
||||||
} else if (rowData['media_type'] === 'clip') {
|
} else if (rowData['media_type'] === 'clip') {
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Video"><i class="fa fa-video-camera fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Video"><i class="fa fa-video-camera fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=art" data-height="80" data-width="140">' + rowData['title'] + '</span>';
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 500, 280, null, null, null, 'art') + '" data-height="80" data-width="140">' + rowData['title'] + '</span>';
|
||||||
$(td).html('<div class="history-title"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></div>');
|
$(td).html('<div class="history-title"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></div>');
|
||||||
} else {
|
} else {
|
||||||
$(td).html(cellData);
|
$(td).html(cellData);
|
||||||
|
@@ -51,9 +51,9 @@ sync_table_options = {
|
|||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== '') {
|
if (cellData !== '') {
|
||||||
if (rowData['user_id']) {
|
if (rowData['user_id']) {
|
||||||
$(td).html('<a href="user?user_id=' + rowData['user_id'] + '">' + cellData + '</a>');
|
$(td).html('<a href="' + page('user', rowData['user_id']) + '>' + cellData + '</a>');
|
||||||
} else {
|
} else {
|
||||||
$(td).html('<a href="user?user=' + rowData['user'] + '">' + cellData + '</a>');
|
$(td).html('<a href="' + page('user', null, rowData['user']) + '">' + cellData + '</a>');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$(td).html(cellData);
|
$(td).html(cellData);
|
||||||
@@ -67,7 +67,7 @@ sync_table_options = {
|
|||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== '') {
|
if (cellData !== '') {
|
||||||
if (rowData['rating_key']) {
|
if (rowData['rating_key']) {
|
||||||
$(td).html('<a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a>');
|
$(td).html('<a href="' + page('info', rowData['rating_key']) + '">' + cellData + '</a>');
|
||||||
} else {
|
} else {
|
||||||
$(td).html(cellData);
|
$(td).html(cellData);
|
||||||
}
|
}
|
||||||
|
@@ -82,30 +82,38 @@ user_ip_table_options = {
|
|||||||
"data": "last_played",
|
"data": "last_played",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== '') {
|
if (cellData !== '') {
|
||||||
|
var icon = '';
|
||||||
|
var icon_title = '';
|
||||||
var parent_info = '';
|
var parent_info = '';
|
||||||
var media_type = '';
|
var media_type = '';
|
||||||
var thumb_popover = '';
|
var thumb_popover = '';
|
||||||
|
var fallback = (rowData['live']) ? 'poster-live' : 'poster';
|
||||||
if (rowData['media_type'] === 'movie') {
|
if (rowData['media_type'] === 'movie') {
|
||||||
|
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-film';
|
||||||
|
icon_title = (rowData['live']) ? 'Live TV' : 'Movie';
|
||||||
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Movie"><i class="fa fa-film fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type'] === 'episode') {
|
} else if (rowData['media_type'] === 'episode') {
|
||||||
|
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-television';
|
||||||
|
icon_title = (rowData['live']) ? 'Live TV' : 'Episode';
|
||||||
if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (S' + rowData['parent_media_index'] + ' · E' + rowData['media_index'] + ')'; }
|
if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (S' + rowData['parent_media_index'] + ' · E' + rowData['media_index'] + ')'; }
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
|
else if (rowData['live'] && rowData['originally_available_at']) { parent_info = ' (' + rowData['originally_available_at'] + ')'; }
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||||
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type'] === 'track') {
|
} else if (rowData['media_type'] === 'track') {
|
||||||
if (rowData['parent_title']) { parent_info = ' (' + rowData['parent_title'] + ')'; }
|
if (rowData['parent_title']) { parent_info = ' (' + rowData['parent_title'] + ')'; }
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=cover" data-height="80" data-width="80">' + cellData + parent_info + '</span>'
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 300, null, null, null, 'cover') + '" data-height="80" data-width="80">' + cellData + parent_info + '</span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type']) {
|
} else if (rowData['media_type']) {
|
||||||
$(td).html('<a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a>');
|
$(td).html('<a href="' + page('info', rowData['rating_key']) + '">' + cellData + '</a>');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$(td).html('n/a');
|
$(td).html('n/a');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"width": "30%",
|
"width": "30%",
|
||||||
"className": "datatable-wrap"
|
"className": "datatable-wrap"
|
||||||
|
@@ -60,9 +60,9 @@ users_list_table_options = {
|
|||||||
"data": "user_thumb",
|
"data": "user_thumb",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData === '') {
|
if (cellData === '') {
|
||||||
$(td).html('<a href="user?user_id=' + rowData['user_id'] + '"><div class="users-poster-face" style="background-image: url(../../images/gravatar-default-80x80.png);"></div></a>');
|
$(td).html('<a href="' + page('user', rowData['user_id']) + '"><div class="users-poster-face" style="background-image: url(../../images/gravatar-default-80x80.png);"></div></a>');
|
||||||
} else {
|
} else {
|
||||||
$(td).html('<a href="user?user_id=' + rowData['user_id'] + '"><div class="users-poster-face" style="background-image: url(' + rowData['user_thumb'] + ');"></div></a>');
|
$(td).html('<a href="' + page('user', rowData['user_id']) + '"><div class="users-poster-face" style="background-image: url(' + rowData['user_thumb'] + ');"></div></a>');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"orderable": false,
|
"orderable": false,
|
||||||
@@ -76,7 +76,7 @@ users_list_table_options = {
|
|||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== null && cellData !== '') {
|
if (cellData !== null && cellData !== '') {
|
||||||
$(td).html('<div class="edit-user-name" data-id="' + rowData['user_id'] + '">' +
|
$(td).html('<div class="edit-user-name" data-id="' + rowData['user_id'] + '">' +
|
||||||
'<a href="user?user_id=' + rowData['user_id'] + '">' + cellData + '</a>' +
|
'<a href="' + page('user', rowData['user_id']) + '">' + cellData + '</a>' +
|
||||||
'<input type="text" class="hidden" value="' + cellData + '">' +
|
'<input type="text" class="hidden" value="' + cellData + '">' +
|
||||||
'</div>');
|
'</div>');
|
||||||
} else {
|
} else {
|
||||||
@@ -157,26 +157,34 @@ users_list_table_options = {
|
|||||||
"data":"last_played",
|
"data":"last_played",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== null && cellData !== '') {
|
if (cellData !== null && cellData !== '') {
|
||||||
|
var icon = '';
|
||||||
|
var icon_title = '';
|
||||||
var parent_info = '';
|
var parent_info = '';
|
||||||
var media_type = '';
|
var media_type = '';
|
||||||
var thumb_popover = '';
|
var thumb_popover = '';
|
||||||
|
var fallback = (rowData['live']) ? 'poster-live' : 'poster';
|
||||||
if (rowData['media_type'] === 'movie') {
|
if (rowData['media_type'] === 'movie') {
|
||||||
|
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-film';
|
||||||
|
icon_title = (rowData['live']) ? 'Live TV' : 'Movie';
|
||||||
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Movie"><i class="fa fa-film fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type'] === 'episode') {
|
} else if (rowData['media_type'] === 'episode') {
|
||||||
|
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-television';
|
||||||
|
icon_title = (rowData['live']) ? 'Live TV' : 'Episode';
|
||||||
if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (S' + rowData['parent_media_index'] + ' · E' + rowData['media_index'] + ')'; }
|
if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (S' + rowData['parent_media_index'] + ' · E' + rowData['media_index'] + ')'; }
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
|
else if (rowData['live'] && rowData['originally_available_at']) { parent_info = ' (' + rowData['originally_available_at'] + ')'; }
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||||
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type'] === 'track') {
|
} else if (rowData['media_type'] === 'track') {
|
||||||
if (rowData['parent_title']) { parent_info = ' (' + rowData['parent_title'] + ')'; }
|
if (rowData['parent_title']) { parent_info = ' (' + rowData['parent_title'] + ')'; }
|
||||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
||||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=cover" data-height="80" data-width="80">' + cellData + parent_info + '</span>'
|
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 300, null, null, null, 'cover') + '" data-height="80" data-width="80">' + cellData + parent_info + '</span>';
|
||||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||||
} else if (rowData['media_type']) {
|
} else if (rowData['media_type']) {
|
||||||
$(td).html('<a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a>');
|
$(td).html('<a href="' + page('info', rowData['rating_key']) + '">' + cellData + '</a>');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$(td).html('n/a');
|
$(td).html('n/a');
|
||||||
|
@@ -35,10 +35,14 @@ DOCUMENTATION :: END
|
|||||||
|
|
||||||
<%def name="body()">
|
<%def name="body()">
|
||||||
% if data:
|
% if data:
|
||||||
|
<%
|
||||||
|
from plexpy.common import LIVE_TV_SECTION_ID
|
||||||
|
from plexpy.helpers import page
|
||||||
|
%>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<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(${page('pms_image_proxy', data['library_art'], None, 1920, 1080)})"></div>
|
||||||
% if _session['user_group'] == 'admin':
|
% if _session['user_group'] == 'admin':
|
||||||
<span class="overlay-refresh-image info-art" title="Refresh background image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
<span class="overlay-refresh-image info-art" title="Refresh background image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||||
% endif
|
% endif
|
||||||
@@ -57,8 +61,8 @@ DOCUMENTATION :: END
|
|||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="table-card-back">
|
<div class="table-card-back">
|
||||||
<div class="user-info-wrapper">
|
<div class="user-info-wrapper">
|
||||||
% if data['library_thumb'][:4] == 'http' or data['library_thumb'][:10] == 'interfaces':
|
% if data['library_thumb'].startswith('http'):
|
||||||
<div class="library-info-poster-face" style="background-image: url(${data['library_thumb']});"></div>
|
<div class="library-info-poster-face" style="background-image: url(${page('pms_image_proxy', data['library_thumb'], None, 80, 80)});"></div>
|
||||||
% else:
|
% else:
|
||||||
<div class="library-info-poster-face svg-icon library-${data['section_type']}"></div>
|
<div class="library-info-poster-face svg-icon library-${data['section_type']}"></div>
|
||||||
% endif
|
% endif
|
||||||
@@ -75,8 +79,10 @@ DOCUMENTATION :: END
|
|||||||
<li class="active"><a href="#tabs-profile" role="tab" data-toggle="tab">Profile</a></li>
|
<li class="active"><a href="#tabs-profile" role="tab" data-toggle="tab">Profile</a></li>
|
||||||
<li><a id="history-tab-btn" href="#tabs-history" role="tab" data-toggle="tab">History</a></li>
|
<li><a id="history-tab-btn" href="#tabs-history" role="tab" data-toggle="tab">History</a></li>
|
||||||
% if _session['user_group'] == 'admin':
|
% if _session['user_group'] == 'admin':
|
||||||
|
% if data['section_id'] != LIVE_TV_SECTION_ID:
|
||||||
<li><a id="media-info-tab-btn" href="#tabs-mediainfo" role="tab" data-toggle="tab">Media Info</a></li>
|
<li><a id="media-info-tab-btn" href="#tabs-mediainfo" role="tab" data-toggle="tab">Media Info</a></li>
|
||||||
% endif
|
% endif
|
||||||
|
% endif
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -143,6 +149,7 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
% if data['section_id'] != LIVE_TV_SECTION_ID:
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
@@ -168,6 +175,7 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
% endif
|
||||||
</div>
|
</div>
|
||||||
<div role="tabpanel" class="tab-pane" id="tabs-history">
|
<div role="tabpanel" class="tab-pane" id="tabs-history">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
@@ -348,6 +356,7 @@ DOCUMENTATION :: END
|
|||||||
<script src="${http_root}js/dataTables.bootstrap.min.js"></script>
|
<script src="${http_root}js/dataTables.bootstrap.min.js"></script>
|
||||||
<script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
|
<script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
|
||||||
% if data:
|
% if data:
|
||||||
|
<% from plexpy.common import LIVE_TV_SECTION_ID %>
|
||||||
<script>
|
<script>
|
||||||
% if str(data['section_id']).isdigit():
|
% if str(data['section_id']).isdigit():
|
||||||
var section_id = ${data['section_id']};
|
var section_id = ${data['section_id']};
|
||||||
@@ -526,7 +535,9 @@ DOCUMENTATION :: END
|
|||||||
}
|
}
|
||||||
|
|
||||||
recentlyWatched();
|
recentlyWatched();
|
||||||
|
% if data['section_id'] != LIVE_TV_SECTION_ID:
|
||||||
recentlyAdded();
|
recentlyAdded();
|
||||||
|
% endif
|
||||||
|
|
||||||
function highlightWatchedScrollerButton() {
|
function highlightWatchedScrollerButton() {
|
||||||
var scroller = $("#recently-watched-row-scroller");
|
var scroller = $("#recently-watched-row-scroller");
|
||||||
|
@@ -31,6 +31,9 @@ DOCUMENTATION :: END
|
|||||||
</%doc>
|
</%doc>
|
||||||
|
|
||||||
% if data:
|
% if data:
|
||||||
|
<%
|
||||||
|
from plexpy.helpers import page
|
||||||
|
%>
|
||||||
<div class="dashboard-recent-media-row">
|
<div class="dashboard-recent-media-row">
|
||||||
<div id="recently-added-row-scroller" style="left: 0;">
|
<div id="recently-added-row-scroller" style="left: 0;">
|
||||||
<ul class="dashboard-recent-media list-unstyled">
|
<ul class="dashboard-recent-media list-unstyled">
|
||||||
@@ -38,19 +41,19 @@ DOCUMENTATION :: END
|
|||||||
<li>
|
<li>
|
||||||
% if item['media_type'] == 'episode' or item['media_type'] == 'movie':
|
% if item['media_type'] == 'episode' or item['media_type'] == 'movie':
|
||||||
% if item['media_type'] == 'movie':
|
% if item['media_type'] == 'movie':
|
||||||
<a href="info?rating_key=${item['rating_key']}" title="${item['title']}">
|
<a href="${page('info', item['rating_key'])}" title="${item['title']}">
|
||||||
% elif item['media_type'] == 'episode':
|
% elif item['media_type'] == 'episode':
|
||||||
<a href="info?rating_key=${item['rating_key']}" title="${item['grandparent_title']}">
|
<a href="${page('info', item['rating_key'])}" title="${item['grandparent_title']}">
|
||||||
% endif
|
% endif
|
||||||
<div class="dashboard-recent-media-poster">
|
<div class="dashboard-recent-media-poster">
|
||||||
% if item['media_type'] == 'episode':
|
% if item['media_type'] == 'episode':
|
||||||
% if item['parent_thumb']:
|
% if item['parent_thumb']:
|
||||||
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['parent_thumb']}&width=300&height=450&fallback=poster);">
|
<div class="dashboard-recent-media-poster-face" style="background-image: url(${page('pms_image_proxy', item['parent_thumb'], item['parent_rating_key'], 300, 450, fallback='poster')});">
|
||||||
% else:
|
% else:
|
||||||
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['grandparent_thumb']}&width=300&height=450&fallback=poster);">
|
<div class="dashboard-recent-media-poster-face" style="background-image: url(${page('pms_image_proxy', item['grandparent_thumb'], item['grandparent_rating_key'], 300, 450, fallback='poster')});">
|
||||||
% endif
|
% endif
|
||||||
% elif item['media_type'] == 'movie':
|
% elif item['media_type'] == 'movie':
|
||||||
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=450&fallback=poster);">
|
<div class="dashboard-recent-media-poster-face" style="background-image: url(${page('pms_image_proxy', item['thumb'], item['rating_key'], 300, 450, fallback='poster')});">
|
||||||
% endif
|
% endif
|
||||||
<div class="dashboard-recent-media-overlay">
|
<div class="dashboard-recent-media-overlay">
|
||||||
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
||||||
@@ -68,27 +71,27 @@ DOCUMENTATION :: END
|
|||||||
<div class="dashboard-recent-media-metacontainer">
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
% if item['media_type'] == 'episode':
|
% if item['media_type'] == 'episode':
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${item['grandparent_rating_key']}" title="${item['grandparent_title']}">${item['grandparent_title']}</a>
|
<a href="${page('info', item['grandparent_rating_key'])}" title="${item['grandparent_title']}">${item['grandparent_title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted">
|
<h3 class="text-muted">
|
||||||
<a href="info?rating_key=${item['rating_key']}" title="${item['title']}">${item['title']}</a>
|
<a href="${page('info', item['rating_key'])}" title="${item['title']}">${item['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted">
|
<h3 class="text-muted">
|
||||||
<a href="info?rating_key=${item['parent_rating_key']}" title="Season ${item['parent_media_index']}">S${item['parent_media_index']}</a>
|
<a href="${page('info', item['parent_rating_key'])}" title="Season ${item['parent_media_index']}">S${item['parent_media_index']}</a>
|
||||||
· <a href="info?rating_key=${item['rating_key']}" title="Episode ${item['media_index']}">E${item['media_index']}</a>
|
· <a href="${page('info', item['rating_key'])}" title="Episode ${item['media_index']}">E${item['media_index']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
% elif item['media_type'] == 'movie':
|
% elif item['media_type'] == 'movie':
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${item['rating_key']}" title="${item['title']}">${item['title']}</a>
|
<a href="${page('info', item['rating_key'])}" title="${item['title']}">${item['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted">${item['year']}</h3>
|
<h3 class="text-muted">${item['year']}</h3>
|
||||||
<h3 class="text-muted"> </h3>
|
<h3 class="text-muted"> </h3>
|
||||||
% endif
|
% endif
|
||||||
</div>
|
</div>
|
||||||
% elif item['media_type'] == 'album':
|
% elif item['media_type'] == 'album':
|
||||||
<a href="info?rating_key=${item['rating_key']}" title="${item['title']}">
|
<a href="${page('info', item['rating_key'])}" title="${item['title']}">
|
||||||
<div class="dashboard-recent-media-cover">
|
<div class="dashboard-recent-media-cover">
|
||||||
<div class="dashboard-recent-media-cover-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=300&fallback=cover);">
|
<div class="dashboard-recent-media-cover-face" style="background-image: url(${page('pms_image_proxy', item['thumb'], item['rating_key'], 300, 300, fallback='cover')});">
|
||||||
<div class="dashboard-recent-media-overlay">
|
<div class="dashboard-recent-media-overlay">
|
||||||
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
||||||
<script>
|
<script>
|
||||||
@@ -100,10 +103,10 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${item['parent_rating_key']}" title="${item['parent_title']}">${item['parent_title']}</a>
|
<a href="${page('info', item['parent_rating_key'])}" title="${item['parent_title']}">${item['parent_title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted">
|
<h3 class="text-muted">
|
||||||
<a class="text-muted" href="info?rating_key=${item['rating_key']}" title="${item['title']}">${item['title']}</a>
|
<a class="text-muted" href="${page('info', item['rating_key'])}" title="${item['title']}">${item['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted"> </h3>
|
<h3 class="text-muted"> </h3>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -25,6 +25,8 @@ DOCUMENTATION :: END
|
|||||||
|
|
||||||
% if data:
|
% if data:
|
||||||
<%
|
<%
|
||||||
|
from plexpy.helpers import page
|
||||||
|
|
||||||
types = ('movie', 'show', 'artist', 'photo')
|
types = ('movie', 'show', 'artist', 'photo')
|
||||||
headers = {'movie': ('Movie Libraries', ('Movies', '', '')),
|
headers = {'movie': ('Movie Libraries', ('Movies', '', '')),
|
||||||
'show': ('TV Show Libraries', ('Shows', 'Seasons', 'Episodes')),
|
'show': ('TV Show Libraries', ('Shows', 'Seasons', 'Episodes')),
|
||||||
@@ -33,10 +35,17 @@ DOCUMENTATION :: END
|
|||||||
%>
|
%>
|
||||||
% for section_type in types:
|
% for section_type in types:
|
||||||
% if section_type in data:
|
% if section_type in data:
|
||||||
|
<%
|
||||||
|
row0 = data[section_type][0]
|
||||||
|
%>
|
||||||
<div class="dashboard-stats-instance" id="library-stats-instance-${section_type}" data-section_type="${section_type}">
|
<div class="dashboard-stats-instance" id="library-stats-instance-${section_type}" data-section_type="${section_type}">
|
||||||
<div class="dashboard-stats-container">
|
<div class="dashboard-stats-container">
|
||||||
<div id="library-stats-background-${section_type}" class="dashboard-stats-background" style="background-image: url(pms_image_proxy?img=/:/resources/${section_type}-fanart.jpg&width=500&height=280&opacity=40&background=282828&blur=3&fallback=art);">
|
<div id="library-stats-background-${section_type}" class="dashboard-stats-background" style="background-image: url(${page('pms_image_proxy', row0['art'], None, 500, 280, 40, '282828', 3, fallback='art')});">
|
||||||
|
% if row0['thumb'].startswith('http'):
|
||||||
|
<div id="library-stats-thumb-${section_type}" class="dashboard-stats-flat hidden-xs" style="background-image: url(${page('pms_image_proxy', row0['thumb'], None, 80, 80)});"></div>
|
||||||
|
% else:
|
||||||
<div id="library-stats-thumb-${section_type}" class="dashboard-stats-flat svg-icon library-${section_type} hidden-xs"></div>
|
<div id="library-stats-thumb-${section_type}" class="dashboard-stats-flat svg-icon library-${section_type} hidden-xs"></div>
|
||||||
|
% endif
|
||||||
<div class="dashboard-stats-info-container">
|
<div class="dashboard-stats-info-container">
|
||||||
<div id="library-stats-title-${section_type}" class="dashboard-stats-info-title">
|
<div id="library-stats-title-${section_type}" class="dashboard-stats-info-title">
|
||||||
<h4>${headers[section_type][0]}</h4>
|
<h4>${headers[section_type][0]}</h4>
|
||||||
@@ -46,10 +55,11 @@ DOCUMENTATION :: END
|
|||||||
<div class="dashboard-stats-info scoller-content">
|
<div class="dashboard-stats-info scoller-content">
|
||||||
<ul class="list-unstyled dashboard-stats-info-list">
|
<ul class="list-unstyled dashboard-stats-info-list">
|
||||||
% for section in data[section_type]:
|
% for section in data[section_type]:
|
||||||
<li class="dashboard-stats-info-item ${'expanded' if loop.index == 0 else ''}">
|
<li class="dashboard-stats-info-item ${'expanded' if loop.index == 0 else ''}" data-stat_id="${section_type}"
|
||||||
|
data-art="${section.get('art')}" data-thumb="${section.get('thumb')}">
|
||||||
<div class="sub-list">${loop.index + 1}</div>
|
<div class="sub-list">${loop.index + 1}</div>
|
||||||
<div class="sub-value">
|
<div class="sub-value">
|
||||||
<a href="library?section_id=${section['section_id']}" title="${section['section_name']}">
|
<a href="${page('library', section['section_id'])}" title="${section['section_name']}">
|
||||||
${section['section_name']}
|
${section['section_name']}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -19,16 +19,17 @@ DOCUMENTATION :: END
|
|||||||
</%doc>
|
</%doc>
|
||||||
|
|
||||||
% if data:
|
% if data:
|
||||||
|
<% from plexpy.helpers import page %>
|
||||||
% for a in data:
|
% for a in data:
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<div class="user-player-instance">
|
<div class="user-player-instance">
|
||||||
<li>
|
<li>
|
||||||
% if a['user_id']:
|
% if a['user_id']:
|
||||||
<a href="user?user_id=${a['user_id']}" title="${a['friendly_name']}">
|
<a href="${page('user', a['user_id'])}" title="${a['friendly_name']}">
|
||||||
<div class="library-user-instance-box" style="background-image: url(${a['user_thumb']});"></div>
|
<div class="library-user-instance-box" style="background-image: url(${a['user_thumb']});"></div>
|
||||||
</a>
|
</a>
|
||||||
<div class=" user-player-instance-name">
|
<div class=" user-player-instance-name">
|
||||||
<a href="user?user_id=${a['user_id']}" title="${a['friendly_name']}">${a['friendly_name']}</a>
|
<a href="${page('user', a['user_id'])}" title="${a['friendly_name']}">${a['friendly_name']}</a>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="library-user-instance-box" style="background-image: url(${a['user_thumb']});"></div>
|
<div class="library-user-instance-box" style="background-image: url(${a['user_thumb']});"></div>
|
||||||
|
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
<!-- ICONS -->
|
<!-- ICONS -->
|
||||||
<!-- Android -->
|
<!-- Android -->
|
||||||
<link rel="manifest" href="${http_root}images/favicon/manifest.json?v=2.0.5">
|
<link rel="manifest" href="${http_root}images/favicon/manifest.json?v=2.0.5" crossorigin="use-credentials>
|
||||||
<meta name="theme-color" content="#282a2d">
|
<meta name="theme-color" content="#282a2d">
|
||||||
<!-- Apple -->
|
<!-- Apple -->
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="${http_root}images/favicon/apple-touch-icon.png?v=2.0.5">
|
<link rel="apple-touch-icon" sizes="180x180" href="${http_root}images/favicon/apple-touch-icon.png?v=2.0.5">
|
||||||
|
@@ -31,6 +31,9 @@ DOCUMENTATION :: END
|
|||||||
</%doc>
|
</%doc>
|
||||||
|
|
||||||
% if data != None:
|
% if data != None:
|
||||||
|
<%
|
||||||
|
from plexpy.helpers import page
|
||||||
|
%>
|
||||||
% if data:
|
% if data:
|
||||||
<div class="dashboard-recent-media-row">
|
<div class="dashboard-recent-media-row">
|
||||||
<div id="recently-added-row-scroller" style="left: 0;">
|
<div id="recently-added-row-scroller" style="left: 0;">
|
||||||
@@ -39,9 +42,9 @@ DOCUMENTATION :: END
|
|||||||
<div class="dashboard-recent-media-instance">
|
<div class="dashboard-recent-media-instance">
|
||||||
<li data-type="${item['media_type']}">
|
<li data-type="${item['media_type']}">
|
||||||
% if item['media_type'] == 'movie':
|
% if item['media_type'] == 'movie':
|
||||||
<a href="info?rating_key=${item['rating_key']}" title="${item['title']}">
|
<a href="${page('info', item['rating_key'])}" title="${item['title']}">
|
||||||
<div class="dashboard-recent-media-poster">
|
<div class="dashboard-recent-media-poster">
|
||||||
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=450&fallback=poster);">
|
<div class="dashboard-recent-media-poster-face" style="background-image: url(${page('pms_image_proxy', item['thumb'], item['rating_key'], 300, 450, fallback='poster')});">
|
||||||
<div class="dashboard-recent-media-overlay">
|
<div class="dashboard-recent-media-overlay">
|
||||||
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
||||||
<script>
|
<script>
|
||||||
@@ -57,15 +60,15 @@ DOCUMENTATION :: END
|
|||||||
</a>
|
</a>
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${item['rating_key']}" title="${item['title']}">${item['title']}</a>
|
<a href="${page('info', item['rating_key'])}" title="${item['title']}">${item['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted">${item['year']}</h3>
|
<h3 class="text-muted">${item['year']}</h3>
|
||||||
<h3 class="text-muted"> </h3>
|
<h3 class="text-muted"> </h3>
|
||||||
</div>
|
</div>
|
||||||
% elif item['media_type'] == 'show':
|
% elif item['media_type'] == 'show':
|
||||||
<a href="info?rating_key=${item['rating_key']}" title="${item['title']}">
|
<a href="${page('info', item['rating_key'])}" title="${item['title']}">
|
||||||
<div class="dashboard-recent-media-poster">
|
<div class="dashboard-recent-media-poster">
|
||||||
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=450&fallback=poster);">
|
<div class="dashboard-recent-media-poster-face" style="background-image: url(${page('pms_image_proxy', item['thumb'], item['rating_key'], 300, 450, fallback='poster')});">
|
||||||
<div class="dashboard-recent-media-overlay">
|
<div class="dashboard-recent-media-overlay">
|
||||||
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
||||||
<script>
|
<script>
|
||||||
@@ -81,7 +84,7 @@ DOCUMENTATION :: END
|
|||||||
</a>
|
</a>
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${item['rating_key']}" title="${item['title']}">${item['title']}</a>
|
<a href="${page('info', item['rating_key'])}" title="${item['title']}">${item['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted">
|
<h3 class="text-muted">
|
||||||
${item['child_count']} Seasons
|
${item['child_count']} Seasons
|
||||||
@@ -89,9 +92,13 @@ DOCUMENTATION :: END
|
|||||||
<h3 class="text-muted"> </h3>
|
<h3 class="text-muted"> </h3>
|
||||||
</div>
|
</div>
|
||||||
% elif item['media_type'] == 'season':
|
% elif item['media_type'] == 'season':
|
||||||
<a href="info?rating_key=${item['rating_key']}" title="${item['parent_title']}">
|
<a href="${page('info', item['rating_key'])}" title="${item['parent_title']}">
|
||||||
<div class="dashboard-recent-media-poster">
|
<div class="dashboard-recent-media-poster">
|
||||||
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['thumb'] or item['parent_thumb']}&width=300&height=450&fallback=poster);">
|
% if item['thumb']:
|
||||||
|
<div class="dashboard-recent-media-poster-face" style="background-image: url(${page('pms_image_proxy', item['thumb'], item['rating_key'], 300, 450, fallback='poster')});">
|
||||||
|
% else:
|
||||||
|
<div class="dashboard-recent-media-poster-face" style="background-image: url(${page('pms_image_proxy', item['parent_thumb'], item['parent_rating_key'], 300, 450, fallback='poster')});">
|
||||||
|
% endif
|
||||||
<div class="dashboard-recent-media-overlay">
|
<div class="dashboard-recent-media-overlay">
|
||||||
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
||||||
<script>
|
<script>
|
||||||
@@ -107,17 +114,17 @@ DOCUMENTATION :: END
|
|||||||
</a>
|
</a>
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${item['parent_rating_key']}" title="${item['parent_title']}">${item['parent_title']}</a>
|
<a href="${page('info', item['parent_rating_key'])}" title="${item['parent_title']}">${item['parent_title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted">
|
<h3 class="text-muted">
|
||||||
<a class="text-muted" href="info?rating_key=${item['rating_key']}" title="${item['title']}">${item['title']}</a>
|
<a class="text-muted" href="${page('info', item['rating_key'])}" title="${item['title']}">${item['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted"> </h3>
|
<h3 class="text-muted"> </h3>
|
||||||
</div>
|
</div>
|
||||||
% elif item['media_type'] == 'episode':
|
% elif item['media_type'] == 'episode':
|
||||||
<a href="info?rating_key=${item['rating_key']}" title="${item['title']}">
|
<a href="${page('info', item['rating_key'])}" title="${item['title']}">
|
||||||
<div class="dashboard-recent-media-poster">
|
<div class="dashboard-recent-media-poster">
|
||||||
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['grandparent_thumb']}&width=300&height=450&fallback=poster);">
|
<div class="dashboard-recent-media-poster-face" style="background-image: url(${page('pms_image_proxy', item['grandparent_thumb'], item['grandparent_rating_key'], 300, 450, fallback='poster')});">
|
||||||
<div class="dashboard-recent-media-overlay">
|
<div class="dashboard-recent-media-overlay">
|
||||||
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
||||||
<script>
|
<script>
|
||||||
@@ -133,21 +140,21 @@ DOCUMENTATION :: END
|
|||||||
</a>
|
</a>
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${item['grandparent_rating_key']}" title="${item['grandparent_title']}">${item['grandparent_title']}</a>
|
<a href="${page('info', item['grandparent_rating_key'])}" title="${item['grandparent_title']}">${item['grandparent_title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted">
|
<h3 class="text-muted">
|
||||||
<a href="info?rating_key=${item['rating_key']}" title="${item['title']}">${item['title']}</a>
|
<a href="${page('info', item['rating_key'])}" title="${item['title']}">${item['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted">
|
<h3 class="text-muted">
|
||||||
<a href="info?rating_key=${item['parent_rating_key']}" title="Season ${item['parent_media_index']}">S${item['parent_media_index']}</a>
|
<a href="${page('info', item['parent_rating_key'])}" title="Season ${item['parent_media_index']}">S${item['parent_media_index']}</a>
|
||||||
·
|
·
|
||||||
<a href="info?rating_key=${item['rating_key']}" title="Episode ${item['media_index']}">E${item['media_index']}</a>
|
<a href="${page('info', item['rating_key'])}" title="Episode ${item['media_index']}">E${item['media_index']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
% elif item['media_type'] == 'album':
|
% elif item['media_type'] == 'album':
|
||||||
<a href="info?rating_key=${item['rating_key']}" title="${item['parent_title']}">
|
<a href="${page('info', item['rating_key'])}" title="${item['parent_title']}">
|
||||||
<div class="dashboard-recent-media-cover">
|
<div class="dashboard-recent-media-cover">
|
||||||
<div class="dashboard-recent-media-cover-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=300&fallback=cover);">
|
<div class="dashboard-recent-media-cover-face" style="background-image: url(${page('pms_image_proxy', item['thumb'], item['rating_key'], 300, 300, fallback='cover')});">
|
||||||
<div class="dashboard-recent-media-overlay">
|
<div class="dashboard-recent-media-overlay">
|
||||||
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
||||||
<script>
|
<script>
|
||||||
@@ -163,10 +170,10 @@ DOCUMENTATION :: END
|
|||||||
</a>
|
</a>
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${item['parent_rating_key']}" title="${item['parent_title']}">${item['parent_title']}</a>
|
<a href="${page('info', item['parent_rating_key'])}" title="${item['parent_title']}">${item['parent_title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted">
|
<h3 class="text-muted">
|
||||||
<a class="text-muted" href="info?rating_key=${item['rating_key']}" title="${item['title']}">${item['title']}</a>
|
<a class="text-muted" href="${page('info', item['rating_key'])}" title="${item['title']}">${item['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted"> </h3>
|
<h3 class="text-muted"> </h3>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -217,7 +217,7 @@
|
|||||||
<div id="git_update_options">
|
<div id="git_update_options">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" id="plexpy_auto_update" name="plexpy_auto_update" value="1" ${config['plexpy_auto_update']}> Update Automatically
|
<input type="checkbox" id="plexpy_auto_update" name="plexpy_auto_update" value="1" ${config['plexpy_auto_update']} ${docker_setting}> Update Automatically ${docker_msg | n}
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Update Tautulli automatically if an update is available.</p>
|
<p class="help-block">Update Tautulli automatically if an update is available.</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -265,6 +265,20 @@
|
|||||||
</div>
|
</div>
|
||||||
<p class="help-block">Optional: The path to your git environment variable. Leave blank for default.</p>
|
<p class="help-block">Optional: The path to your git environment variable. Leave blank for default.</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group advanced-setting">
|
||||||
|
<label>Repair Git Install</label>
|
||||||
|
<p class="help-block">
|
||||||
|
Attempt to fix updating by resetting your Tautulli installation back to <strong>${common.RELEASE}</strong>.<br />
|
||||||
|
Note: This will not affect any saved history or settings.
|
||||||
|
</p>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="btn-group">
|
||||||
|
<button class="btn btn-form" type="button" id="reset_git_install">Reset</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
<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>
|
||||||
@@ -2154,6 +2168,17 @@ $(document).ready(function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#reset_git_install").click(function () {
|
||||||
|
var msg = 'Are you sure you want to reset your Tautulli installtion back to <strong>${common.RELEASE}</strong>?' +
|
||||||
|
'<br /><br />Tautulli will restart.';
|
||||||
|
$('#confirm-message').html(msg);
|
||||||
|
$('#confirm-modal').modal();
|
||||||
|
$('#confirm-modal').one('click', '#confirm-button', function () {
|
||||||
|
settingsChanged = false;
|
||||||
|
window.location.href = 'reset_git_install';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$('#api_key').click(function(){ $('#api_key').select() });
|
$('#api_key').click(function(){ $('#api_key').select() });
|
||||||
$("#generate_api").click(function() {
|
$("#generate_api").click(function() {
|
||||||
$.get('generate_api_key',
|
$.get('generate_api_key',
|
||||||
@@ -2531,6 +2556,7 @@ $(document).ready(function() {
|
|||||||
for (var i in libraries_list) {
|
for (var i in libraries_list) {
|
||||||
var title = libraries_list[i].section_name;
|
var title = libraries_list[i].section_name;
|
||||||
var key = libraries_list[i].section_id;
|
var key = libraries_list[i].section_id;
|
||||||
|
if (key === 999999) { continue; } // Don't show Live TV library
|
||||||
$('#sortable_home_library_cards').append(
|
$('#sortable_home_library_cards').append(
|
||||||
'<li class="card card-sortable">' +
|
'<li class="card card-sortable">' +
|
||||||
'<div class="card-handle"><i class="fa fa-bars"></i></div>' +
|
'<div class="card-handle"><i class="fa fa-bars"></i></div>' +
|
||||||
|
@@ -127,6 +127,7 @@ DOCUMENTATION :: END
|
|||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="modalIncludes()">
|
<%def name="modalIncludes()">
|
||||||
|
% if query:
|
||||||
<div class="modal fade" id="confirm-modal-update" tabindex="-1" role="dialog" aria-labelledby="confirm-modal-update">
|
<div class="modal fade" id="confirm-modal-update" tabindex="-1" role="dialog" aria-labelledby="confirm-modal-update">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@@ -169,6 +170,7 @@ DOCUMENTATION :: END
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="javascriptIncludes()">
|
<%def name="javascriptIncludes()">
|
||||||
|
@@ -168,6 +168,9 @@ DOCUMENTATION :: END
|
|||||||
<label class="btn btn-dark">
|
<label class="btn btn-dark">
|
||||||
<input type="radio" name="media_type-filter" id="history-track" value="track" autocomplete="off"> Music
|
<input type="radio" name="media_type-filter" id="history-track" value="track" autocomplete="off"> Music
|
||||||
</label>
|
</label>
|
||||||
|
<label class="btn btn-dark">
|
||||||
|
<input type="radio" name="media_type-filter" id="history-live" value="live" autocomplete="off"> Live TV
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button class="btn btn-dark refresh-history-button" id="refresh-history-list"><i class="fa fa-refresh"></i> Refresh history</button>
|
<button class="btn btn-dark refresh-history-button" id="refresh-history-list"><i class="fa fa-refresh"></i> Refresh history</button>
|
||||||
|
@@ -27,6 +27,9 @@ DOCUMENTATION :: END
|
|||||||
</%doc>
|
</%doc>
|
||||||
|
|
||||||
% if data:
|
% if data:
|
||||||
|
<%
|
||||||
|
from plexpy.helpers import page
|
||||||
|
%>
|
||||||
<div class="dashboard-recent-media-row">
|
<div class="dashboard-recent-media-row">
|
||||||
<div id="recently-watched-row-scroller" style="left: 0;">
|
<div id="recently-watched-row-scroller" style="left: 0;">
|
||||||
<ul class="dashboard-recent-media list-unstyled">
|
<ul class="dashboard-recent-media list-unstyled">
|
||||||
@@ -35,12 +38,12 @@ DOCUMENTATION :: END
|
|||||||
% if item['media_type'] == 'episode' or item['media_type'] == 'movie':
|
% if item['media_type'] == 'episode' or item['media_type'] == 'movie':
|
||||||
% if item['rating_key']:
|
% if item['rating_key']:
|
||||||
% if item['media_type'] == 'movie':
|
% if item['media_type'] == 'movie':
|
||||||
<a href="info?source=history&rating_key=${item['rating_key']}" title="${item['title']}">
|
<a href="${page('info', item['rating_key'], history=True, live=item['live'])}" title="${item['title']}">
|
||||||
% elif item['media_type'] == 'episode':
|
% elif item['media_type'] == 'episode':
|
||||||
<a href="info?source=history&rating_key=${item['rating_key']}" title="${item['grandparent_title']}">
|
<a href="${page('info', item['rating_key'], history=True, live=item['live'])}" title="${item['grandparent_title']}">
|
||||||
% endif
|
% endif
|
||||||
<div class="dashboard-recent-media-poster">
|
<div class="dashboard-recent-media-poster">
|
||||||
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=450&fallback=poster);">
|
<div class="dashboard-recent-media-poster-face" style="background-image: url(${page('pms_image_proxy', item['thumb'], item['rating_key'], 300, 450, fallback='poster')});">
|
||||||
<div class="dashboard-recent-media-overlay">
|
<div class="dashboard-recent-media-overlay">
|
||||||
<div class="dashboard-recent-media-overlay-text" id="time-${item['time']}">
|
<div class="dashboard-recent-media-overlay-text" id="time-${item['time']}">
|
||||||
<script>
|
<script>
|
||||||
@@ -56,19 +59,38 @@ DOCUMENTATION :: END
|
|||||||
</a>
|
</a>
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
% if item['media_type'] == 'episode':
|
% if item['media_type'] == 'episode':
|
||||||
|
% if item['live']:
|
||||||
<h3>
|
<h3>
|
||||||
<a href="info?rating_key=${item['grandparent_rating_key']}" title="${item['grandparent_title']}">${item['grandparent_title']}</a>
|
<a href="${page('info', item['rating_key'], history=True, live=item['live'])}" title="${item['grandparent_title']}">${item['grandparent_title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted" title="${item['title']}">
|
<h3 class="text-muted" title="${item['title']}">
|
||||||
<a href="info?source=history&rating_key=${item['rating_key']}" title="${item['title']}">${item['title']}</a>
|
<a href="${page('info', item['rating_key'], history=True, live=item['live'])}" title="${item['title']}">${item['title']}</a>
|
||||||
|
</h3>
|
||||||
|
% if item['media_index']:
|
||||||
|
<h3 class="text-muted">
|
||||||
|
<a href="${page('info', item['rating_key'], history=True, live=item['live'])}" title="Season ${item['parent_media_index']}">S${item['parent_media_index']}</a>
|
||||||
|
· <a href="${page('info', item['rating_key'], history=True, live=item['live'])}" title="Episode ${item['media_index']}">E${item['media_index']}</a>
|
||||||
|
</h3>
|
||||||
|
% else:
|
||||||
|
<h3 class="text-muted">
|
||||||
|
<a href="${page('info', item['rating_key'], history=True, live=item['live'])}" title="${item['originally_available_at']}">${item['originally_available_at']}</a>
|
||||||
|
</h3>
|
||||||
|
% endif
|
||||||
|
% else:
|
||||||
|
<h3>
|
||||||
|
<a href="${page('info', item['grandparent_rating_key'])}" title="${item['grandparent_title']}">${item['grandparent_title']}</a>
|
||||||
|
</h3>
|
||||||
|
<h3 class="text-muted" title="${item['title']}">
|
||||||
|
<a href="${page('info', item['rating_key'], history=True, live=item['live'])}" title="${item['title']}">${item['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted">
|
<h3 class="text-muted">
|
||||||
<a href="info?rating_key=${item['parent_rating_key']}" title="Season ${item['parent_media_index']}">S${item['parent_media_index']}</a>
|
<a href="${page('info', item['parent_rating_key'])}" title="Season ${item['parent_media_index']}">S${item['parent_media_index']}</a>
|
||||||
· <a href="info?source=history&rating_key=${item['rating_key']}" title="Episode ${item['media_index']}">E${item['media_index']}</a>
|
· <a href="${page('info', item['rating_key'], history=True, live=item['live'])}" title="Episode ${item['media_index']}">E${item['media_index']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
|
% endif
|
||||||
% elif item['media_type'] == 'movie':
|
% elif item['media_type'] == 'movie':
|
||||||
<h3 title="${item['title']}">
|
<h3 title="${item['title']}">
|
||||||
<a href="info?source=history&rating_key=${item['rating_key']}" title="${item['title']}">${item['title']}</a>
|
<a href="${page('info', item['rating_key'], history=True, live=item['live'])}" title="${item['title']}">${item['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted">${item['year']}</h3>
|
<h3 class="text-muted">${item['year']}</h3>
|
||||||
<h3 class="text-muted"> </h3>
|
<h3 class="text-muted"> </h3>
|
||||||
@@ -94,9 +116,9 @@ DOCUMENTATION :: END
|
|||||||
% endif
|
% endif
|
||||||
% elif item['media_type'] == 'track':
|
% elif item['media_type'] == 'track':
|
||||||
% if item['rating_key']:
|
% if item['rating_key']:
|
||||||
<a href="info?source=history&rating_key=${item['rating_key']}" title="${item['parent_title']}">
|
<a href="${page('info', item['rating_key'], history=True, live=item['live'])}" title="${item['parent_title']}">
|
||||||
<div class="dashboard-recent-media-cover">
|
<div class="dashboard-recent-media-cover">
|
||||||
<div class="dashboard-recent-media-cover-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=300&fallback=cover);">
|
<div class="dashboard-recent-media-cover-face" style="background-image: url(${page('pms_image_proxy', item['thumb'], item['rating_key'], 300, 300, fallback='cover')});">
|
||||||
<div class="dashboard-recent-media-overlay">
|
<div class="dashboard-recent-media-overlay">
|
||||||
<div class="dashboard-recent-media-overlay-text" id="time-${item['time']}">
|
<div class="dashboard-recent-media-overlay-text" id="time-${item['time']}">
|
||||||
<script>
|
<script>
|
||||||
@@ -109,13 +131,13 @@ DOCUMENTATION :: END
|
|||||||
</a>
|
</a>
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
<h3 title="${item['original_title'] or item['grandparent_title']}">
|
<h3 title="${item['original_title'] or item['grandparent_title']}">
|
||||||
<a href="info?rating_key=${item['grandparent_rating_key']}" title="${item['original_title'] or item['grandparent_title']}">${item['original_title'] or item['grandparent_title']}</a>
|
<a href="${page('info', item['grandparent_rating_key'])}" title="${item['original_title'] or item['grandparent_title']}">${item['original_title'] or item['grandparent_title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted" title="${item['title']}">
|
<h3 class="text-muted" title="${item['title']}">
|
||||||
<a href="info?source=history&rating_key=${item['rating_key']}" title="${item['title']}">${item['title']}</a>
|
<a href="${page('info', item['rating_key'], history=True, live=item['live'])}" title="${item['title']}">${item['title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-muted">
|
<h3 class="text-muted">
|
||||||
<a href="info?rating_key=${item['parent_rating_key']}" title="${item['parent_title']}">${item['parent_title']}</a>
|
<a href="${page('info', item['parent_rating_key'])}" title="${item['parent_title']}">${item['parent_title']}</a>
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
|
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
<!-- ICONS -->
|
<!-- ICONS -->
|
||||||
<!-- Android -->
|
<!-- Android -->
|
||||||
<link rel="manifest" href="${http_root}images/favicon/manifest.json?v=2.0.5">
|
<link rel="manifest" href="${http_root}images/favicon/manifest.json?v=2.0.5" crossorigin="use-credentials">
|
||||||
<meta name="theme-color" content="#282a2d">
|
<meta name="theme-color" content="#282a2d">
|
||||||
<!-- Apple -->
|
<!-- Apple -->
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="${http_root}images/favicon/apple-touch-icon.png?v=2.0.5">
|
<link rel="apple-touch-icon" sizes="180x180" href="${http_root}images/favicon/apple-touch-icon.png?v=2.0.5">
|
||||||
|
@@ -585,6 +585,7 @@ def dbcheck():
|
|||||||
'media_index INTEGER, parent_media_index INTEGER, '
|
'media_index INTEGER, parent_media_index INTEGER, '
|
||||||
'thumb TEXT, parent_thumb TEXT, grandparent_thumb TEXT, year INTEGER, '
|
'thumb TEXT, parent_thumb TEXT, grandparent_thumb TEXT, year INTEGER, '
|
||||||
'parent_rating_key INTEGER, grandparent_rating_key INTEGER, '
|
'parent_rating_key INTEGER, grandparent_rating_key INTEGER, '
|
||||||
|
'originally_available_at TEXT, added_at INTEGER, guid TEXT, '
|
||||||
'view_offset INTEGER DEFAULT 0, duration INTEGER, video_decision TEXT, audio_decision TEXT, '
|
'view_offset INTEGER DEFAULT 0, duration INTEGER, video_decision TEXT, audio_decision TEXT, '
|
||||||
'transcode_decision TEXT, container TEXT, bitrate INTEGER, width INTEGER, height INTEGER, '
|
'transcode_decision TEXT, container TEXT, bitrate INTEGER, width INTEGER, height INTEGER, '
|
||||||
'video_codec TEXT, video_bitrate INTEGER, video_resolution TEXT, video_width INTEGER, video_height INTEGER, '
|
'video_codec TEXT, video_bitrate INTEGER, video_resolution TEXT, video_width INTEGER, video_height INTEGER, '
|
||||||
@@ -604,7 +605,8 @@ def dbcheck():
|
|||||||
'transcode_hw_decoding INTEGER, transcode_hw_encoding INTEGER, '
|
'transcode_hw_decoding INTEGER, transcode_hw_encoding INTEGER, '
|
||||||
'optimized_version INTEGER, optimized_version_profile TEXT, optimized_version_title TEXT, '
|
'optimized_version INTEGER, optimized_version_profile TEXT, optimized_version_title TEXT, '
|
||||||
'synced_version INTEGER, synced_version_profile TEXT, '
|
'synced_version INTEGER, synced_version_profile TEXT, '
|
||||||
'live INTEGER, live_uuid TEXT, secure INTEGER, relayed INTEGER, '
|
'live INTEGER, live_uuid TEXT, channel_call_sign TEXT, channel_identifier TEXT, channel_thumb TEXT, '
|
||||||
|
'secure INTEGER, relayed INTEGER, '
|
||||||
'buffer_count INTEGER DEFAULT 0, buffer_last_triggered INTEGER, last_paused INTEGER, watched INTEGER DEFAULT 0, '
|
'buffer_count INTEGER DEFAULT 0, buffer_last_triggered INTEGER, last_paused INTEGER, watched INTEGER DEFAULT 0, '
|
||||||
'write_attempts INTEGER DEFAULT 0, raw_stream_info TEXT)'
|
'write_attempts INTEGER DEFAULT 0, raw_stream_info TEXT)'
|
||||||
)
|
)
|
||||||
@@ -652,7 +654,7 @@ def dbcheck():
|
|||||||
'art TEXT, media_type TEXT, year INTEGER, originally_available_at TEXT, added_at INTEGER, updated_at INTEGER, '
|
'art TEXT, media_type TEXT, year INTEGER, originally_available_at TEXT, added_at INTEGER, updated_at INTEGER, '
|
||||||
'last_viewed_at INTEGER, content_rating TEXT, summary TEXT, tagline TEXT, rating TEXT, '
|
'last_viewed_at INTEGER, content_rating TEXT, summary TEXT, tagline TEXT, rating TEXT, '
|
||||||
'duration INTEGER DEFAULT 0, guid TEXT, directors TEXT, writers TEXT, actors TEXT, genres TEXT, studio TEXT, '
|
'duration INTEGER DEFAULT 0, guid TEXT, directors TEXT, writers TEXT, actors TEXT, genres TEXT, studio TEXT, '
|
||||||
'labels TEXT)'
|
'labels TEXT, live INTEGER DEFAULT 0, channel_call_sign TEXT, channel_identifier TEXT, channel_thumb TEXT)'
|
||||||
)
|
)
|
||||||
|
|
||||||
# users table :: This table keeps record of the friends list
|
# users table :: This table keeps record of the friends list
|
||||||
@@ -670,7 +672,8 @@ def dbcheck():
|
|||||||
c_db.execute(
|
c_db.execute(
|
||||||
'CREATE TABLE IF NOT EXISTS library_sections (id INTEGER PRIMARY KEY AUTOINCREMENT, '
|
'CREATE TABLE IF NOT EXISTS library_sections (id INTEGER PRIMARY KEY AUTOINCREMENT, '
|
||||||
'server_id TEXT, section_id INTEGER, section_name TEXT, section_type TEXT, agent TEXT, '
|
'server_id TEXT, section_id INTEGER, section_name TEXT, section_type TEXT, agent TEXT, '
|
||||||
'thumb TEXT, custom_thumb_url TEXT, art TEXT, count INTEGER, parent_count INTEGER, child_count INTEGER, '
|
'thumb TEXT, custom_thumb_url TEXT, art TEXT, custom_art_url TEXT, '
|
||||||
|
'count INTEGER, parent_count INTEGER, child_count INTEGER, '
|
||||||
'do_notify INTEGER DEFAULT 1, do_notify_created INTEGER DEFAULT 1, keep_history INTEGER DEFAULT 1, '
|
'do_notify INTEGER DEFAULT 1, do_notify_created INTEGER DEFAULT 1, keep_history INTEGER DEFAULT 1, '
|
||||||
'deleted_section INTEGER DEFAULT 0, UNIQUE(server_id, section_id))'
|
'deleted_section INTEGER DEFAULT 0, UNIQUE(server_id, section_id))'
|
||||||
)
|
)
|
||||||
@@ -1220,6 +1223,42 @@ def dbcheck():
|
|||||||
'ALTER TABLE sessions ADD COLUMN stream_video_dynamic_range TEXT'
|
'ALTER TABLE sessions ADD COLUMN stream_video_dynamic_range TEXT'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Upgrade sessions table from earlier versions
|
||||||
|
try:
|
||||||
|
c_db.execute('SELECT channel_identifier FROM sessions')
|
||||||
|
except sqlite3.OperationalError:
|
||||||
|
logger.debug(u"Altering database. Updating database table sessions.")
|
||||||
|
c_db.execute(
|
||||||
|
'ALTER TABLE sessions ADD COLUMN channel_call_sign TEXT'
|
||||||
|
)
|
||||||
|
c_db.execute(
|
||||||
|
'ALTER TABLE sessions ADD COLUMN channel_identifier TEXT'
|
||||||
|
)
|
||||||
|
c_db.execute(
|
||||||
|
'ALTER TABLE sessions ADD COLUMN channel_thumb TEXT'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Upgrade sessions table from earlier versions
|
||||||
|
try:
|
||||||
|
c_db.execute('SELECT originally_available_at FROM sessions')
|
||||||
|
except sqlite3.OperationalError:
|
||||||
|
logger.debug(u"Altering database. Updating database table sessions.")
|
||||||
|
c_db.execute(
|
||||||
|
'ALTER TABLE sessions ADD COLUMN originally_available_at TEXT'
|
||||||
|
)
|
||||||
|
c_db.execute(
|
||||||
|
'ALTER TABLE sessions ADD COLUMN added_at INTEGER'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Upgrade sessions table from earlier versions
|
||||||
|
try:
|
||||||
|
c_db.execute('SELECT guid FROM sessions')
|
||||||
|
except sqlite3.OperationalError:
|
||||||
|
logger.debug(u"Altering database. Updating database table sessions.")
|
||||||
|
c_db.execute(
|
||||||
|
'ALTER TABLE sessions ADD COLUMN guid TEXT'
|
||||||
|
)
|
||||||
|
|
||||||
# Upgrade session_history table from earlier versions
|
# Upgrade session_history table from earlier versions
|
||||||
try:
|
try:
|
||||||
c_db.execute('SELECT reference_id FROM session_history')
|
c_db.execute('SELECT reference_id FROM session_history')
|
||||||
@@ -1282,6 +1321,18 @@ def dbcheck():
|
|||||||
'ALTER TABLE session_history ADD COLUMN relayed INTEGER'
|
'ALTER TABLE session_history ADD COLUMN relayed INTEGER'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Upgrade session_history table from earlier versions
|
||||||
|
try:
|
||||||
|
result = c_db.execute('SELECT platform FROM session_history '
|
||||||
|
'WHERE platform = "windows"').fetchall()
|
||||||
|
if len(result) > 0:
|
||||||
|
logger.debug(u"Altering database. Capitalizing Windows platform values in session_history table.")
|
||||||
|
c_db.execute(
|
||||||
|
'UPDATE session_history SET platform = "Windows" WHERE platform = "windows" '
|
||||||
|
)
|
||||||
|
except sqlite3.OperationalError:
|
||||||
|
logger.warn(u"Unable to capitalize Windows platform values in session_history table.")
|
||||||
|
|
||||||
# Upgrade session_history_metadata table from earlier versions
|
# Upgrade session_history_metadata table from earlier versions
|
||||||
try:
|
try:
|
||||||
c_db.execute('SELECT full_title FROM session_history_metadata')
|
c_db.execute('SELECT full_title FROM session_history_metadata')
|
||||||
@@ -1327,6 +1378,24 @@ def dbcheck():
|
|||||||
'ALTER TABLE session_history_metadata ADD COLUMN original_title TEXT'
|
'ALTER TABLE session_history_metadata ADD COLUMN original_title TEXT'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Upgrade session_history_metadata table from earlier versions
|
||||||
|
try:
|
||||||
|
c_db.execute('SELECT live FROM session_history_metadata')
|
||||||
|
except sqlite3.OperationalError:
|
||||||
|
logger.debug(u"Altering database. Updating database table session_history_metadata.")
|
||||||
|
c_db.execute(
|
||||||
|
'ALTER TABLE session_history_metadata ADD COLUMN live INTEGER DEFAULT 0'
|
||||||
|
)
|
||||||
|
c_db.execute(
|
||||||
|
'ALTER TABLE session_history_metadata ADD COLUMN channel_call_sign TEXT'
|
||||||
|
)
|
||||||
|
c_db.execute(
|
||||||
|
'ALTER TABLE session_history_metadata ADD COLUMN channel_identifier TEXT'
|
||||||
|
)
|
||||||
|
c_db.execute(
|
||||||
|
'ALTER TABLE session_history_metadata ADD COLUMN channel_thumb TEXT'
|
||||||
|
)
|
||||||
|
|
||||||
# Upgrade session_history_media_info table from earlier versions
|
# Upgrade session_history_media_info table from earlier versions
|
||||||
try:
|
try:
|
||||||
c_db.execute('SELECT transcode_decision FROM session_history_media_info')
|
c_db.execute('SELECT transcode_decision FROM session_history_media_info')
|
||||||
@@ -1825,6 +1894,15 @@ def dbcheck():
|
|||||||
'ALTER TABLE library_sections ADD COLUMN agent TEXT'
|
'ALTER TABLE library_sections ADD COLUMN agent TEXT'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Upgrade library_sections table from earlier versions
|
||||||
|
try:
|
||||||
|
c_db.execute('SELECT custom_art_url FROM library_sections')
|
||||||
|
except sqlite3.OperationalError:
|
||||||
|
logger.debug(u"Altering database. Updating database table library_sections.")
|
||||||
|
c_db.execute(
|
||||||
|
'ALTER TABLE library_sections ADD COLUMN custom_art_url TEXT'
|
||||||
|
)
|
||||||
|
|
||||||
# Upgrade users table from earlier versions (remove UNIQUE constraint on username)
|
# Upgrade users table from earlier versions (remove UNIQUE constraint on username)
|
||||||
try:
|
try:
|
||||||
result = c_db.execute('SELECT SQL FROM sqlite_master WHERE type="table" AND name="users"').fetchone()
|
result = c_db.execute('SELECT SQL FROM sqlite_master WHERE type="table" AND name="users"').fetchone()
|
||||||
@@ -2011,7 +2089,7 @@ def upgrade():
|
|||||||
libraries.update_libraries_db_notify()
|
libraries.update_libraries_db_notify()
|
||||||
|
|
||||||
|
|
||||||
def shutdown(restart=False, update=False, checkout=False):
|
def shutdown(restart=False, update=False, checkout=False, reset=False):
|
||||||
webstart.stop()
|
webstart.stop()
|
||||||
|
|
||||||
# Shutdown the websocket connection
|
# Shutdown the websocket connection
|
||||||
@@ -2046,6 +2124,13 @@ def shutdown(restart=False, update=False, checkout=False):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"Tautulli failed to switch git branch: %s. Restarting." % e)
|
logger.warn(u"Tautulli failed to switch git branch: %s. Restarting." % e)
|
||||||
|
|
||||||
|
if reset:
|
||||||
|
logger.info(u"Tautulli is resetting the git install...")
|
||||||
|
try:
|
||||||
|
versioncheck.reset_git_install()
|
||||||
|
except Exception as e:
|
||||||
|
logger.warn(u"Tautulli failed to reset git install: %s. Restarting." % e)
|
||||||
|
|
||||||
if CREATEPID:
|
if CREATEPID:
|
||||||
logger.info(u"Removing pidfile %s", PIDFILE)
|
logger.info(u"Removing pidfile %s", PIDFILE)
|
||||||
os.remove(PIDFILE)
|
os.remove(PIDFILE)
|
||||||
|
@@ -58,9 +58,19 @@ class ActivityHandler(object):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_live_session(self):
|
def get_metadata(self, skip_cache=False):
|
||||||
|
cache_key = None if skip_cache else self.get_session_key()
|
||||||
pms_connect = pmsconnect.PmsConnect()
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
session_list = pms_connect.get_current_activity()
|
metadata = pms_connect.get_metadata_details(rating_key=self.get_rating_key(), cache_key=cache_key)
|
||||||
|
|
||||||
|
if metadata:
|
||||||
|
return metadata
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_live_session(self, skip_cache=False):
|
||||||
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
|
session_list = pms_connect.get_current_activity(skip_cache=skip_cache)
|
||||||
|
|
||||||
if session_list:
|
if session_list:
|
||||||
for session in session_list['sessions']:
|
for session in session_list['sessions']:
|
||||||
@@ -94,7 +104,7 @@ class ActivityHandler(object):
|
|||||||
|
|
||||||
def on_start(self):
|
def on_start(self):
|
||||||
if self.is_valid_session():
|
if self.is_valid_session():
|
||||||
session = self.get_live_session()
|
session = self.get_live_session(skip_cache=True)
|
||||||
|
|
||||||
if not session:
|
if not session:
|
||||||
return
|
return
|
||||||
@@ -107,9 +117,9 @@ class ActivityHandler(object):
|
|||||||
if not session:
|
if not session:
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.debug(u"Tautulli ActivityHandler :: Session %s started by user %s (%s) with ratingKey %s (%s)."
|
logger.debug(u"Tautulli ActivityHandler :: Session %s started by user %s (%s) with ratingKey %s (%s)%s."
|
||||||
% (str(session['session_key']), str(session['user_id']), session['username'],
|
% (str(session['session_key']), str(session['user_id']), session['username'],
|
||||||
str(session['rating_key']), session['full_title']))
|
str(session['rating_key']), session['full_title'], '[Live TV]' if session['live'] else ''))
|
||||||
|
|
||||||
plexpy.NOTIFY_QUEUE.put({'stream_data': session.copy(), 'notify_action': 'on_play'})
|
plexpy.NOTIFY_QUEUE.put({'stream_data': session.copy(), 'notify_action': 'on_play'})
|
||||||
|
|
||||||
@@ -269,11 +279,20 @@ class ActivityHandler(object):
|
|||||||
last_transcode_key = db_session['transcode_key'].split('/')[-1]
|
last_transcode_key = db_session['transcode_key'].split('/')[-1]
|
||||||
last_paused = db_session['last_paused']
|
last_paused = db_session['last_paused']
|
||||||
last_rating_key_websocket = db_session['rating_key_websocket']
|
last_rating_key_websocket = db_session['rating_key_websocket']
|
||||||
|
last_guid = db_session['guid']
|
||||||
|
|
||||||
|
this_guid = last_guid
|
||||||
|
# Check guid for live TV metadata every 60 seconds
|
||||||
|
if db_session['live'] and int(time.time()) - db_session['stopped'] > 60:
|
||||||
|
metadata = self.get_metadata(skip_cache=True)
|
||||||
|
if metadata:
|
||||||
|
this_guid = metadata['guid']
|
||||||
|
|
||||||
# Make sure the same item is being played
|
# Make sure the same item is being played
|
||||||
if this_rating_key == last_rating_key \
|
if (this_rating_key == last_rating_key
|
||||||
or this_rating_key == last_rating_key_websocket \
|
or this_rating_key == last_rating_key_websocket
|
||||||
or this_live_uuid == last_live_uuid:
|
or this_live_uuid == last_live_uuid) \
|
||||||
|
and this_guid == last_guid:
|
||||||
# Update the session state and viewOffset
|
# Update the session state and viewOffset
|
||||||
if this_state == 'playing':
|
if this_state == 'playing':
|
||||||
# Update the session in our temp session table
|
# Update the session in our temp session table
|
||||||
|
@@ -61,6 +61,9 @@ class ActivityProcessor(object):
|
|||||||
'platform': session.get('platform', ''),
|
'platform': session.get('platform', ''),
|
||||||
'parent_rating_key': session.get('parent_rating_key', ''),
|
'parent_rating_key': session.get('parent_rating_key', ''),
|
||||||
'grandparent_rating_key': session.get('grandparent_rating_key', ''),
|
'grandparent_rating_key': session.get('grandparent_rating_key', ''),
|
||||||
|
'originally_available_at': session.get('originally_available_at', ''),
|
||||||
|
'added_at': session.get('added_at', ''),
|
||||||
|
'guid': session.get('guid', ''),
|
||||||
'view_offset': session.get('view_offset', ''),
|
'view_offset': session.get('view_offset', ''),
|
||||||
'duration': session.get('duration', ''),
|
'duration': session.get('duration', ''),
|
||||||
'video_decision': session.get('video_decision', ''),
|
'video_decision': session.get('video_decision', ''),
|
||||||
@@ -125,6 +128,9 @@ class ActivityProcessor(object):
|
|||||||
'relayed': session.get('relayed', 0),
|
'relayed': session.get('relayed', 0),
|
||||||
'rating_key_websocket': session.get('rating_key_websocket', ''),
|
'rating_key_websocket': session.get('rating_key_websocket', ''),
|
||||||
'raw_stream_info': json.dumps(session),
|
'raw_stream_info': json.dumps(session),
|
||||||
|
'channel_call_sign': session.get('channel_call_sign', ''),
|
||||||
|
'channel_identifier': session.get('channel_identifier', ''),
|
||||||
|
'channel_thumb': session.get('channel_thumb', ''),
|
||||||
'stopped': int(time.time())
|
'stopped': int(time.time())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +149,10 @@ class ActivityProcessor(object):
|
|||||||
timestamp = {'started': started}
|
timestamp = {'started': started}
|
||||||
self.db.upsert('sessions', timestamp, keys)
|
self.db.upsert('sessions', timestamp, keys)
|
||||||
|
|
||||||
|
# Add Live TV library if it hasn't been added
|
||||||
|
if values['live']:
|
||||||
|
libraries.add_live_tv_library()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def write_session_history(self, session=None, import_metadata=None, is_import=False, import_ignore_interval=0):
|
def write_session_history(self, session=None, import_metadata=None, is_import=False, import_ignore_interval=0):
|
||||||
@@ -235,6 +245,11 @@ class ActivityProcessor(object):
|
|||||||
if not is_import:
|
if not is_import:
|
||||||
logger.debug(u"Tautulli ActivityProcessor :: Fetching metadata for item ratingKey %s" % session['rating_key'])
|
logger.debug(u"Tautulli ActivityProcessor :: Fetching metadata for item ratingKey %s" % session['rating_key'])
|
||||||
pms_connect = pmsconnect.PmsConnect()
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
|
if session['live']:
|
||||||
|
metadata = pms_connect.get_metadata_details(rating_key=str(session['rating_key']),
|
||||||
|
cache_key=session['session_key'],
|
||||||
|
return_cache=True)
|
||||||
|
else:
|
||||||
metadata = pms_connect.get_metadata_details(rating_key=str(session['rating_key']))
|
metadata = pms_connect.get_metadata_details(rating_key=str(session['rating_key']))
|
||||||
if not metadata:
|
if not metadata:
|
||||||
return False
|
return False
|
||||||
@@ -279,30 +294,49 @@ class ActivityProcessor(object):
|
|||||||
# % session['session_key'])
|
# % session['session_key'])
|
||||||
self.db.upsert(table_name='session_history', key_dict=keys, value_dict=values)
|
self.db.upsert(table_name='session_history', key_dict=keys, value_dict=values)
|
||||||
|
|
||||||
|
# Get the last insert row id
|
||||||
|
last_id = self.db.last_insert_id()
|
||||||
|
new_session = prev_session = None
|
||||||
|
prev_progress_percent = media_watched_percent = 0
|
||||||
|
|
||||||
|
if session['live']:
|
||||||
|
# Check if we should group the session, select the last guid from the user
|
||||||
|
query = 'SELECT session_history.id, session_history_metadata.guid, session_history.reference_id ' \
|
||||||
|
'FROM session_history ' \
|
||||||
|
'JOIN session_history_metadata ON session_history.id == session_history_metadata.id ' \
|
||||||
|
'WHERE session_history.user_id = ? ORDER BY session_history.id DESC LIMIT 1 '
|
||||||
|
|
||||||
|
args = [session['user_id']]
|
||||||
|
|
||||||
|
result = self.db.select(query=query, args=args)
|
||||||
|
|
||||||
|
if len(result) > 0:
|
||||||
|
new_session = {'id': last_id,
|
||||||
|
'guid': metadata['guid'],
|
||||||
|
'reference_id': last_id}
|
||||||
|
|
||||||
|
prev_session = {'id': result[0]['id'],
|
||||||
|
'guid': result[0]['guid'],
|
||||||
|
'reference_id': result[0]['reference_id']}
|
||||||
|
|
||||||
|
else:
|
||||||
# Check if we should group the session, select the last two rows from the user
|
# Check if we should group the session, select the last two rows from the user
|
||||||
query = 'SELECT id, rating_key, view_offset, user_id, reference_id FROM session_history ' \
|
query = 'SELECT id, rating_key, view_offset, reference_id FROM session_history ' \
|
||||||
'WHERE user_id = ? AND rating_key = ? ORDER BY id DESC LIMIT 2 '
|
'WHERE user_id = ? AND rating_key = ? ORDER BY id DESC LIMIT 2 '
|
||||||
|
|
||||||
args = [session['user_id'], session['rating_key']]
|
args = [session['user_id'], session['rating_key']]
|
||||||
|
|
||||||
result = self.db.select(query=query, args=args)
|
result = self.db.select(query=query, args=args)
|
||||||
|
|
||||||
new_session = prev_session = None
|
|
||||||
prev_progress_percent = media_watched_percent = 0
|
|
||||||
# Get the last insert row id
|
|
||||||
last_id = self.db.last_insert_id()
|
|
||||||
|
|
||||||
if len(result) > 1:
|
if len(result) > 1:
|
||||||
new_session = {'id': result[0]['id'],
|
new_session = {'id': result[0]['id'],
|
||||||
'rating_key': result[0]['rating_key'],
|
'rating_key': result[0]['rating_key'],
|
||||||
'view_offset': result[0]['view_offset'],
|
'view_offset': result[0]['view_offset'],
|
||||||
'user_id': result[0]['user_id'],
|
|
||||||
'reference_id': result[0]['reference_id']}
|
'reference_id': result[0]['reference_id']}
|
||||||
|
|
||||||
prev_session = {'id': result[1]['id'],
|
prev_session = {'id': result[1]['id'],
|
||||||
'rating_key': result[1]['rating_key'],
|
'rating_key': result[1]['rating_key'],
|
||||||
'view_offset': result[1]['view_offset'],
|
'view_offset': result[1]['view_offset'],
|
||||||
'user_id': result[1]['user_id'],
|
|
||||||
'reference_id': result[1]['reference_id']}
|
'reference_id': result[1]['reference_id']}
|
||||||
|
|
||||||
watched_percent = {'movie': plexpy.CONFIG.MOVIE_WATCHED_PERCENT,
|
watched_percent = {'movie': plexpy.CONFIG.MOVIE_WATCHED_PERCENT,
|
||||||
@@ -321,7 +355,8 @@ class ActivityProcessor(object):
|
|||||||
if prev_session is None and new_session is None:
|
if prev_session is None and new_session is None:
|
||||||
args = [last_id, last_id]
|
args = [last_id, last_id]
|
||||||
elif prev_progress_percent < media_watched_percent and \
|
elif prev_progress_percent < media_watched_percent and \
|
||||||
prev_session['view_offset'] <= new_session['view_offset']:
|
prev_session['view_offset'] <= new_session['view_offset'] or \
|
||||||
|
session['live'] and prev_session['guid'] == new_session['guid']:
|
||||||
args = [prev_session['reference_id'], new_session['id']]
|
args = [prev_session['reference_id'], new_session['id']]
|
||||||
else:
|
else:
|
||||||
args = [new_session['id'], new_session['id']]
|
args = [new_session['id'], new_session['id']]
|
||||||
@@ -453,7 +488,11 @@ class ActivityProcessor(object):
|
|||||||
'actors': actors,
|
'actors': actors,
|
||||||
'genres': genres,
|
'genres': genres,
|
||||||
'studio': metadata['studio'],
|
'studio': metadata['studio'],
|
||||||
'labels': labels
|
'labels': labels,
|
||||||
|
'live': session['live'],
|
||||||
|
'channel_call_sign': media_info.get('channel_call_sign', ''),
|
||||||
|
'channel_identifier': media_info.get('channel_identifier', ''),
|
||||||
|
'channel_thumb': media_info.get('channel_thumb', '')
|
||||||
}
|
}
|
||||||
|
|
||||||
# logger.debug(u"Tautulli ActivityProcessor :: Writing sessionKey %s session_history_metadata transaction..."
|
# logger.debug(u"Tautulli ActivityProcessor :: Writing sessionKey %s session_history_metadata transaction..."
|
||||||
|
@@ -116,7 +116,7 @@ class API2:
|
|||||||
# Allow override for the api.
|
# Allow override for the api.
|
||||||
self._api_out_type = kwargs.pop('out_type', 'json')
|
self._api_out_type = kwargs.pop('out_type', 'json')
|
||||||
|
|
||||||
if 'app' in kwargs and kwargs.pop('app') == 'true':
|
if 'app' in kwargs and helpers.bool_true(kwargs.pop('app')):
|
||||||
self._api_app = True
|
self._api_app = True
|
||||||
|
|
||||||
if plexpy.CONFIG.API_ENABLED and not self._api_msg or self._api_cmd in ('get_apikey', 'docs', 'docs_md'):
|
if plexpy.CONFIG.API_ENABLED and not self._api_msg or self._api_cmd in ('get_apikey', 'docs', 'docs_md'):
|
||||||
|
@@ -34,11 +34,26 @@ DEFAULT_USER_THUMB = "interfaces/default/images/gravatar-default-80x80.png"
|
|||||||
DEFAULT_POSTER_THUMB = "interfaces/default/images/poster.png"
|
DEFAULT_POSTER_THUMB = "interfaces/default/images/poster.png"
|
||||||
DEFAULT_COVER_THUMB = "interfaces/default/images/cover.png"
|
DEFAULT_COVER_THUMB = "interfaces/default/images/cover.png"
|
||||||
DEFAULT_ART = "interfaces/default/images/art.png"
|
DEFAULT_ART = "interfaces/default/images/art.png"
|
||||||
|
DEFAULT_LIVE_TV_POSTER_THUMB = "interfaces/default/images/poster-live.png"
|
||||||
|
DEFAULT_LIVE_TV_ART = "interfaces/default/images/art-live.png"
|
||||||
|
DEFAULT_LIVE_TV_ART_FULL = "interfaces/default/images/art-live-full.png"
|
||||||
|
|
||||||
ONLINE_POSTER_THUMB = "https://tautulli.com/images/poster.png"
|
ONLINE_POSTER_THUMB = "https://tautulli.com/images/poster.png"
|
||||||
ONLINE_COVER_THUMB = "https://tautulli.com/images/cover.png"
|
ONLINE_COVER_THUMB = "https://tautulli.com/images/cover.png"
|
||||||
ONLINE_ART = "https://tautulli.com/images/art.png"
|
ONLINE_ART = "https://tautulli.com/images/art.png"
|
||||||
|
|
||||||
|
LIVE_TV_SECTION_ID = 999999 # Fake section_id for Live TV library
|
||||||
|
LIVE_TV_SECTION_NAME = "Live TV" # Fake section_name for Live TV library
|
||||||
|
|
||||||
|
DEFAULT_IMAGES = {
|
||||||
|
'poster': DEFAULT_POSTER_THUMB,
|
||||||
|
'cover': DEFAULT_COVER_THUMB,
|
||||||
|
'art': DEFAULT_ART,
|
||||||
|
'poster-live': DEFAULT_LIVE_TV_POSTER_THUMB,
|
||||||
|
'art-live': DEFAULT_LIVE_TV_ART,
|
||||||
|
'art-live-full': DEFAULT_LIVE_TV_ART_FULL
|
||||||
|
}
|
||||||
|
|
||||||
MEDIA_TYPE_HEADERS = {
|
MEDIA_TYPE_HEADERS = {
|
||||||
'movie': 'Movies',
|
'movie': 'Movies',
|
||||||
'show': 'TV Shows',
|
'show': 'TV Shows',
|
||||||
@@ -351,6 +366,9 @@ NOTIFICATION_PARAMETERS = [
|
|||||||
{'name': 'Optimized Version Profile', 'type': 'str', 'value': 'optimized_version_profile', 'description': 'The optimized version profile of the stream.'},
|
{'name': 'Optimized Version Profile', 'type': 'str', 'value': 'optimized_version_profile', 'description': 'The optimized version profile of the stream.'},
|
||||||
{'name': 'Synced Version', 'type': 'int', 'value': 'synced_version', 'description': 'If the stream is an synced version.', 'example': '0 or 1'},
|
{'name': 'Synced Version', 'type': 'int', 'value': 'synced_version', 'description': 'If the stream is an synced version.', 'example': '0 or 1'},
|
||||||
{'name': 'Live', 'type': 'int', 'value': 'live', 'description': 'If the stream is live TV.', 'example': '0 or 1'},
|
{'name': 'Live', 'type': 'int', 'value': 'live', 'description': 'If the stream is live TV.', 'example': '0 or 1'},
|
||||||
|
{'name': 'Channel Call Sign', 'type': 'str', 'value': 'channel_call_sign', 'description': 'The Live TV channel call sign.'},
|
||||||
|
{'name': 'Channel Identifier', 'type': 'str', 'value': 'channel_identifier', 'description': 'The Live TV channel number.'},
|
||||||
|
{'name': 'Channel Thumb', 'type': 'str', 'value': 'channel_thumb', 'description': 'The URL for the Live TV channel logo.'},
|
||||||
{'name': 'Secure', 'type': 'int', 'value': 'secure', 'description': 'If the stream is using a secure connection.', 'example': '0 or 1'},
|
{'name': 'Secure', 'type': 'int', 'value': 'secure', 'description': 'If the stream is using a secure connection.', 'example': '0 or 1'},
|
||||||
{'name': 'Relayed', 'type': 'int', 'value': 'relayed', 'description': 'If the stream is using Plex Relay.', 'example': '0 or 1'},
|
{'name': 'Relayed', 'type': 'int', 'value': 'relayed', 'description': 'If the stream is using Plex Relay.', 'example': '0 or 1'},
|
||||||
{'name': 'Stream Local', 'type': 'int', 'value': 'stream_local', 'description': 'If the stream is local.', 'example': '0 or 1'},
|
{'name': 'Stream Local', 'type': 'int', 'value': 'stream_local', 'description': 'If the stream is local.', 'example': '0 or 1'},
|
||||||
@@ -513,6 +531,7 @@ NOTIFICATION_PARAMETERS = [
|
|||||||
{'name': 'Rating Key', 'type': 'int', 'value': 'rating_key', 'description': 'The unique identifier for the movie, episode, or track.'},
|
{'name': 'Rating Key', 'type': 'int', 'value': 'rating_key', 'description': 'The unique identifier for the movie, episode, or track.'},
|
||||||
{'name': 'Parent Rating Key', 'type': 'int', 'value': 'parent_rating_key', 'description': 'The unique identifier for the season or album.'},
|
{'name': 'Parent Rating Key', 'type': 'int', 'value': 'parent_rating_key', 'description': 'The unique identifier for the season or album.'},
|
||||||
{'name': 'Grandparent Rating Key', 'type': 'int', 'value': 'grandparent_rating_key', 'description': 'The unique identifier for the TV show or artist.'},
|
{'name': 'Grandparent Rating Key', 'type': 'int', 'value': 'grandparent_rating_key', 'description': 'The unique identifier for the TV show or artist.'},
|
||||||
|
{'name': 'Art', 'type': 'str', 'value': 'art', 'description': 'The Plex background art for the media.'},
|
||||||
{'name': 'Thumb', 'type': 'str', 'value': 'thumb', 'description': 'The Plex thumbnail for the movie or episode.'},
|
{'name': 'Thumb', 'type': 'str', 'value': 'thumb', 'description': 'The Plex thumbnail for the movie or episode.'},
|
||||||
{'name': 'Parent Thumb', 'type': 'str', 'value': 'parent_thumb', 'description': 'The Plex thumbnail for the season or album.'},
|
{'name': 'Parent Thumb', 'type': 'str', 'value': 'parent_thumb', 'description': 'The Plex thumbnail for the season or album.'},
|
||||||
{'name': 'Grandparent Thumb', 'type': 'str', 'value': 'grandparent_thumb', 'description': 'The Plex thumbnail for the TV show or artist.'},
|
{'name': 'Grandparent Thumb', 'type': 'str', 'value': 'grandparent_thumb', 'description': 'The Plex thumbnail for the TV show or artist.'},
|
||||||
|
@@ -68,6 +68,7 @@ _CONFIG_DEFINITIONS = {
|
|||||||
'PMS_UPDATE_CHECK_INTERVAL': (int, 'Advanced', 24),
|
'PMS_UPDATE_CHECK_INTERVAL': (int, 'Advanced', 24),
|
||||||
'PMS_WEB_URL': (str, 'PMS', 'https://app.plex.tv/desktop'),
|
'PMS_WEB_URL': (str, 'PMS', 'https://app.plex.tv/desktop'),
|
||||||
'TIME_FORMAT': (str, 'General', 'HH:mm'),
|
'TIME_FORMAT': (str, 'General', 'HH:mm'),
|
||||||
|
'ADD_LIVE_TV_LIBRARY': (int, 'Advanced', 1),
|
||||||
'ANON_REDIRECT': (str, 'General', 'http://www.nullrefer.com/?'),
|
'ANON_REDIRECT': (str, 'General', 'http://www.nullrefer.com/?'),
|
||||||
'API_ENABLED': (int, 'General', 1),
|
'API_ENABLED': (int, 'General', 1),
|
||||||
'API_KEY': (str, 'General', ''),
|
'API_KEY': (str, 'General', ''),
|
||||||
@@ -933,3 +934,9 @@ class Config(object):
|
|||||||
self.GEOIP_DB = os.path.join(plexpy.DATA_DIR, 'GeoLite2-City.mmdb')
|
self.GEOIP_DB = os.path.join(plexpy.DATA_DIR, 'GeoLite2-City.mmdb')
|
||||||
|
|
||||||
self.CONFIG_VERSION = 14
|
self.CONFIG_VERSION = 14
|
||||||
|
|
||||||
|
if self.CONFIG_VERSION == 14:
|
||||||
|
if plexpy.DOCKER:
|
||||||
|
self.PLEXPY_AUTO_UPDATE = 0
|
||||||
|
|
||||||
|
self.CONFIG_VERSION == 15
|
||||||
|
@@ -94,6 +94,10 @@ class DataFactory(object):
|
|||||||
'session_history_metadata.thumb',
|
'session_history_metadata.thumb',
|
||||||
'session_history_metadata.parent_thumb',
|
'session_history_metadata.parent_thumb',
|
||||||
'session_history_metadata.grandparent_thumb',
|
'session_history_metadata.grandparent_thumb',
|
||||||
|
'session_history_metadata.live',
|
||||||
|
'session_history_metadata.added_at',
|
||||||
|
'session_history_metadata.originally_available_at',
|
||||||
|
'session_history_metadata.guid',
|
||||||
'MAX((CASE WHEN (view_offset IS NULL OR view_offset = "") THEN 0.1 ELSE view_offset * 1.0 END) / \
|
'MAX((CASE WHEN (view_offset IS NULL OR view_offset = "") THEN 0.1 ELSE view_offset * 1.0 END) / \
|
||||||
(CASE WHEN (session_history_metadata.duration IS NULL OR session_history_metadata.duration = "") \
|
(CASE WHEN (session_history_metadata.duration IS NULL OR session_history_metadata.duration = "") \
|
||||||
THEN 1.0 ELSE session_history_metadata.duration * 1.0 END) * 100) AS percent_complete',
|
THEN 1.0 ELSE session_history_metadata.duration * 1.0 END) * 100) AS percent_complete',
|
||||||
@@ -142,6 +146,10 @@ class DataFactory(object):
|
|||||||
'thumb',
|
'thumb',
|
||||||
'parent_thumb',
|
'parent_thumb',
|
||||||
'grandparent_thumb',
|
'grandparent_thumb',
|
||||||
|
'live',
|
||||||
|
'added_at',
|
||||||
|
'originally_available_at',
|
||||||
|
'guid',
|
||||||
'MAX((CASE WHEN (view_offset IS NULL OR view_offset = "") THEN 0.1 ELSE view_offset * 1.0 END) / \
|
'MAX((CASE WHEN (view_offset IS NULL OR view_offset = "") THEN 0.1 ELSE view_offset * 1.0 END) / \
|
||||||
(CASE WHEN (duration IS NULL OR duration = "") \
|
(CASE WHEN (duration IS NULL OR duration = "") \
|
||||||
THEN 1.0 ELSE duration * 1.0 END) * 100) AS percent_complete',
|
THEN 1.0 ELSE duration * 1.0 END) * 100) AS percent_complete',
|
||||||
@@ -206,6 +214,9 @@ class DataFactory(object):
|
|||||||
else:
|
else:
|
||||||
thumb = item['thumb']
|
thumb = item['thumb']
|
||||||
|
|
||||||
|
if item['live']:
|
||||||
|
item['percent_complete'] = 100
|
||||||
|
|
||||||
if item['percent_complete'] >= watched_percent[item['media_type']]:
|
if item['percent_complete'] >= watched_percent[item['media_type']]:
|
||||||
watched_status = 1
|
watched_status = 1
|
||||||
elif item['percent_complete'] >= watched_percent[item['media_type']]/2:
|
elif item['percent_complete'] >= watched_percent[item['media_type']]/2:
|
||||||
@@ -230,6 +241,7 @@ class DataFactory(object):
|
|||||||
'product': item['product'],
|
'product': item['product'],
|
||||||
'player': item['player'],
|
'player': item['player'],
|
||||||
'ip_address': item['ip_address'],
|
'ip_address': item['ip_address'],
|
||||||
|
'live': item['live'],
|
||||||
'media_type': item['media_type'],
|
'media_type': item['media_type'],
|
||||||
'rating_key': item['rating_key'],
|
'rating_key': item['rating_key'],
|
||||||
'parent_rating_key': item['parent_rating_key'],
|
'parent_rating_key': item['parent_rating_key'],
|
||||||
@@ -243,6 +255,8 @@ class DataFactory(object):
|
|||||||
'media_index': item['media_index'],
|
'media_index': item['media_index'],
|
||||||
'parent_media_index': item['parent_media_index'],
|
'parent_media_index': item['parent_media_index'],
|
||||||
'thumb': thumb,
|
'thumb': thumb,
|
||||||
|
'originally_available_at': item['originally_available_at'],
|
||||||
|
'guid': item['guid'],
|
||||||
'transcode_decision': item['transcode_decision'],
|
'transcode_decision': item['transcode_decision'],
|
||||||
'percent_complete': int(round(item['percent_complete'])),
|
'percent_complete': int(round(item['percent_complete'])),
|
||||||
'watched_status': watched_status,
|
'watched_status': watched_status,
|
||||||
@@ -286,7 +300,7 @@ class DataFactory(object):
|
|||||||
top_movies = []
|
top_movies = []
|
||||||
try:
|
try:
|
||||||
query = 'SELECT t.id, t.full_title, t.rating_key, t.thumb, t.section_id, ' \
|
query = 'SELECT t.id, t.full_title, t.rating_key, t.thumb, t.section_id, ' \
|
||||||
't.art, t.media_type, t.content_rating, t.labels, t.started, ' \
|
't.art, t.media_type, t.content_rating, t.labels, t.started, t.live, t.guid, ' \
|
||||||
'MAX(t.started) AS last_watch, COUNT(t.id) AS total_plays, SUM(t.d) AS total_duration ' \
|
'MAX(t.started) AS last_watch, COUNT(t.id) AS total_plays, SUM(t.d) AS total_duration ' \
|
||||||
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
||||||
' (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) ' \
|
' (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) ' \
|
||||||
@@ -323,6 +337,8 @@ class DataFactory(object):
|
|||||||
'friendly_name': '',
|
'friendly_name': '',
|
||||||
'platform': '',
|
'platform': '',
|
||||||
'platform': '',
|
'platform': '',
|
||||||
|
'live': item['live'],
|
||||||
|
'guid': item['guid'],
|
||||||
'row_id': item['id']
|
'row_id': item['id']
|
||||||
}
|
}
|
||||||
top_movies.append(row)
|
top_movies.append(row)
|
||||||
@@ -336,7 +352,7 @@ class DataFactory(object):
|
|||||||
popular_movies = []
|
popular_movies = []
|
||||||
try:
|
try:
|
||||||
query = 'SELECT t.id, t.full_title, t.rating_key, t.thumb, t.section_id, ' \
|
query = 'SELECT t.id, t.full_title, t.rating_key, t.thumb, t.section_id, ' \
|
||||||
't.art, t.media_type, t.content_rating, t.labels, t.started, ' \
|
't.art, t.media_type, t.content_rating, t.labels, t.started, t.live, t.guid, ' \
|
||||||
'COUNT(DISTINCT t.user_id) AS users_watched, ' \
|
'COUNT(DISTINCT t.user_id) AS users_watched, ' \
|
||||||
'MAX(t.started) AS last_watch, COUNT(t.id) as total_plays, SUM(t.d) AS total_duration ' \
|
'MAX(t.started) AS last_watch, COUNT(t.id) as total_plays, SUM(t.d) AS total_duration ' \
|
||||||
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
||||||
@@ -372,6 +388,8 @@ class DataFactory(object):
|
|||||||
'user': '',
|
'user': '',
|
||||||
'friendly_name': '',
|
'friendly_name': '',
|
||||||
'platform': '',
|
'platform': '',
|
||||||
|
'live': item['live'],
|
||||||
|
'guid': item['guid'],
|
||||||
'row_id': item['id']
|
'row_id': item['id']
|
||||||
}
|
}
|
||||||
popular_movies.append(row)
|
popular_movies.append(row)
|
||||||
@@ -384,7 +402,7 @@ class DataFactory(object):
|
|||||||
top_tv = []
|
top_tv = []
|
||||||
try:
|
try:
|
||||||
query = 'SELECT t.id, t.grandparent_title, t.grandparent_rating_key, t.grandparent_thumb, t.section_id, ' \
|
query = 'SELECT t.id, t.grandparent_title, t.grandparent_rating_key, t.grandparent_thumb, t.section_id, ' \
|
||||||
't.art, t.media_type, t.content_rating, t.labels, t.started, ' \
|
't.rating_key, t.art, t.media_type, t.content_rating, t.labels, t.started, t.live, t.guid, ' \
|
||||||
'MAX(t.started) AS last_watch, COUNT(t.id) AS total_plays, SUM(t.d) AS total_duration ' \
|
'MAX(t.started) AS last_watch, COUNT(t.id) AS total_plays, SUM(t.d) AS total_duration ' \
|
||||||
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
||||||
' (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) ' \
|
' (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) ' \
|
||||||
@@ -408,7 +426,7 @@ class DataFactory(object):
|
|||||||
'total_plays': item['total_plays'],
|
'total_plays': item['total_plays'],
|
||||||
'total_duration': item['total_duration'],
|
'total_duration': item['total_duration'],
|
||||||
'users_watched': '',
|
'users_watched': '',
|
||||||
'rating_key': item['grandparent_rating_key'],
|
'rating_key': item['rating_key'] if item['live'] else item['grandparent_rating_key'],
|
||||||
'last_play': item['last_watch'],
|
'last_play': item['last_watch'],
|
||||||
'grandparent_thumb': item['grandparent_thumb'],
|
'grandparent_thumb': item['grandparent_thumb'],
|
||||||
'thumb': item['grandparent_thumb'],
|
'thumb': item['grandparent_thumb'],
|
||||||
@@ -420,6 +438,8 @@ class DataFactory(object):
|
|||||||
'user': '',
|
'user': '',
|
||||||
'friendly_name': '',
|
'friendly_name': '',
|
||||||
'platform': '',
|
'platform': '',
|
||||||
|
'live': item['live'],
|
||||||
|
'guid': item['guid'],
|
||||||
'row_id': item['id']
|
'row_id': item['id']
|
||||||
}
|
}
|
||||||
top_tv.append(row)
|
top_tv.append(row)
|
||||||
@@ -433,7 +453,7 @@ class DataFactory(object):
|
|||||||
popular_tv = []
|
popular_tv = []
|
||||||
try:
|
try:
|
||||||
query = 'SELECT t.id, t.grandparent_title, t.grandparent_rating_key, t.grandparent_thumb, t.section_id, ' \
|
query = 'SELECT t.id, t.grandparent_title, t.grandparent_rating_key, t.grandparent_thumb, t.section_id, ' \
|
||||||
't.art, t.media_type, t.content_rating, t.labels, t.started, ' \
|
't.rating_key, t.art, t.media_type, t.content_rating, t.labels, t.started, t.live, t.guid, ' \
|
||||||
'COUNT(DISTINCT t.user_id) AS users_watched, ' \
|
'COUNT(DISTINCT t.user_id) AS users_watched, ' \
|
||||||
'MAX(t.started) AS last_watch, COUNT(t.id) as total_plays, SUM(t.d) AS total_duration ' \
|
'MAX(t.started) AS last_watch, COUNT(t.id) as total_plays, SUM(t.d) AS total_duration ' \
|
||||||
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
||||||
@@ -456,7 +476,7 @@ class DataFactory(object):
|
|||||||
for item in result:
|
for item in result:
|
||||||
row = {'title': item['grandparent_title'],
|
row = {'title': item['grandparent_title'],
|
||||||
'users_watched': item['users_watched'],
|
'users_watched': item['users_watched'],
|
||||||
'rating_key': item['grandparent_rating_key'],
|
'rating_key': item['rating_key'] if item['live'] else item['grandparent_rating_key'],
|
||||||
'last_play': item['last_watch'],
|
'last_play': item['last_watch'],
|
||||||
'total_plays': item['total_plays'],
|
'total_plays': item['total_plays'],
|
||||||
'grandparent_thumb': item['grandparent_thumb'],
|
'grandparent_thumb': item['grandparent_thumb'],
|
||||||
@@ -469,6 +489,8 @@ class DataFactory(object):
|
|||||||
'user': '',
|
'user': '',
|
||||||
'friendly_name': '',
|
'friendly_name': '',
|
||||||
'platform': '',
|
'platform': '',
|
||||||
|
'live': item['live'],
|
||||||
|
'guid': item['guid'],
|
||||||
'row_id': item['id']
|
'row_id': item['id']
|
||||||
}
|
}
|
||||||
popular_tv.append(row)
|
popular_tv.append(row)
|
||||||
@@ -482,7 +504,7 @@ class DataFactory(object):
|
|||||||
try:
|
try:
|
||||||
query = 'SELECT t.id, t.grandparent_title, t.original_title, ' \
|
query = 'SELECT t.id, t.grandparent_title, t.original_title, ' \
|
||||||
't.grandparent_rating_key, t.grandparent_thumb, t.section_id, ' \
|
't.grandparent_rating_key, t.grandparent_thumb, t.section_id, ' \
|
||||||
't.art, t.media_type, t.content_rating, t.labels, t.started, ' \
|
't.art, t.media_type, t.content_rating, t.labels, t.started, t.live, t.guid, ' \
|
||||||
'MAX(t.started) AS last_watch, COUNT(t.id) AS total_plays, SUM(t.d) AS total_duration ' \
|
'MAX(t.started) AS last_watch, COUNT(t.id) AS total_plays, SUM(t.d) AS total_duration ' \
|
||||||
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
||||||
' (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) ' \
|
' (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) ' \
|
||||||
@@ -518,6 +540,8 @@ class DataFactory(object):
|
|||||||
'user': '',
|
'user': '',
|
||||||
'friendly_name': '',
|
'friendly_name': '',
|
||||||
'platform': '',
|
'platform': '',
|
||||||
|
'live': item['live'],
|
||||||
|
'guid': item['guid'],
|
||||||
'row_id': item['id']
|
'row_id': item['id']
|
||||||
}
|
}
|
||||||
top_music.append(row)
|
top_music.append(row)
|
||||||
@@ -532,7 +556,7 @@ class DataFactory(object):
|
|||||||
try:
|
try:
|
||||||
query = 'SELECT t.id, t.grandparent_title, t.original_title, ' \
|
query = 'SELECT t.id, t.grandparent_title, t.original_title, ' \
|
||||||
't.grandparent_rating_key, t.grandparent_thumb, t.section_id, ' \
|
't.grandparent_rating_key, t.grandparent_thumb, t.section_id, ' \
|
||||||
't.art, t.media_type, t.content_rating, t.labels, t.started, ' \
|
't.art, t.media_type, t.content_rating, t.labels, t.started, t.live, t.guid, ' \
|
||||||
'COUNT(DISTINCT t.user_id) AS users_watched, ' \
|
'COUNT(DISTINCT t.user_id) AS users_watched, ' \
|
||||||
'MAX(t.started) AS last_watch, COUNT(t.id) as total_plays, SUM(t.d) AS total_duration ' \
|
'MAX(t.started) AS last_watch, COUNT(t.id) as total_plays, SUM(t.d) AS total_duration ' \
|
||||||
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
||||||
@@ -568,6 +592,8 @@ class DataFactory(object):
|
|||||||
'user': '',
|
'user': '',
|
||||||
'friendly_name': '',
|
'friendly_name': '',
|
||||||
'platform': '',
|
'platform': '',
|
||||||
|
'live': item['live'],
|
||||||
|
'guid': item['guid'],
|
||||||
'row_id': item['id']
|
'row_id': item['id']
|
||||||
}
|
}
|
||||||
popular_music.append(row)
|
popular_music.append(row)
|
||||||
@@ -684,7 +710,7 @@ class DataFactory(object):
|
|||||||
try:
|
try:
|
||||||
query = 'SELECT t.id, t.full_title, t.rating_key, t.thumb, t.grandparent_thumb, ' \
|
query = 'SELECT t.id, t.full_title, t.rating_key, t.thumb, t.grandparent_thumb, ' \
|
||||||
't.user, t.user_id, t.custom_avatar_url as user_thumb, t.player, t.section_id, ' \
|
't.user, t.user_id, t.custom_avatar_url as user_thumb, t.player, t.section_id, ' \
|
||||||
't.art, t.media_type, t.content_rating, t.labels, ' \
|
't.art, t.media_type, t.content_rating, t.labels, t.live, t.guid, ' \
|
||||||
'(CASE WHEN t.friendly_name IS NULL THEN t.username ELSE t.friendly_name END) ' \
|
'(CASE WHEN t.friendly_name IS NULL THEN t.username ELSE t.friendly_name END) ' \
|
||||||
' AS friendly_name, ' \
|
' AS friendly_name, ' \
|
||||||
'MAX(t.started) AS last_watch, ' \
|
'MAX(t.started) AS last_watch, ' \
|
||||||
@@ -730,6 +756,8 @@ class DataFactory(object):
|
|||||||
'content_rating': item['content_rating'],
|
'content_rating': item['content_rating'],
|
||||||
'labels': item['labels'].split(';') if item['labels'] else (),
|
'labels': item['labels'].split(';') if item['labels'] else (),
|
||||||
'last_watch': item['last_watch'],
|
'last_watch': item['last_watch'],
|
||||||
|
'live': item['live'],
|
||||||
|
'guid': item['guid'],
|
||||||
'player': item['player']
|
'player': item['player']
|
||||||
}
|
}
|
||||||
last_watched.append(row)
|
last_watched.append(row)
|
||||||
@@ -834,7 +862,8 @@ class DataFactory(object):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
query = 'SELECT section_id, section_name, section_type, thumb AS library_thumb, ' \
|
query = 'SELECT section_id, section_name, section_type, thumb AS library_thumb, ' \
|
||||||
'custom_thumb_url AS custom_thumb, art, count, parent_count, child_count ' \
|
'custom_thumb_url AS custom_thumb, art AS library_art, custom_art_url AS custom_art, ' \
|
||||||
|
'count, parent_count, child_count ' \
|
||||||
'FROM library_sections ' \
|
'FROM library_sections ' \
|
||||||
'WHERE section_id IN (%s) ' \
|
'WHERE section_id IN (%s) ' \
|
||||||
'ORDER BY section_type, count DESC, parent_count DESC, child_count DESC ' % ','.join(library_cards)
|
'ORDER BY section_type, count DESC, parent_count DESC, child_count DESC ' % ','.join(library_cards)
|
||||||
@@ -851,11 +880,16 @@ class DataFactory(object):
|
|||||||
else:
|
else:
|
||||||
library_thumb = common.DEFAULT_COVER_THUMB
|
library_thumb = common.DEFAULT_COVER_THUMB
|
||||||
|
|
||||||
|
if item['custom_art'] and item['custom_art'] != item['library_art']:
|
||||||
|
library_art = item['custom_art']
|
||||||
|
else:
|
||||||
|
library_art = item['library_art']
|
||||||
|
|
||||||
library = {'section_id': item['section_id'],
|
library = {'section_id': item['section_id'],
|
||||||
'section_name': item['section_name'],
|
'section_name': item['section_name'],
|
||||||
'section_type': item['section_type'],
|
'section_type': item['section_type'],
|
||||||
'thumb': library_thumb,
|
'thumb': library_thumb,
|
||||||
'art': item['art'],
|
'art': library_art,
|
||||||
'count': item['count'],
|
'count': item['count'],
|
||||||
'child_count': item['parent_count'],
|
'child_count': item['parent_count'],
|
||||||
'grandchild_count': item['child_count']
|
'grandchild_count': item['child_count']
|
||||||
@@ -992,10 +1026,17 @@ class DataFactory(object):
|
|||||||
stream_output = {k: v or '' for k, v in stream_output.iteritems()}
|
stream_output = {k: v or '' for k, v in stream_output.iteritems()}
|
||||||
return stream_output
|
return stream_output
|
||||||
|
|
||||||
def get_metadata_details(self, rating_key):
|
def get_metadata_details(self, rating_key='', guid=''):
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
if rating_key:
|
if rating_key or guid:
|
||||||
|
if guid:
|
||||||
|
where = 'session_history_metadata.guid LIKE ?'
|
||||||
|
args = [guid.split('?')[0] + '%'] # SQLite LIKE wildcard
|
||||||
|
else:
|
||||||
|
where = 'session_history_metadata.rating_key = ?'
|
||||||
|
args = [rating_key]
|
||||||
|
|
||||||
query = 'SELECT session_history_metadata.id, ' \
|
query = 'SELECT session_history_metadata.id, ' \
|
||||||
'session_history_metadata.rating_key, session_history_metadata.parent_rating_key, ' \
|
'session_history_metadata.rating_key, session_history_metadata.parent_rating_key, ' \
|
||||||
'session_history_metadata.grandparent_rating_key, session_history_metadata.title, ' \
|
'session_history_metadata.grandparent_rating_key, session_history_metadata.title, ' \
|
||||||
@@ -1015,15 +1056,18 @@ class DataFactory(object):
|
|||||||
'session_history_metadata.labels, ' \
|
'session_history_metadata.labels, ' \
|
||||||
'session_history_media_info.container, session_history_media_info.bitrate, ' \
|
'session_history_media_info.container, session_history_media_info.bitrate, ' \
|
||||||
'session_history_media_info.video_codec, session_history_media_info.video_resolution, ' \
|
'session_history_media_info.video_codec, session_history_media_info.video_resolution, ' \
|
||||||
|
'session_history_media_info.video_full_resolution, ' \
|
||||||
'session_history_media_info.video_framerate, session_history_media_info.audio_codec, ' \
|
'session_history_media_info.video_framerate, session_history_media_info.audio_codec, ' \
|
||||||
'session_history_media_info.audio_channels ' \
|
'session_history_media_info.audio_channels, session_history_metadata.live, ' \
|
||||||
|
'session_history_metadata.channel_call_sign, session_history_metadata.channel_identifier, ' \
|
||||||
|
'session_history_metadata.channel_thumb ' \
|
||||||
'FROM session_history_metadata ' \
|
'FROM session_history_metadata ' \
|
||||||
'JOIN library_sections ON session_history_metadata.section_id = library_sections.section_id ' \
|
'JOIN library_sections ON session_history_metadata.section_id = library_sections.section_id ' \
|
||||||
'JOIN session_history_media_info ON session_history_metadata.id = session_history_media_info.id ' \
|
'JOIN session_history_media_info ON session_history_metadata.id = session_history_media_info.id ' \
|
||||||
'WHERE session_history_metadata.rating_key = ? ' \
|
'WHERE %s ' \
|
||||||
'ORDER BY session_history_metadata.id DESC ' \
|
'ORDER BY session_history_metadata.id DESC ' \
|
||||||
'LIMIT 1'
|
'LIMIT 1' % where
|
||||||
result = monitor_db.select(query=query, args=[rating_key])
|
result = monitor_db.select(query=query, args=args)
|
||||||
else:
|
else:
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
@@ -1040,9 +1084,13 @@ class DataFactory(object):
|
|||||||
'bitrate': item['bitrate'],
|
'bitrate': item['bitrate'],
|
||||||
'video_codec': item['video_codec'],
|
'video_codec': item['video_codec'],
|
||||||
'video_resolution': item['video_resolution'],
|
'video_resolution': item['video_resolution'],
|
||||||
|
'video_full_resolution': item['video_full_resolution'],
|
||||||
'video_framerate': item['video_framerate'],
|
'video_framerate': item['video_framerate'],
|
||||||
'audio_codec': item['audio_codec'],
|
'audio_codec': item['audio_codec'],
|
||||||
'audio_channels': item['audio_channels']
|
'audio_channels': item['audio_channels'],
|
||||||
|
'channel_call_sign': item['channel_call_sign'],
|
||||||
|
'channel_identifier': item['channel_identifier'],
|
||||||
|
'channel_thumb': item['channel_thumb']
|
||||||
}]
|
}]
|
||||||
|
|
||||||
metadata = {'media_type': item['media_type'],
|
metadata = {'media_type': item['media_type'],
|
||||||
@@ -1056,6 +1104,7 @@ class DataFactory(object):
|
|||||||
'media_index': item['media_index'],
|
'media_index': item['media_index'],
|
||||||
'studio': item['studio'],
|
'studio': item['studio'],
|
||||||
'title': item['title'],
|
'title': item['title'],
|
||||||
|
'full_title': item['full_title'],
|
||||||
'content_rating': item['content_rating'],
|
'content_rating': item['content_rating'],
|
||||||
'summary': item['summary'],
|
'summary': item['summary'],
|
||||||
'tagline': item['tagline'],
|
'tagline': item['tagline'],
|
||||||
@@ -1078,6 +1127,7 @@ class DataFactory(object):
|
|||||||
'labels': labels,
|
'labels': labels,
|
||||||
'library_name': item['section_name'],
|
'library_name': item['section_name'],
|
||||||
'section_id': item['section_id'],
|
'section_id': item['section_id'],
|
||||||
|
'live': item['live'],
|
||||||
'media_info': media_info
|
'media_info': media_info
|
||||||
}
|
}
|
||||||
metadata_list.append(metadata)
|
metadata_list.append(metadata)
|
||||||
|
@@ -142,6 +142,9 @@ class DataTables(object):
|
|||||||
for w_ in w[1]:
|
for w_ in w[1]:
|
||||||
if w_ == None:
|
if w_ == None:
|
||||||
c_where += w[0] + ' IS NULL OR '
|
c_where += w[0] + ' IS NULL OR '
|
||||||
|
elif str(w_).startswith('LIKE '):
|
||||||
|
c_where += w[0] + ' LIKE ? OR '
|
||||||
|
args.append(w_[5:])
|
||||||
else:
|
else:
|
||||||
c_where += w[0] + ' = ? OR '
|
c_where += w[0] + ' = ? OR '
|
||||||
args.append(w_)
|
args.append(w_)
|
||||||
@@ -149,6 +152,9 @@ class DataTables(object):
|
|||||||
else:
|
else:
|
||||||
if w[1] == None:
|
if w[1] == None:
|
||||||
c_where += w[0] + ' IS NULL AND '
|
c_where += w[0] + ' IS NULL AND '
|
||||||
|
elif str(w[1]).startswith('LIKE '):
|
||||||
|
c_where += w[0] + ' LIKE ? AND '
|
||||||
|
args.append(w[1][5:])
|
||||||
else:
|
else:
|
||||||
c_where += w[0] + ' = ? AND '
|
c_where += w[0] + ' = ? AND '
|
||||||
args.append(w[1])
|
args.append(w[1])
|
||||||
|
277
plexpy/graphs.py
277
plexpy/graphs.py
@@ -18,6 +18,7 @@ import datetime
|
|||||||
import plexpy
|
import plexpy
|
||||||
import common
|
import common
|
||||||
import database
|
import database
|
||||||
|
import libraries
|
||||||
import logger
|
import logger
|
||||||
import session
|
import session
|
||||||
|
|
||||||
@@ -42,15 +43,17 @@ class Graphs(object):
|
|||||||
if grouping is None:
|
if grouping is None:
|
||||||
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
||||||
|
|
||||||
group_by = 'reference_id' if grouping else 'id'
|
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if y_axis == 'plays':
|
if y_axis == 'plays':
|
||||||
query = 'SELECT date(started, "unixepoch", "localtime") AS date_played, ' \
|
query = 'SELECT date(started, "unixepoch", "localtime") AS date_played, ' \
|
||||||
'SUM(CASE WHEN media_type = "episode" THEN 1 ELSE 0 END) AS tv_count, ' \
|
'SUM(CASE WHEN media_type = "episode" AND live = 0 THEN 1 ELSE 0 END) AS tv_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "movie" THEN 1 ELSE 0 END) AS movie_count, ' \
|
'SUM(CASE WHEN media_type = "movie" AND live = 0 THEN 1 ELSE 0 END) AS movie_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "track" THEN 1 ELSE 0 END) AS music_count ' \
|
'SUM(CASE WHEN media_type = "track" AND live = 0 THEN 1 ELSE 0 END) AS music_count, ' \
|
||||||
|
'SUM(live) AS live_count ' \
|
||||||
'FROM (SELECT * FROM session_history ' \
|
'FROM (SELECT * FROM session_history ' \
|
||||||
|
'JOIN session_history_metadata ON session_history.id = session_history_metadata.id ' \
|
||||||
'GROUP BY date(started, "unixepoch", "localtime"), %s) ' \
|
'GROUP BY date(started, "unixepoch", "localtime"), %s) ' \
|
||||||
'AS session_history ' \
|
'AS session_history ' \
|
||||||
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") %s' \
|
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") %s' \
|
||||||
@@ -60,13 +63,17 @@ class Graphs(object):
|
|||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
else:
|
else:
|
||||||
query = 'SELECT date(started, "unixepoch", "localtime") AS date_played, ' \
|
query = 'SELECT date(started, "unixepoch", "localtime") AS date_played, ' \
|
||||||
'SUM(CASE WHEN media_type = "episode" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "episode" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tv_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tv_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "movie" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "movie" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS movie_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS movie_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "track" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "track" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS music_count ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS music_count, ' \
|
||||||
'FROM session_history ' \
|
'SUM(CASE WHEN live = 1 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS live_count ' \
|
||||||
|
'FROM (SELECT * FROM session_history ' \
|
||||||
|
'JOIN session_history_metadata ON session_history.id = session_history_metadata.id) ' \
|
||||||
|
'AS session_history ' \
|
||||||
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") %s' \
|
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") %s' \
|
||||||
'GROUP BY date_played ' \
|
'GROUP BY date_played ' \
|
||||||
'ORDER BY started ASC' % (time_range, user_cond)
|
'ORDER BY started ASC' % (time_range, user_cond)
|
||||||
@@ -85,6 +92,7 @@ class Graphs(object):
|
|||||||
series_1 = []
|
series_1 = []
|
||||||
series_2 = []
|
series_2 = []
|
||||||
series_3 = []
|
series_3 = []
|
||||||
|
series_4 = []
|
||||||
|
|
||||||
for date_item in sorted(date_list):
|
for date_item in sorted(date_list):
|
||||||
date_string = date_item.strftime('%Y-%m-%d')
|
date_string = date_item.strftime('%Y-%m-%d')
|
||||||
@@ -92,20 +100,24 @@ class Graphs(object):
|
|||||||
series_1_value = 0
|
series_1_value = 0
|
||||||
series_2_value = 0
|
series_2_value = 0
|
||||||
series_3_value = 0
|
series_3_value = 0
|
||||||
|
series_4_value = 0
|
||||||
for item in result:
|
for item in result:
|
||||||
if date_string == item['date_played']:
|
if date_string == item['date_played']:
|
||||||
series_1_value = item['tv_count']
|
series_1_value = item['tv_count']
|
||||||
series_2_value = item['movie_count']
|
series_2_value = item['movie_count']
|
||||||
series_3_value = item['music_count']
|
series_3_value = item['music_count']
|
||||||
|
series_4_value = item['live_count']
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
series_1_value = 0
|
series_1_value = 0
|
||||||
series_2_value = 0
|
series_2_value = 0
|
||||||
series_3_value = 0
|
series_3_value = 0
|
||||||
|
series_4_value = 0
|
||||||
|
|
||||||
series_1.append(series_1_value)
|
series_1.append(series_1_value)
|
||||||
series_2.append(series_2_value)
|
series_2.append(series_2_value)
|
||||||
series_3.append(series_3_value)
|
series_3.append(series_3_value)
|
||||||
|
series_4.append(series_4_value)
|
||||||
|
|
||||||
series_1_output = {'name': 'TV',
|
series_1_output = {'name': 'TV',
|
||||||
'data': series_1}
|
'data': series_1}
|
||||||
@@ -113,9 +125,21 @@ class Graphs(object):
|
|||||||
'data': series_2}
|
'data': series_2}
|
||||||
series_3_output = {'name': 'Music',
|
series_3_output = {'name': 'Music',
|
||||||
'data': series_3}
|
'data': series_3}
|
||||||
|
series_4_output = {'name': 'Live TV',
|
||||||
|
'data': series_4}
|
||||||
|
|
||||||
|
series_output = []
|
||||||
|
if libraries.has_library_type('show'):
|
||||||
|
series_output.append(series_1_output)
|
||||||
|
if libraries.has_library_type('movie'):
|
||||||
|
series_output.append(series_2_output)
|
||||||
|
if libraries.has_library_type('artist'):
|
||||||
|
series_output.append(series_3_output)
|
||||||
|
if libraries.has_library_type('live'):
|
||||||
|
series_output.append(series_4_output)
|
||||||
|
|
||||||
output = {'categories': categories,
|
output = {'categories': categories,
|
||||||
'series': [series_1_output, series_2_output, series_3_output]}
|
'series': series_output}
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def get_total_plays_per_dayofweek(self, time_range='30', y_axis='plays', user_id=None, grouping=None):
|
def get_total_plays_per_dayofweek(self, time_range='30', y_axis='plays', user_id=None, grouping=None):
|
||||||
@@ -133,7 +157,7 @@ class Graphs(object):
|
|||||||
if grouping is None:
|
if grouping is None:
|
||||||
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
||||||
|
|
||||||
group_by = 'reference_id' if grouping else 'id'
|
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if y_axis == 'plays':
|
if y_axis == 'plays':
|
||||||
@@ -146,10 +170,12 @@ class Graphs(object):
|
|||||||
'WHEN 4 THEN "Thursday" ' \
|
'WHEN 4 THEN "Thursday" ' \
|
||||||
'WHEN 5 THEN "Friday" ' \
|
'WHEN 5 THEN "Friday" ' \
|
||||||
'ELSE "Saturday" END) AS dayofweek, ' \
|
'ELSE "Saturday" END) AS dayofweek, ' \
|
||||||
'SUM(CASE WHEN media_type = "episode" THEN 1 ELSE 0 END) AS tv_count, ' \
|
'SUM(CASE WHEN media_type = "episode" AND live = 0 THEN 1 ELSE 0 END) AS tv_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "movie" THEN 1 ELSE 0 END) AS movie_count, ' \
|
'SUM(CASE WHEN media_type = "movie" AND live = 0 THEN 1 ELSE 0 END) AS movie_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "track" THEN 1 ELSE 0 END) AS music_count ' \
|
'SUM(CASE WHEN media_type = "track" AND live = 0 THEN 1 ELSE 0 END) AS music_count, ' \
|
||||||
|
'SUM(live) AS live_count ' \
|
||||||
'FROM (SELECT * FROM session_history ' \
|
'FROM (SELECT * FROM session_history ' \
|
||||||
|
'JOIN session_history_metadata ON session_history.id = session_history_metadata.id ' \
|
||||||
'GROUP BY strftime("%%w", datetime(started, "unixepoch", "localtime")), %s) ' \
|
'GROUP BY strftime("%%w", datetime(started, "unixepoch", "localtime")), %s) ' \
|
||||||
'AS session_history ' \
|
'AS session_history ' \
|
||||||
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") %s' \
|
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") %s' \
|
||||||
@@ -167,13 +193,17 @@ class Graphs(object):
|
|||||||
'WHEN 4 THEN "Thursday" ' \
|
'WHEN 4 THEN "Thursday" ' \
|
||||||
'WHEN 5 THEN "Friday" ' \
|
'WHEN 5 THEN "Friday" ' \
|
||||||
'ELSE "Saturday" END) AS dayofweek, ' \
|
'ELSE "Saturday" END) AS dayofweek, ' \
|
||||||
'SUM(CASE WHEN media_type = "episode" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "episode" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tv_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tv_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "movie" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "movie" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS movie_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS movie_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "track" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "track" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS music_count ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS music_count, ' \
|
||||||
'FROM session_history ' \
|
'SUM(CASE WHEN live = 1 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS live_count ' \
|
||||||
|
'FROM (SELECT * FROM session_history ' \
|
||||||
|
'JOIN session_history_metadata ON session_history.id = session_history_metadata.id) ' \
|
||||||
|
'AS session_history ' \
|
||||||
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") %s' \
|
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") %s' \
|
||||||
'GROUP BY dayofweek ' \
|
'GROUP BY dayofweek ' \
|
||||||
'ORDER BY daynumber' % (time_range, user_cond)
|
'ORDER BY daynumber' % (time_range, user_cond)
|
||||||
@@ -194,26 +224,31 @@ class Graphs(object):
|
|||||||
series_1 = []
|
series_1 = []
|
||||||
series_2 = []
|
series_2 = []
|
||||||
series_3 = []
|
series_3 = []
|
||||||
|
series_4 = []
|
||||||
|
|
||||||
for day_item in days_list:
|
for day_item in days_list:
|
||||||
categories.append(day_item)
|
categories.append(day_item)
|
||||||
series_1_value = 0
|
series_1_value = 0
|
||||||
series_2_value = 0
|
series_2_value = 0
|
||||||
series_3_value = 0
|
series_3_value = 0
|
||||||
|
series_4_value = 0
|
||||||
for item in result:
|
for item in result:
|
||||||
if day_item == item['dayofweek']:
|
if day_item == item['dayofweek']:
|
||||||
series_1_value = item['tv_count']
|
series_1_value = item['tv_count']
|
||||||
series_2_value = item['movie_count']
|
series_2_value = item['movie_count']
|
||||||
series_3_value = item['music_count']
|
series_3_value = item['music_count']
|
||||||
|
series_4_value = item['live_count']
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
series_1_value = 0
|
series_1_value = 0
|
||||||
series_2_value = 0
|
series_2_value = 0
|
||||||
series_3_value = 0
|
series_3_value = 0
|
||||||
|
series_4_value = 0
|
||||||
|
|
||||||
series_1.append(series_1_value)
|
series_1.append(series_1_value)
|
||||||
series_2.append(series_2_value)
|
series_2.append(series_2_value)
|
||||||
series_3.append(series_3_value)
|
series_3.append(series_3_value)
|
||||||
|
series_4.append(series_4_value)
|
||||||
|
|
||||||
series_1_output = {'name': 'TV',
|
series_1_output = {'name': 'TV',
|
||||||
'data': series_1}
|
'data': series_1}
|
||||||
@@ -221,9 +256,21 @@ class Graphs(object):
|
|||||||
'data': series_2}
|
'data': series_2}
|
||||||
series_3_output = {'name': 'Music',
|
series_3_output = {'name': 'Music',
|
||||||
'data': series_3}
|
'data': series_3}
|
||||||
|
series_4_output = {'name': 'Live TV',
|
||||||
|
'data': series_4}
|
||||||
|
|
||||||
|
series_output = []
|
||||||
|
if libraries.has_library_type('show'):
|
||||||
|
series_output.append(series_1_output)
|
||||||
|
if libraries.has_library_type('movie'):
|
||||||
|
series_output.append(series_2_output)
|
||||||
|
if libraries.has_library_type('artist'):
|
||||||
|
series_output.append(series_3_output)
|
||||||
|
if libraries.has_library_type('live'):
|
||||||
|
series_output.append(series_4_output)
|
||||||
|
|
||||||
output = {'categories': categories,
|
output = {'categories': categories,
|
||||||
'series': [series_1_output, series_2_output, series_3_output]}
|
'series': series_output}
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def get_total_plays_per_hourofday(self, time_range='30', y_axis='plays', user_id=None, grouping=None):
|
def get_total_plays_per_hourofday(self, time_range='30', y_axis='plays', user_id=None, grouping=None):
|
||||||
@@ -241,15 +288,17 @@ class Graphs(object):
|
|||||||
if grouping is None:
|
if grouping is None:
|
||||||
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
||||||
|
|
||||||
group_by = 'reference_id' if grouping else 'id'
|
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if y_axis == 'plays':
|
if y_axis == 'plays':
|
||||||
query = 'SELECT strftime("%%H", datetime(started, "unixepoch", "localtime")) AS hourofday, ' \
|
query = 'SELECT strftime("%%H", datetime(started, "unixepoch", "localtime")) AS hourofday, ' \
|
||||||
'SUM(CASE WHEN media_type = "episode" THEN 1 ELSE 0 END) AS tv_count, ' \
|
'SUM(CASE WHEN media_type = "episode" AND live = 0 THEN 1 ELSE 0 END) AS tv_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "movie" THEN 1 ELSE 0 END) AS movie_count, ' \
|
'SUM(CASE WHEN media_type = "movie" AND live = 0 THEN 1 ELSE 0 END) AS movie_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "track" THEN 1 ELSE 0 END) AS music_count ' \
|
'SUM(CASE WHEN media_type = "track" AND live = 0 THEN 1 ELSE 0 END) AS music_count, ' \
|
||||||
|
'SUM(live) AS live_count ' \
|
||||||
'FROM (SELECT * FROM session_history ' \
|
'FROM (SELECT * FROM session_history ' \
|
||||||
|
'JOIN session_history_metadata ON session_history.id = session_history_metadata.id ' \
|
||||||
'GROUP BY strftime("%%H", datetime(started, "unixepoch", "localtime")) , %s) ' \
|
'GROUP BY strftime("%%H", datetime(started, "unixepoch", "localtime")) , %s) ' \
|
||||||
'AS session_history ' \
|
'AS session_history ' \
|
||||||
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") %s' \
|
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") %s' \
|
||||||
@@ -259,13 +308,17 @@ class Graphs(object):
|
|||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
else:
|
else:
|
||||||
query = 'SELECT strftime("%%H", datetime(started, "unixepoch", "localtime")) AS hourofday, ' \
|
query = 'SELECT strftime("%%H", datetime(started, "unixepoch", "localtime")) AS hourofday, ' \
|
||||||
'SUM(CASE WHEN media_type = "episode" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "episode" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tv_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tv_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "movie" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "movie" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS movie_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS movie_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "track" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "track" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS music_count ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS music_count, ' \
|
||||||
'FROM session_history ' \
|
'SUM(CASE WHEN live = 1 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS live_count ' \
|
||||||
|
'FROM (SELECT * FROM session_history ' \
|
||||||
|
'JOIN session_history_metadata ON session_history.id = session_history_metadata.id) ' \
|
||||||
|
'AS session_history ' \
|
||||||
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") %s' \
|
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") %s' \
|
||||||
'GROUP BY hourofday ' \
|
'GROUP BY hourofday ' \
|
||||||
'ORDER BY hourofday' % (time_range, user_cond)
|
'ORDER BY hourofday' % (time_range, user_cond)
|
||||||
@@ -275,35 +328,40 @@ class Graphs(object):
|
|||||||
logger.warn(u"Tautulli Graphs :: Unable to execute database query for get_total_plays_per_hourofday: %s." % e)
|
logger.warn(u"Tautulli Graphs :: Unable to execute database query for get_total_plays_per_hourofday: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
hours_list = ['00','01','02','03','04','05',
|
hours_list = ['00', '01', '02', '03', '04', '05',
|
||||||
'06','07','08','09','10','11',
|
'06', '07', '08', '09', '10', '11',
|
||||||
'12','13','14','15','16','17',
|
'12', '13', '14', '15', '16', '17',
|
||||||
'18','19','20','21','22','23']
|
'18', '19', '20', '21', '22', '23']
|
||||||
|
|
||||||
categories = []
|
categories = []
|
||||||
series_1 = []
|
series_1 = []
|
||||||
series_2 = []
|
series_2 = []
|
||||||
series_3 = []
|
series_3 = []
|
||||||
|
series_4 = []
|
||||||
|
|
||||||
for hour_item in hours_list:
|
for hour_item in hours_list:
|
||||||
categories.append(hour_item)
|
categories.append(hour_item)
|
||||||
series_1_value = 0
|
series_1_value = 0
|
||||||
series_2_value = 0
|
series_2_value = 0
|
||||||
series_3_value = 0
|
series_3_value = 0
|
||||||
|
series_4_value = 0
|
||||||
for item in result:
|
for item in result:
|
||||||
if hour_item == item['hourofday']:
|
if hour_item == item['hourofday']:
|
||||||
series_1_value = item['tv_count']
|
series_1_value = item['tv_count']
|
||||||
series_2_value = item['movie_count']
|
series_2_value = item['movie_count']
|
||||||
series_3_value = item['music_count']
|
series_3_value = item['music_count']
|
||||||
|
series_4_value = item['live_count']
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
series_1_value = 0
|
series_1_value = 0
|
||||||
series_2_value = 0
|
series_2_value = 0
|
||||||
series_3_value = 0
|
series_3_value = 0
|
||||||
|
series_4_value = 0
|
||||||
|
|
||||||
series_1.append(series_1_value)
|
series_1.append(series_1_value)
|
||||||
series_2.append(series_2_value)
|
series_2.append(series_2_value)
|
||||||
series_3.append(series_3_value)
|
series_3.append(series_3_value)
|
||||||
|
series_4.append(series_4_value)
|
||||||
|
|
||||||
series_1_output = {'name': 'TV',
|
series_1_output = {'name': 'TV',
|
||||||
'data': series_1}
|
'data': series_1}
|
||||||
@@ -311,14 +369,24 @@ class Graphs(object):
|
|||||||
'data': series_2}
|
'data': series_2}
|
||||||
series_3_output = {'name': 'Music',
|
series_3_output = {'name': 'Music',
|
||||||
'data': series_3}
|
'data': series_3}
|
||||||
|
series_4_output = {'name': 'Live TV',
|
||||||
|
'data': series_4}
|
||||||
|
|
||||||
|
series_output = []
|
||||||
|
if libraries.has_library_type('show'):
|
||||||
|
series_output.append(series_1_output)
|
||||||
|
if libraries.has_library_type('movie'):
|
||||||
|
series_output.append(series_2_output)
|
||||||
|
if libraries.has_library_type('artist'):
|
||||||
|
series_output.append(series_3_output)
|
||||||
|
if libraries.has_library_type('live'):
|
||||||
|
series_output.append(series_4_output)
|
||||||
|
|
||||||
output = {'categories': categories,
|
output = {'categories': categories,
|
||||||
'series': [series_1_output, series_2_output, series_3_output]}
|
'series': series_output}
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def get_total_plays_per_month(self, time_range='12', y_axis='plays', user_id=None, grouping=None):
|
def get_total_plays_per_month(self, time_range='12', y_axis='plays', user_id=None, grouping=None):
|
||||||
import time as time
|
|
||||||
|
|
||||||
if not time_range.isdigit():
|
if not time_range.isdigit():
|
||||||
time_range = '12'
|
time_range = '12'
|
||||||
|
|
||||||
@@ -333,15 +401,17 @@ class Graphs(object):
|
|||||||
if grouping is None:
|
if grouping is None:
|
||||||
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
||||||
|
|
||||||
group_by = 'reference_id' if grouping else 'id'
|
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if y_axis == 'plays':
|
if y_axis == 'plays':
|
||||||
query = 'SELECT strftime("%%Y-%%m", datetime(started, "unixepoch", "localtime")) AS datestring, ' \
|
query = 'SELECT strftime("%%Y-%%m", datetime(started, "unixepoch", "localtime")) AS datestring, ' \
|
||||||
'SUM(CASE WHEN media_type = "episode" THEN 1 ELSE 0 END) AS tv_count, ' \
|
'SUM(CASE WHEN media_type = "episode" AND live = 0 THEN 1 ELSE 0 END) AS tv_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "movie" THEN 1 ELSE 0 END) AS movie_count, ' \
|
'SUM(CASE WHEN media_type = "movie" AND live = 0 THEN 1 ELSE 0 END) AS movie_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "track" THEN 1 ELSE 0 END) AS music_count ' \
|
'SUM(CASE WHEN media_type = "track" AND live = 0 THEN 1 ELSE 0 END) AS music_count, ' \
|
||||||
|
'SUM(live) AS live_count ' \
|
||||||
'FROM (SELECT * FROM session_history ' \
|
'FROM (SELECT * FROM session_history ' \
|
||||||
|
'JOIN session_history_metadata ON session_history.id = session_history_metadata.id ' \
|
||||||
'GROUP BY strftime("%%Y-%%m", datetime(started, "unixepoch", "localtime")), %s) ' \
|
'GROUP BY strftime("%%Y-%%m", datetime(started, "unixepoch", "localtime")), %s) ' \
|
||||||
'AS session_history ' \
|
'AS session_history ' \
|
||||||
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s months", "localtime") %s' \
|
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s months", "localtime") %s' \
|
||||||
@@ -351,13 +421,17 @@ class Graphs(object):
|
|||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
else:
|
else:
|
||||||
query = 'SELECT strftime("%%Y-%%m", datetime(started, "unixepoch", "localtime")) AS datestring, ' \
|
query = 'SELECT strftime("%%Y-%%m", datetime(started, "unixepoch", "localtime")) AS datestring, ' \
|
||||||
'SUM(CASE WHEN media_type = "episode" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "episode" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tv_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tv_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "movie" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "movie" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS movie_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS movie_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "track" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "track" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS music_count ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS music_count, ' \
|
||||||
'FROM session_history ' \
|
'SUM(CASE WHEN live = 1 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS live_count ' \
|
||||||
|
'FROM (SELECT * FROM session_history ' \
|
||||||
|
'JOIN session_history_metadata ON session_history.id = session_history_metadata.id) ' \
|
||||||
|
'AS session_history ' \
|
||||||
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s months", "localtime") %s' \
|
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s months", "localtime") %s' \
|
||||||
'GROUP BY strftime("%%Y-%%m", datetime(started, "unixepoch", "localtime")) ' \
|
'GROUP BY strftime("%%Y-%%m", datetime(started, "unixepoch", "localtime")) ' \
|
||||||
'ORDER BY datestring DESC LIMIT %s' % (time_range, user_cond, time_range)
|
'ORDER BY datestring DESC LIMIT %s' % (time_range, user_cond, time_range)
|
||||||
@@ -383,6 +457,7 @@ class Graphs(object):
|
|||||||
series_1 = []
|
series_1 = []
|
||||||
series_2 = []
|
series_2 = []
|
||||||
series_3 = []
|
series_3 = []
|
||||||
|
series_4 = []
|
||||||
|
|
||||||
for dt in sorted(month_range):
|
for dt in sorted(month_range):
|
||||||
date_string = dt.strftime('%Y-%m')
|
date_string = dt.strftime('%Y-%m')
|
||||||
@@ -390,20 +465,24 @@ class Graphs(object):
|
|||||||
series_1_value = 0
|
series_1_value = 0
|
||||||
series_2_value = 0
|
series_2_value = 0
|
||||||
series_3_value = 0
|
series_3_value = 0
|
||||||
|
series_4_value = 0
|
||||||
for item in result:
|
for item in result:
|
||||||
if date_string == item['datestring']:
|
if date_string == item['datestring']:
|
||||||
series_1_value = item['tv_count']
|
series_1_value = item['tv_count']
|
||||||
series_2_value = item['movie_count']
|
series_2_value = item['movie_count']
|
||||||
series_3_value = item['music_count']
|
series_3_value = item['music_count']
|
||||||
|
series_4_value = item['live_count']
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
series_1_value = 0
|
series_1_value = 0
|
||||||
series_2_value = 0
|
series_2_value = 0
|
||||||
series_3_value = 0
|
series_3_value = 0
|
||||||
|
series_4_value = 0
|
||||||
|
|
||||||
series_1.append(series_1_value)
|
series_1.append(series_1_value)
|
||||||
series_2.append(series_2_value)
|
series_2.append(series_2_value)
|
||||||
series_3.append(series_3_value)
|
series_3.append(series_3_value)
|
||||||
|
series_4.append(series_4_value)
|
||||||
|
|
||||||
series_1_output = {'name': 'TV',
|
series_1_output = {'name': 'TV',
|
||||||
'data': series_1}
|
'data': series_1}
|
||||||
@@ -411,9 +490,21 @@ class Graphs(object):
|
|||||||
'data': series_2}
|
'data': series_2}
|
||||||
series_3_output = {'name': 'Music',
|
series_3_output = {'name': 'Music',
|
||||||
'data': series_3}
|
'data': series_3}
|
||||||
|
series_4_output = {'name': 'Live TV',
|
||||||
|
'data': series_4}
|
||||||
|
|
||||||
|
series_output = []
|
||||||
|
if libraries.has_library_type('show'):
|
||||||
|
series_output.append(series_1_output)
|
||||||
|
if libraries.has_library_type('movie'):
|
||||||
|
series_output.append(series_2_output)
|
||||||
|
if libraries.has_library_type('artist'):
|
||||||
|
series_output.append(series_3_output)
|
||||||
|
if libraries.has_library_type('live'):
|
||||||
|
series_output.append(series_4_output)
|
||||||
|
|
||||||
output = {'categories': categories,
|
output = {'categories': categories,
|
||||||
'series': [series_1_output, series_2_output, series_3_output]}
|
'series': series_output}
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def get_total_plays_by_top_10_platforms(self, time_range='30', y_axis='plays', user_id=None, grouping=None):
|
def get_total_plays_by_top_10_platforms(self, time_range='30', y_axis='plays', user_id=None, grouping=None):
|
||||||
@@ -431,16 +522,20 @@ class Graphs(object):
|
|||||||
if grouping is None:
|
if grouping is None:
|
||||||
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
||||||
|
|
||||||
group_by = 'reference_id' if grouping else 'id'
|
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if y_axis == 'plays':
|
if y_axis == 'plays':
|
||||||
query = 'SELECT platform, ' \
|
query = 'SELECT platform, ' \
|
||||||
'SUM(CASE WHEN media_type = "episode" THEN 1 ELSE 0 END) AS tv_count, ' \
|
'SUM(CASE WHEN media_type = "episode" AND live = 0 THEN 1 ELSE 0 END) AS tv_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "movie" THEN 1 ELSE 0 END) AS movie_count, ' \
|
'SUM(CASE WHEN media_type = "movie" AND live = 0 THEN 1 ELSE 0 END) AS movie_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "track" THEN 1 ELSE 0 END) AS music_count, ' \
|
'SUM(CASE WHEN media_type = "track" AND live = 0 THEN 1 ELSE 0 END) AS music_count, ' \
|
||||||
|
'SUM(live) AS live_count, ' \
|
||||||
'COUNT(id) AS total_count ' \
|
'COUNT(id) AS total_count ' \
|
||||||
'FROM (SELECT * FROM session_history GROUP BY %s) AS session_history ' \
|
'FROM (SELECT * FROM session_history ' \
|
||||||
|
'JOIN session_history_metadata ON session_history.id = session_history_metadata.id ' \
|
||||||
|
'GROUP BY %s) ' \
|
||||||
|
'AS session_history ' \
|
||||||
'WHERE (datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime")) %s' \
|
'WHERE (datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime")) %s' \
|
||||||
'GROUP BY platform ' \
|
'GROUP BY platform ' \
|
||||||
'ORDER BY total_count DESC ' \
|
'ORDER BY total_count DESC ' \
|
||||||
@@ -449,15 +544,19 @@ class Graphs(object):
|
|||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
else:
|
else:
|
||||||
query = 'SELECT platform, ' \
|
query = 'SELECT platform, ' \
|
||||||
'SUM(CASE WHEN media_type = "episode" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "episode" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tv_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tv_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "movie" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "movie" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS movie_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS movie_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "track" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "track" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS music_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS music_count, ' \
|
||||||
|
'SUM(CASE WHEN live = 1 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS live_count, ' \
|
||||||
'SUM(CASE WHEN stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS total_duration ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS total_duration ' \
|
||||||
'FROM session_history ' \
|
'FROM (SELECT * FROM session_history ' \
|
||||||
|
'JOIN session_history_metadata ON session_history.id = session_history_metadata.id) ' \
|
||||||
|
'AS session_history ' \
|
||||||
'WHERE (datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime")) %s' \
|
'WHERE (datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime")) %s' \
|
||||||
'GROUP BY platform ' \
|
'GROUP BY platform ' \
|
||||||
'ORDER BY total_duration DESC ' \
|
'ORDER BY total_duration DESC ' \
|
||||||
@@ -472,12 +571,14 @@ class Graphs(object):
|
|||||||
series_1 = []
|
series_1 = []
|
||||||
series_2 = []
|
series_2 = []
|
||||||
series_3 = []
|
series_3 = []
|
||||||
|
series_4 = []
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
categories.append(common.PLATFORM_NAME_OVERRIDES.get(item['platform'], item['platform']))
|
categories.append(common.PLATFORM_NAME_OVERRIDES.get(item['platform'], item['platform']))
|
||||||
series_1.append(item['tv_count'])
|
series_1.append(item['tv_count'])
|
||||||
series_2.append(item['movie_count'])
|
series_2.append(item['movie_count'])
|
||||||
series_3.append(item['music_count'])
|
series_3.append(item['music_count'])
|
||||||
|
series_4.append(item['live_count'])
|
||||||
|
|
||||||
series_1_output = {'name': 'TV',
|
series_1_output = {'name': 'TV',
|
||||||
'data': series_1}
|
'data': series_1}
|
||||||
@@ -485,9 +586,21 @@ class Graphs(object):
|
|||||||
'data': series_2}
|
'data': series_2}
|
||||||
series_3_output = {'name': 'Music',
|
series_3_output = {'name': 'Music',
|
||||||
'data': series_3}
|
'data': series_3}
|
||||||
|
series_4_output = {'name': 'Live TV',
|
||||||
|
'data': series_4}
|
||||||
|
|
||||||
|
series_output = []
|
||||||
|
if libraries.has_library_type('show'):
|
||||||
|
series_output.append(series_1_output)
|
||||||
|
if libraries.has_library_type('movie'):
|
||||||
|
series_output.append(series_2_output)
|
||||||
|
if libraries.has_library_type('artist'):
|
||||||
|
series_output.append(series_3_output)
|
||||||
|
if libraries.has_library_type('live'):
|
||||||
|
series_output.append(series_4_output)
|
||||||
|
|
||||||
output = {'categories': categories,
|
output = {'categories': categories,
|
||||||
'series': [series_1_output, series_2_output, series_3_output]}
|
'series': series_output}
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def get_total_plays_by_top_10_users(self, time_range='30', y_axis='plays', user_id=None, grouping=None):
|
def get_total_plays_by_top_10_users(self, time_range='30', y_axis='plays', user_id=None, grouping=None):
|
||||||
@@ -505,7 +618,7 @@ class Graphs(object):
|
|||||||
if grouping is None:
|
if grouping is None:
|
||||||
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
||||||
|
|
||||||
group_by = 'reference_id' if grouping else 'id'
|
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if y_axis == 'plays':
|
if y_axis == 'plays':
|
||||||
@@ -513,11 +626,15 @@ class Graphs(object):
|
|||||||
'users.user_id, users.username, ' \
|
'users.user_id, users.username, ' \
|
||||||
'(CASE WHEN users.friendly_name IS NULL OR TRIM(users.friendly_name) = "" ' \
|
'(CASE WHEN users.friendly_name IS NULL OR TRIM(users.friendly_name) = "" ' \
|
||||||
' THEN users.username ELSE users.friendly_name END) AS friendly_name,' \
|
' THEN users.username ELSE users.friendly_name END) AS friendly_name,' \
|
||||||
'SUM(CASE WHEN media_type = "episode" THEN 1 ELSE 0 END) AS tv_count, ' \
|
'SUM(CASE WHEN media_type = "episode" AND live = 0 THEN 1 ELSE 0 END) AS tv_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "movie" THEN 1 ELSE 0 END) AS movie_count, ' \
|
'SUM(CASE WHEN media_type = "movie" AND live = 0 THEN 1 ELSE 0 END) AS movie_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "track" THEN 1 ELSE 0 END) AS music_count, ' \
|
'SUM(CASE WHEN media_type = "track" AND live = 0 THEN 1 ELSE 0 END) AS music_count, ' \
|
||||||
|
'SUM(live) AS live_count, ' \
|
||||||
'COUNT(session_history.id) AS total_count ' \
|
'COUNT(session_history.id) AS total_count ' \
|
||||||
'FROM (SELECT * FROM session_history GROUP BY %s) AS session_history ' \
|
'FROM (SELECT * FROM session_history ' \
|
||||||
|
'JOIN session_history_metadata ON session_history.id = session_history_metadata.id ' \
|
||||||
|
'GROUP BY %s) ' \
|
||||||
|
'AS session_history ' \
|
||||||
'JOIN users ON session_history.user_id = users.user_id ' \
|
'JOIN users ON session_history.user_id = users.user_id ' \
|
||||||
'WHERE (datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime")) %s' \
|
'WHERE (datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime")) %s' \
|
||||||
'GROUP BY session_history.user_id ' \
|
'GROUP BY session_history.user_id ' \
|
||||||
@@ -530,15 +647,19 @@ class Graphs(object):
|
|||||||
'users.user_id, users.username, ' \
|
'users.user_id, users.username, ' \
|
||||||
'(CASE WHEN users.friendly_name IS NULL OR TRIM(users.friendly_name) = "" ' \
|
'(CASE WHEN users.friendly_name IS NULL OR TRIM(users.friendly_name) = "" ' \
|
||||||
' THEN users.username ELSE users.friendly_name END) AS friendly_name,' \
|
' THEN users.username ELSE users.friendly_name END) AS friendly_name,' \
|
||||||
'SUM(CASE WHEN media_type = "episode" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "episode" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tv_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tv_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "movie" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "movie" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS movie_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS movie_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "track" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "track" AND live = 0 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS music_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS music_count, ' \
|
||||||
|
'SUM(CASE WHEN live = 1 AND stopped > 0 THEN (stopped - started) ' \
|
||||||
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS live_count, ' \
|
||||||
'SUM(CASE WHEN stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS total_duration ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS total_duration ' \
|
||||||
'FROM session_history ' \
|
'FROM (SELECT * FROM session_history ' \
|
||||||
|
'JOIN session_history_metadata ON session_history.id = session_history_metadata.id) ' \
|
||||||
|
'AS session_history ' \
|
||||||
'JOIN users ON session_history.user_id = users.user_id ' \
|
'JOIN users ON session_history.user_id = users.user_id ' \
|
||||||
'WHERE (datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime")) %s' \
|
'WHERE (datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime")) %s' \
|
||||||
'GROUP BY session_history.user_id ' \
|
'GROUP BY session_history.user_id ' \
|
||||||
@@ -554,6 +675,7 @@ class Graphs(object):
|
|||||||
series_1 = []
|
series_1 = []
|
||||||
series_2 = []
|
series_2 = []
|
||||||
series_3 = []
|
series_3 = []
|
||||||
|
series_4 = []
|
||||||
|
|
||||||
session_user_id = session.get_session_user_id()
|
session_user_id = session.get_session_user_id()
|
||||||
|
|
||||||
@@ -565,6 +687,7 @@ class Graphs(object):
|
|||||||
series_1.append(item['tv_count'])
|
series_1.append(item['tv_count'])
|
||||||
series_2.append(item['movie_count'])
|
series_2.append(item['movie_count'])
|
||||||
series_3.append(item['music_count'])
|
series_3.append(item['music_count'])
|
||||||
|
series_4.append(item['live_count'])
|
||||||
|
|
||||||
series_1_output = {'name': 'TV',
|
series_1_output = {'name': 'TV',
|
||||||
'data': series_1}
|
'data': series_1}
|
||||||
@@ -572,9 +695,21 @@ class Graphs(object):
|
|||||||
'data': series_2}
|
'data': series_2}
|
||||||
series_3_output = {'name': 'Music',
|
series_3_output = {'name': 'Music',
|
||||||
'data': series_3}
|
'data': series_3}
|
||||||
|
series_4_output = {'name': 'Live TV',
|
||||||
|
'data': series_4}
|
||||||
|
|
||||||
|
series_output = []
|
||||||
|
if libraries.has_library_type('show'):
|
||||||
|
series_output.append(series_1_output)
|
||||||
|
if libraries.has_library_type('movie'):
|
||||||
|
series_output.append(series_2_output)
|
||||||
|
if libraries.has_library_type('artist'):
|
||||||
|
series_output.append(series_3_output)
|
||||||
|
if libraries.has_library_type('live'):
|
||||||
|
series_output.append(series_4_output)
|
||||||
|
|
||||||
output = {'categories': categories,
|
output = {'categories': categories,
|
||||||
'series': [series_1_output, series_2_output, series_3_output]}
|
'series': series_output}
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def get_total_plays_per_stream_type(self, time_range='30', y_axis='plays', user_id=None, grouping=None):
|
def get_total_plays_per_stream_type(self, time_range='30', y_axis='plays', user_id=None, grouping=None):
|
||||||
@@ -592,7 +727,7 @@ class Graphs(object):
|
|||||||
if grouping is None:
|
if grouping is None:
|
||||||
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
||||||
|
|
||||||
group_by = 'reference_id' if grouping else 'id'
|
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if y_axis == 'plays':
|
if y_axis == 'plays':
|
||||||
@@ -698,7 +833,7 @@ class Graphs(object):
|
|||||||
if grouping is None:
|
if grouping is None:
|
||||||
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
||||||
|
|
||||||
group_by = 'reference_id' if grouping else 'id'
|
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if y_axis == 'plays':
|
if y_axis == 'plays':
|
||||||
@@ -784,7 +919,7 @@ class Graphs(object):
|
|||||||
if grouping is None:
|
if grouping is None:
|
||||||
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
||||||
|
|
||||||
group_by = 'reference_id' if grouping else 'id'
|
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if y_axis == 'plays':
|
if y_axis == 'plays':
|
||||||
@@ -894,7 +1029,7 @@ class Graphs(object):
|
|||||||
if grouping is None:
|
if grouping is None:
|
||||||
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
||||||
|
|
||||||
group_by = 'reference_id' if grouping else 'id'
|
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if y_axis == 'plays':
|
if y_axis == 'plays':
|
||||||
@@ -984,7 +1119,7 @@ class Graphs(object):
|
|||||||
if grouping is None:
|
if grouping is None:
|
||||||
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
|
||||||
|
|
||||||
group_by = 'reference_id' if grouping else 'id'
|
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if y_axis == 'plays':
|
if y_axis == 'plays':
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import arrow
|
||||||
import base64
|
import base64
|
||||||
import certifi
|
import certifi
|
||||||
import cloudinary
|
import cloudinary
|
||||||
@@ -40,6 +41,7 @@ import sys
|
|||||||
import tarfile
|
import tarfile
|
||||||
import time
|
import time
|
||||||
import unicodedata
|
import unicodedata
|
||||||
|
import urllib
|
||||||
import urllib3
|
import urllib3
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
import xmltodict
|
import xmltodict
|
||||||
@@ -221,6 +223,22 @@ def utc_now_iso():
|
|||||||
return utcnow.isoformat()
|
return utcnow.isoformat()
|
||||||
|
|
||||||
|
|
||||||
|
def timestamp_to_YMD(timestamp):
|
||||||
|
return timestamp_to_datetime(timestamp).strftime("%Y-%m-%d")
|
||||||
|
|
||||||
|
|
||||||
|
def timestamp_to_datetime(timestamp):
|
||||||
|
return datetime.datetime.fromtimestamp(cast_to_int(str(timestamp)))
|
||||||
|
|
||||||
|
|
||||||
|
def iso_to_YMD(iso):
|
||||||
|
return iso_to_datetime(iso).strftime("%Y-%m-%d")
|
||||||
|
|
||||||
|
|
||||||
|
def iso_to_datetime(iso):
|
||||||
|
return arrow.get(iso).datetime
|
||||||
|
|
||||||
|
|
||||||
def human_duration(s, sig='dhms'):
|
def human_duration(s, sig='dhms'):
|
||||||
|
|
||||||
hd = ''
|
hd = ''
|
||||||
@@ -1240,3 +1258,92 @@ def mask_config_passwords(config):
|
|||||||
config[cfg] = ' '
|
config[cfg] = ' '
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def bool_true(value):
|
||||||
|
if value is True or value == 1:
|
||||||
|
return True
|
||||||
|
elif isinstance(value, basestring) and value.lower() in ('1', 'true', 't', 'yes', 'y', 'on'):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def page(endpoint, *args, **kwargs):
|
||||||
|
endpoints = {
|
||||||
|
'pms_image_proxy': pms_image_proxy,
|
||||||
|
'info': info_page,
|
||||||
|
'library': library_page,
|
||||||
|
'user': user_page
|
||||||
|
}
|
||||||
|
|
||||||
|
params = {}
|
||||||
|
|
||||||
|
if endpoint in endpoints:
|
||||||
|
params = endpoints[endpoint](*args, **kwargs)
|
||||||
|
|
||||||
|
return endpoint + '?' + urllib.urlencode(params)
|
||||||
|
|
||||||
|
|
||||||
|
def pms_image_proxy(img=None, rating_key=None, width=None, height=None,
|
||||||
|
opacity=None, background=None, blur=None, img_format=None,
|
||||||
|
fallback=None, refresh=None, clip=None):
|
||||||
|
params = {}
|
||||||
|
|
||||||
|
if img is not None:
|
||||||
|
params['img'] = img
|
||||||
|
if rating_key is not None:
|
||||||
|
params['rating_key'] = rating_key
|
||||||
|
if width is not None:
|
||||||
|
params['width'] = width
|
||||||
|
if height is not None:
|
||||||
|
params['height'] = height
|
||||||
|
if opacity is not None:
|
||||||
|
params['opacity'] = opacity
|
||||||
|
if background is not None:
|
||||||
|
params['background'] = background
|
||||||
|
if blur is not None:
|
||||||
|
params['blur'] = blur
|
||||||
|
if img_format is not None:
|
||||||
|
params['img_format'] = img_format
|
||||||
|
if fallback is not None:
|
||||||
|
params['fallback'] = fallback
|
||||||
|
if refresh is not None:
|
||||||
|
params['refresh'] = 'true'
|
||||||
|
if clip is not None:
|
||||||
|
params['clip'] = 'true'
|
||||||
|
|
||||||
|
return params
|
||||||
|
|
||||||
|
|
||||||
|
def info_page(rating_key=None, guid=None, history=None, live=None):
|
||||||
|
params = {}
|
||||||
|
|
||||||
|
if live and history:
|
||||||
|
params['guid'] = guid
|
||||||
|
else:
|
||||||
|
params['rating_key'] = rating_key
|
||||||
|
|
||||||
|
if history:
|
||||||
|
params['source'] = 'history'
|
||||||
|
|
||||||
|
return params
|
||||||
|
|
||||||
|
|
||||||
|
def library_page(section_id=None):
|
||||||
|
params = {}
|
||||||
|
|
||||||
|
if section_id is not None:
|
||||||
|
params['section_id'] = section_id
|
||||||
|
|
||||||
|
return params
|
||||||
|
|
||||||
|
|
||||||
|
def user_page(user_id=None, user=None):
|
||||||
|
params = {}
|
||||||
|
|
||||||
|
if user_id is not None:
|
||||||
|
params['user_id'] = user_id
|
||||||
|
if user is not None:
|
||||||
|
params['user'] = user
|
||||||
|
|
||||||
|
return params
|
||||||
|
@@ -88,6 +88,37 @@ def refresh_libraries():
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def add_live_tv_library():
|
||||||
|
if not plexpy.CONFIG.ADD_LIVE_TV_LIBRARY:
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.info(u"Tautulli Libraries :: Adding Live TV library to the database.")
|
||||||
|
|
||||||
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
|
section_keys = {'server_id': plexpy.CONFIG.PMS_IDENTIFIER,
|
||||||
|
'section_id': common.LIVE_TV_SECTION_ID}
|
||||||
|
section_values = {'server_id': plexpy.CONFIG.PMS_IDENTIFIER,
|
||||||
|
'section_id': common.LIVE_TV_SECTION_ID,
|
||||||
|
'section_name': common.LIVE_TV_SECTION_NAME,
|
||||||
|
'section_type': 'live'
|
||||||
|
}
|
||||||
|
|
||||||
|
result = monitor_db.upsert('library_sections', key_dict=section_keys, value_dict=section_values)
|
||||||
|
|
||||||
|
if result == 'insert':
|
||||||
|
plexpy.CONFIG.__setattr__('ADD_LIVE_TV_LIBRARY', 0)
|
||||||
|
plexpy.CONFIG.write()
|
||||||
|
|
||||||
|
|
||||||
|
def has_library_type(section_type):
|
||||||
|
monitor_db = database.MonitorDatabase()
|
||||||
|
query = 'SELECT * FROM library_sections WHERE section_type = ? AND deleted_section = 0'
|
||||||
|
args = [section_type]
|
||||||
|
result = monitor_db.select_single(query=query, args=args)
|
||||||
|
return bool(result)
|
||||||
|
|
||||||
|
|
||||||
def update_section_ids():
|
def update_section_ids():
|
||||||
plexpy.CONFIG.UPDATE_SECTION_IDS = -1
|
plexpy.CONFIG.UPDATE_SECTION_IDS = -1
|
||||||
|
|
||||||
@@ -285,6 +316,10 @@ class Libraries(object):
|
|||||||
'session_history_metadata.parent_media_index',
|
'session_history_metadata.parent_media_index',
|
||||||
'session_history_metadata.content_rating',
|
'session_history_metadata.content_rating',
|
||||||
'session_history_metadata.labels',
|
'session_history_metadata.labels',
|
||||||
|
'session_history_metadata.live',
|
||||||
|
'session_history_metadata.added_at',
|
||||||
|
'session_history_metadata.originally_available_at',
|
||||||
|
'session_history_metadata.guid',
|
||||||
'library_sections.do_notify',
|
'library_sections.do_notify',
|
||||||
'library_sections.do_notify_created',
|
'library_sections.do_notify_created',
|
||||||
'library_sections.keep_history'
|
'library_sections.keep_history'
|
||||||
@@ -348,6 +383,9 @@ class Libraries(object):
|
|||||||
'parent_media_index': item['parent_media_index'],
|
'parent_media_index': item['parent_media_index'],
|
||||||
'content_rating': item['content_rating'],
|
'content_rating': item['content_rating'],
|
||||||
'labels': item['labels'].split(';') if item['labels'] else (),
|
'labels': item['labels'].split(';') if item['labels'] else (),
|
||||||
|
'live': item['live'],
|
||||||
|
'originally_available_at': item['originally_available_at'],
|
||||||
|
'guid': item['guid'],
|
||||||
'do_notify': helpers.checked(item['do_notify']),
|
'do_notify': helpers.checked(item['do_notify']),
|
||||||
'do_notify_created': helpers.checked(item['do_notify_created']),
|
'do_notify_created': helpers.checked(item['do_notify_created']),
|
||||||
'keep_history': helpers.checked(item['keep_history'])
|
'keep_history': helpers.checked(item['keep_history'])
|
||||||
@@ -670,12 +708,14 @@ class Libraries(object):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def set_config(self, section_id=None, custom_thumb='', do_notify=1, keep_history=1, do_notify_created=1):
|
def set_config(self, section_id=None, custom_thumb='', custom_art='',
|
||||||
|
do_notify=1, keep_history=1, do_notify_created=1):
|
||||||
if section_id:
|
if section_id:
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
key_dict = {'section_id': section_id}
|
key_dict = {'section_id': section_id}
|
||||||
value_dict = {'custom_thumb_url': custom_thumb,
|
value_dict = {'custom_thumb_url': custom_thumb,
|
||||||
|
'custom_art_url': custom_art,
|
||||||
'do_notify': do_notify,
|
'do_notify': do_notify,
|
||||||
'do_notify_created': do_notify_created,
|
'do_notify_created': do_notify_created,
|
||||||
'keep_history': keep_history}
|
'keep_history': keep_history}
|
||||||
@@ -699,7 +739,7 @@ class Libraries(object):
|
|||||||
'deleted_section': 0
|
'deleted_section': 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if not section_id or helpers.cast_to_int(section_id) <= 0:
|
if not section_id:
|
||||||
return default_return
|
return default_return
|
||||||
|
|
||||||
def get_library_details(section_id=section_id):
|
def get_library_details(section_id=section_id):
|
||||||
@@ -708,7 +748,8 @@ class Libraries(object):
|
|||||||
try:
|
try:
|
||||||
if str(section_id).isdigit():
|
if str(section_id).isdigit():
|
||||||
query = 'SELECT section_id, section_name, section_type, count, parent_count, child_count, ' \
|
query = 'SELECT section_id, section_name, section_type, count, parent_count, child_count, ' \
|
||||||
'thumb AS library_thumb, custom_thumb_url AS custom_thumb, art, ' \
|
'thumb AS library_thumb, custom_thumb_url AS custom_thumb, art AS library_art, ' \
|
||||||
|
'custom_art_url AS custom_art, ' \
|
||||||
'do_notify, do_notify_created, keep_history, deleted_section ' \
|
'do_notify, do_notify_created, keep_history, deleted_section ' \
|
||||||
'FROM library_sections ' \
|
'FROM library_sections ' \
|
||||||
'WHERE section_id = ? '
|
'WHERE section_id = ? '
|
||||||
@@ -729,11 +770,16 @@ class Libraries(object):
|
|||||||
else:
|
else:
|
||||||
library_thumb = common.DEFAULT_COVER_THUMB
|
library_thumb = common.DEFAULT_COVER_THUMB
|
||||||
|
|
||||||
|
if item['custom_art'] and item['custom_art'] != item['library_art']:
|
||||||
|
library_art = item['custom_art']
|
||||||
|
else:
|
||||||
|
library_art = item['library_art']
|
||||||
|
|
||||||
library_details = {'section_id': item['section_id'],
|
library_details = {'section_id': item['section_id'],
|
||||||
'section_name': item['section_name'],
|
'section_name': item['section_name'],
|
||||||
'section_type': item['section_type'],
|
'section_type': item['section_type'],
|
||||||
'library_thumb': library_thumb,
|
'library_thumb': library_thumb,
|
||||||
'library_art': item['art'],
|
'library_art': library_art,
|
||||||
'count': item['count'],
|
'count': item['count'],
|
||||||
'parent_count': item['parent_count'],
|
'parent_count': item['parent_count'],
|
||||||
'child_count': item['child_count'],
|
'child_count': item['child_count'],
|
||||||
@@ -879,11 +925,11 @@ class Libraries(object):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if str(section_id).isdigit():
|
if str(section_id).isdigit():
|
||||||
query = 'SELECT session_history.id, session_history.media_type, ' \
|
query = 'SELECT session_history.id, session_history.media_type, guid, ' \
|
||||||
'session_history.rating_key, session_history.parent_rating_key, session_history.grandparent_rating_key, ' \
|
'session_history.rating_key, session_history.parent_rating_key, session_history.grandparent_rating_key, ' \
|
||||||
'title, parent_title, grandparent_title, original_title, ' \
|
'title, parent_title, grandparent_title, original_title, ' \
|
||||||
'thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, ' \
|
'thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, ' \
|
||||||
'year, started, user, content_rating, labels, section_id ' \
|
'year, originally_available_at, added_at, live, started, user, content_rating, labels, section_id ' \
|
||||||
'FROM session_history_metadata ' \
|
'FROM session_history_metadata ' \
|
||||||
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
|
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
|
||||||
'WHERE section_id = ? ' \
|
'WHERE section_id = ? ' \
|
||||||
@@ -917,6 +963,9 @@ class Libraries(object):
|
|||||||
'media_index': row['media_index'],
|
'media_index': row['media_index'],
|
||||||
'parent_media_index': row['parent_media_index'],
|
'parent_media_index': row['parent_media_index'],
|
||||||
'year': row['year'],
|
'year': row['year'],
|
||||||
|
'originally_available_at': row['originally_available_at'],
|
||||||
|
'live': row['live'],
|
||||||
|
'guid': row['guid'],
|
||||||
'time': row['started'],
|
'time': row['started'],
|
||||||
'user': row['user'],
|
'user': row['user'],
|
||||||
'section_id': row['section_id'],
|
'section_id': row['section_id'],
|
||||||
|
@@ -140,11 +140,12 @@ class PublicIPFilter(RegexFilter):
|
|||||||
super(PublicIPFilter, self).__init__()
|
super(PublicIPFilter, self).__init__()
|
||||||
|
|
||||||
# Currently only checking for ipv4 addresses
|
# Currently only checking for ipv4 addresses
|
||||||
self.regex = re.compile(r'[0-9]+(?:\.[0-9]+){3}(?!\d*-[a-z0-9]{6})')
|
self.regex = re.compile(r'[0-9]+(?:[.-][0-9]+){3}(?!\d*-[a-z0-9]{6})')
|
||||||
|
|
||||||
def replace(self, text, ip):
|
def replace(self, text, ip):
|
||||||
if helpers.is_public_ip(ip):
|
if helpers.is_public_ip(ip.replace('-', '.')):
|
||||||
return text.replace(ip, ip.partition('.')[0] + '.***.***.***')
|
partition = '-' if '-' in ip else '.'
|
||||||
|
return text.replace(ip, ip.partition(partition)[0] + (partition + '***') * 3)
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
@@ -536,8 +536,15 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
|
|||||||
|
|
||||||
ap = activity_processor.ActivityProcessor()
|
ap = activity_processor.ActivityProcessor()
|
||||||
sessions = ap.get_sessions()
|
sessions = ap.get_sessions()
|
||||||
stream_count = len(sessions)
|
|
||||||
user_sessions = ap.get_sessions(user_id=session.get('user_id'))
|
user_sessions = ap.get_sessions(user_id=session.get('user_id'))
|
||||||
|
|
||||||
|
# Filter out the session_key from the database sessions for playback stopped events
|
||||||
|
# to prevent race condition between the database and notifications
|
||||||
|
if notify_action == 'on_stop':
|
||||||
|
sessions = [s for s in sessions if str(s['session_key']) != notify_params['session_key']]
|
||||||
|
user_sessions = [s for s in user_sessions if str(s['session_key']) != notify_params['session_key']]
|
||||||
|
|
||||||
|
stream_count = len(sessions)
|
||||||
user_stream_count = len(user_sessions)
|
user_stream_count = len(user_sessions)
|
||||||
|
|
||||||
# Generate a combined transcode decision value
|
# Generate a combined transcode decision value
|
||||||
@@ -683,18 +690,26 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
|
|||||||
poster_key = notify_params['parent_rating_key']
|
poster_key = notify_params['parent_rating_key']
|
||||||
poster_title = '%s - %s' % (notify_params['grandparent_title'],
|
poster_title = '%s - %s' % (notify_params['grandparent_title'],
|
||||||
notify_params['parent_title'])
|
notify_params['parent_title'])
|
||||||
|
elif notify_params['media_type'] == 'clip':
|
||||||
|
if notify_params['extra_type']:
|
||||||
|
poster_thumb = notify_params['art'].replace('/art', '/thumb') or notify_params['thumb']
|
||||||
|
else:
|
||||||
|
poster_thumb = notify_params['parent_thumb'] or notify_params['thumb']
|
||||||
|
poster_key = notify_params['rating_key']
|
||||||
|
poster_title = notify_params['title']
|
||||||
else:
|
else:
|
||||||
poster_thumb = ''
|
poster_thumb = ''
|
||||||
poster_key = ''
|
poster_key = ''
|
||||||
poster_title = ''
|
poster_title = ''
|
||||||
|
|
||||||
img_service = helpers.get_img_service(include_self=True)
|
img_service = helpers.get_img_service(include_self=True)
|
||||||
|
fallback = 'poster-live' if notify_params['live'] else 'poster'
|
||||||
if img_service not in (None, 'self-hosted'):
|
if img_service not in (None, 'self-hosted'):
|
||||||
img_info = get_img_info(img=poster_thumb, rating_key=poster_key, title=poster_title, fallback='poster')
|
img_info = get_img_info(img=poster_thumb, rating_key=poster_key, title=poster_title, fallback=fallback)
|
||||||
poster_info = {'poster_title': img_info['img_title'], 'poster_url': img_info['img_url']}
|
poster_info = {'poster_title': img_info['img_title'], 'poster_url': img_info['img_url']}
|
||||||
notify_params.update(poster_info)
|
notify_params.update(poster_info)
|
||||||
elif img_service == 'self-hosted' and plexpy.CONFIG.HTTP_BASE_URL:
|
elif img_service == 'self-hosted' and plexpy.CONFIG.HTTP_BASE_URL:
|
||||||
img_hash = set_hash_image_info(img=poster_thumb, fallback='poster')
|
img_hash = set_hash_image_info(img=poster_thumb, fallback=fallback)
|
||||||
poster_info = {'poster_title': poster_title,
|
poster_info = {'poster_title': poster_title,
|
||||||
'poster_url': plexpy.CONFIG.HTTP_BASE_URL + plexpy.HTTP_ROOT + 'image/' + img_hash}
|
'poster_url': plexpy.CONFIG.HTTP_BASE_URL + plexpy.HTTP_ROOT + 'image/' + img_hash}
|
||||||
notify_params.update(poster_info)
|
notify_params.update(poster_info)
|
||||||
@@ -818,6 +833,9 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
|
|||||||
'optimized_version_profile': notify_params['optimized_version_profile'],
|
'optimized_version_profile': notify_params['optimized_version_profile'],
|
||||||
'synced_version': notify_params['synced_version'],
|
'synced_version': notify_params['synced_version'],
|
||||||
'live': notify_params['live'],
|
'live': notify_params['live'],
|
||||||
|
'channel_call_sign': notify_params['channel_call_sign'],
|
||||||
|
'channel_identifier': notify_params['channel_identifier'],
|
||||||
|
'channel_thumb': notify_params['channel_thumb'],
|
||||||
'secure': 'unknown' if notify_params['secure'] is None else notify_params['secure'],
|
'secure': 'unknown' if notify_params['secure'] is None else notify_params['secure'],
|
||||||
'relayed': notify_params['relayed'],
|
'relayed': notify_params['relayed'],
|
||||||
'stream_local': notify_params['local'],
|
'stream_local': notify_params['local'],
|
||||||
@@ -984,6 +1002,7 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
|
|||||||
'rating_key': notify_params['rating_key'],
|
'rating_key': notify_params['rating_key'],
|
||||||
'parent_rating_key': notify_params['parent_rating_key'],
|
'parent_rating_key': notify_params['parent_rating_key'],
|
||||||
'grandparent_rating_key': notify_params['grandparent_rating_key'],
|
'grandparent_rating_key': notify_params['grandparent_rating_key'],
|
||||||
|
'art': notify_params['art'],
|
||||||
'thumb': notify_params['thumb'],
|
'thumb': notify_params['thumb'],
|
||||||
'parent_thumb': notify_params['parent_thumb'],
|
'parent_thumb': notify_params['parent_thumb'],
|
||||||
'grandparent_thumb': notify_params['grandparent_thumb'],
|
'grandparent_thumb': notify_params['grandparent_thumb'],
|
||||||
@@ -1239,14 +1258,17 @@ def get_img_info(img=None, rating_key=None, title='', width=1000, height=1500,
|
|||||||
return img_info
|
return img_info
|
||||||
|
|
||||||
if rating_key and not img:
|
if rating_key and not img:
|
||||||
if fallback == 'art':
|
if fallback and fallback.startswith('art'):
|
||||||
img = '/library/metadata/{}/art'.format(rating_key)
|
img = '/library/metadata/{}/art'.format(rating_key)
|
||||||
else:
|
else:
|
||||||
img = '/library/metadata/{}/thumb'.format(rating_key)
|
img = '/library/metadata/{}/thumb'.format(rating_key)
|
||||||
|
|
||||||
|
if img.startswith('/library/metadata'):
|
||||||
img_split = img.split('/')
|
img_split = img.split('/')
|
||||||
img = '/'.join(img_split[:5])
|
img = '/'.join(img_split[:5])
|
||||||
rating_key = rating_key or img_split[3]
|
img_rating_key = img_split[3]
|
||||||
|
if rating_key != img_rating_key:
|
||||||
|
rating_key = img_rating_key
|
||||||
|
|
||||||
service = helpers.get_img_service()
|
service = helpers.get_img_service()
|
||||||
|
|
||||||
@@ -1256,7 +1278,7 @@ def get_img_info(img=None, rating_key=None, title='', width=1000, height=1500,
|
|||||||
elif service == 'cloudinary':
|
elif service == 'cloudinary':
|
||||||
if fallback == 'cover':
|
if fallback == 'cover':
|
||||||
w, h = 1000, 1000
|
w, h = 1000, 1000
|
||||||
elif fallback == 'art':
|
elif fallback and fallback.startswith('art'):
|
||||||
w, h = 1920, 1080
|
w, h = 1920, 1080
|
||||||
else:
|
else:
|
||||||
w, h = 1000, 1500
|
w, h = 1000, 1500
|
||||||
@@ -1340,14 +1362,17 @@ def set_hash_image_info(img=None, rating_key=None, width=750, height=1000,
|
|||||||
return fallback
|
return fallback
|
||||||
|
|
||||||
if rating_key and not img:
|
if rating_key and not img:
|
||||||
if fallback == 'art':
|
if fallback and fallback.startswith('art'):
|
||||||
img = '/library/metadata/{}/art'.format(rating_key)
|
img = '/library/metadata/{}/art'.format(rating_key)
|
||||||
else:
|
else:
|
||||||
img = '/library/metadata/{}/thumb'.format(rating_key)
|
img = '/library/metadata/{}/thumb'.format(rating_key)
|
||||||
|
|
||||||
|
if img.startswith('/library/metadata'):
|
||||||
img_split = img.split('/')
|
img_split = img.split('/')
|
||||||
img = '/'.join(img_split[:5])
|
img = '/'.join(img_split[:5])
|
||||||
rating_key = rating_key or img_split[3]
|
img_rating_key = img_split[3]
|
||||||
|
if rating_key != img_rating_key:
|
||||||
|
rating_key = img_rating_key
|
||||||
|
|
||||||
img_string = '{}.{}.{}.{}.{}.{}.{}.{}'.format(
|
img_string = '{}.{}.{}.{}.{}.{}.{}.{}'.format(
|
||||||
plexpy.CONFIG.PMS_UUID, img, rating_key, width, height, opacity, background, blur, fallback)
|
plexpy.CONFIG.PMS_UUID, img, rating_key, width, height, opacity, background, blur, fallback)
|
||||||
|
@@ -3609,7 +3609,7 @@ class WEBHOOK(Notifier):
|
|||||||
"""
|
"""
|
||||||
NAME = 'Webhook'
|
NAME = 'Webhook'
|
||||||
_DEFAULT_CONFIG = {'hook': '',
|
_DEFAULT_CONFIG = {'hook': '',
|
||||||
'method': ''
|
'method': 'POST'
|
||||||
}
|
}
|
||||||
|
|
||||||
def agent_notify(self, subject='', body='', action='', **kwargs):
|
def agent_notify(self, subject='', body='', action='', **kwargs):
|
||||||
@@ -3655,8 +3655,7 @@ class WEBHOOK(Notifier):
|
|||||||
'name': 'webhook_method',
|
'name': 'webhook_method',
|
||||||
'description': 'The Webhook HTTP request method.',
|
'description': 'The Webhook HTTP request method.',
|
||||||
'input_type': 'select',
|
'input_type': 'select',
|
||||||
'select_options': {'': '',
|
'select_options': {'GET': 'GET',
|
||||||
'GET': 'GET',
|
|
||||||
'POST': 'POST',
|
'POST': 'POST',
|
||||||
'PUT': 'PUT',
|
'PUT': 'PUT',
|
||||||
'DELETE': 'DELETE'}
|
'DELETE': 'DELETE'}
|
||||||
|
@@ -571,7 +571,8 @@ class PmsConnect(object):
|
|||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def get_metadata_details(self, rating_key='', sync_id='', cache_key=None, media_info=True):
|
def get_metadata_details(self, rating_key='', sync_id='', plex_guid='',
|
||||||
|
skip_cache=False, cache_key=None, return_cache=False, media_info=True):
|
||||||
"""
|
"""
|
||||||
Return processed and validated metadata list for requested item.
|
Return processed and validated metadata list for requested item.
|
||||||
|
|
||||||
@@ -581,7 +582,7 @@ class PmsConnect(object):
|
|||||||
"""
|
"""
|
||||||
metadata = {}
|
metadata = {}
|
||||||
|
|
||||||
if cache_key:
|
if not skip_cache and cache_key:
|
||||||
in_file_folder = os.path.join(plexpy.CONFIG.CACHE_DIR, 'session_metadata')
|
in_file_folder = os.path.join(plexpy.CONFIG.CACHE_DIR, 'session_metadata')
|
||||||
in_file_path = os.path.join(in_file_folder, 'metadata-sessionKey-%s.json' % cache_key)
|
in_file_path = os.path.join(in_file_folder, 'metadata-sessionKey-%s.json' % cache_key)
|
||||||
|
|
||||||
@@ -596,14 +597,18 @@ class PmsConnect(object):
|
|||||||
|
|
||||||
if metadata:
|
if metadata:
|
||||||
_cache_time = metadata.pop('_cache_time', 0)
|
_cache_time = metadata.pop('_cache_time', 0)
|
||||||
# Return cached metadata if less than METADATA_CACHE_SECONDS ago
|
# Return cached metadata if less than cache_seconds ago
|
||||||
if int(time.time()) - _cache_time <= plexpy.CONFIG.METADATA_CACHE_SECONDS:
|
if return_cache or int(time.time()) - _cache_time <= plexpy.CONFIG.METADATA_CACHE_SECONDS:
|
||||||
return metadata
|
return metadata
|
||||||
|
|
||||||
if rating_key:
|
if rating_key:
|
||||||
metadata_xml = self.get_metadata(str(rating_key), output_format='xml')
|
metadata_xml = self.get_metadata(str(rating_key), output_format='xml')
|
||||||
elif sync_id:
|
elif sync_id:
|
||||||
metadata_xml = self.get_sync_item(str(sync_id), output_format='xml')
|
metadata_xml = self.get_sync_item(str(sync_id), output_format='xml')
|
||||||
|
elif plex_guid.startswith(('plex://movie', 'plex://episode')):
|
||||||
|
rating_key = plex_guid.rsplit('/', 1)[-1]
|
||||||
|
plextv_metadata = PmsConnect(url='https://metadata.provider.plex.tv', token=plexpy.CONFIG.PMS_TOKEN)
|
||||||
|
metadata_xml = plextv_metadata.get_metadata(rating_key, output_format='xml')
|
||||||
else:
|
else:
|
||||||
return metadata
|
return metadata
|
||||||
|
|
||||||
@@ -719,7 +724,8 @@ class PmsConnect(object):
|
|||||||
'labels': labels,
|
'labels': labels,
|
||||||
'collections': collections,
|
'collections': collections,
|
||||||
'full_title': helpers.get_xml_attr(metadata_main, 'title'),
|
'full_title': helpers.get_xml_attr(metadata_main, 'title'),
|
||||||
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount')
|
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount'),
|
||||||
|
'live': int(helpers.get_xml_attr(metadata_main, 'live') == '1')
|
||||||
}
|
}
|
||||||
|
|
||||||
elif metadata_type == 'show':
|
elif metadata_type == 'show':
|
||||||
@@ -771,12 +777,19 @@ class PmsConnect(object):
|
|||||||
'labels': labels,
|
'labels': labels,
|
||||||
'collections': collections,
|
'collections': collections,
|
||||||
'full_title': helpers.get_xml_attr(metadata_main, 'title'),
|
'full_title': helpers.get_xml_attr(metadata_main, 'title'),
|
||||||
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount')
|
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount'),
|
||||||
|
'live': int(helpers.get_xml_attr(metadata_main, 'live') == '1')
|
||||||
}
|
}
|
||||||
|
|
||||||
elif metadata_type == 'season':
|
elif metadata_type == 'season':
|
||||||
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
|
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
|
||||||
|
parent_guid = helpers.get_xml_attr(metadata_main, 'parentGuid')
|
||||||
|
show_details = {}
|
||||||
|
if plex_guid and parent_guid:
|
||||||
|
show_details = self.get_metadata_details(plex_guid=parent_guid)
|
||||||
|
elif not plex_guid and parent_rating_key:
|
||||||
show_details = self.get_metadata_details(parent_rating_key)
|
show_details = self.get_metadata_details(parent_rating_key)
|
||||||
|
|
||||||
metadata = {'media_type': metadata_type,
|
metadata = {'media_type': metadata_type,
|
||||||
'section_id': section_id,
|
'section_id': section_id,
|
||||||
'library_name': library_name,
|
'library_name': library_name,
|
||||||
@@ -790,22 +803,22 @@ class PmsConnect(object):
|
|||||||
'sort_title': helpers.get_xml_attr(metadata_main, 'titleSort'),
|
'sort_title': helpers.get_xml_attr(metadata_main, 'titleSort'),
|
||||||
'media_index': helpers.get_xml_attr(metadata_main, 'index'),
|
'media_index': helpers.get_xml_attr(metadata_main, 'index'),
|
||||||
'parent_media_index': helpers.get_xml_attr(metadata_main, 'parentIndex'),
|
'parent_media_index': helpers.get_xml_attr(metadata_main, 'parentIndex'),
|
||||||
'studio': show_details['studio'],
|
'studio': show_details.get('studio', ''),
|
||||||
'content_rating': show_details['content_rating'],
|
'content_rating': show_details.get('content_rating', ''),
|
||||||
'summary': show_details['summary'],
|
'summary': show_details.get('summary', ''),
|
||||||
'tagline': helpers.get_xml_attr(metadata_main, 'tagline'),
|
'tagline': helpers.get_xml_attr(metadata_main, 'tagline'),
|
||||||
'rating': helpers.get_xml_attr(metadata_main, 'rating'),
|
'rating': helpers.get_xml_attr(metadata_main, 'rating'),
|
||||||
'rating_image': helpers.get_xml_attr(metadata_main, 'ratingImage'),
|
'rating_image': helpers.get_xml_attr(metadata_main, 'ratingImage'),
|
||||||
'audience_rating': helpers.get_xml_attr(metadata_main, 'audienceRating'),
|
'audience_rating': helpers.get_xml_attr(metadata_main, 'audienceRating'),
|
||||||
'audience_rating_image': helpers.get_xml_attr(metadata_main, 'audienceRatingImage'),
|
'audience_rating_image': helpers.get_xml_attr(metadata_main, 'audienceRatingImage'),
|
||||||
'user_rating': helpers.get_xml_attr(metadata_main, 'userRating'),
|
'user_rating': helpers.get_xml_attr(metadata_main, 'userRating'),
|
||||||
'duration': show_details['duration'],
|
'duration': show_details.get('duration', ''),
|
||||||
'year': helpers.get_xml_attr(metadata_main, 'year'),
|
'year': helpers.get_xml_attr(metadata_main, 'year'),
|
||||||
'thumb': helpers.get_xml_attr(metadata_main, 'thumb'),
|
'thumb': helpers.get_xml_attr(metadata_main, 'thumb'),
|
||||||
'parent_thumb': helpers.get_xml_attr(metadata_main, 'parentThumb'),
|
'parent_thumb': helpers.get_xml_attr(metadata_main, 'parentThumb'),
|
||||||
'grandparent_thumb': helpers.get_xml_attr(metadata_main, 'grandparentThumb'),
|
'grandparent_thumb': helpers.get_xml_attr(metadata_main, 'grandparentThumb'),
|
||||||
'art': helpers.get_xml_attr(metadata_main, 'art'),
|
'art': helpers.get_xml_attr(metadata_main, 'art'),
|
||||||
'banner': show_details['banner'],
|
'banner': show_details.get('banner', ''),
|
||||||
'originally_available_at': helpers.get_xml_attr(metadata_main, 'originallyAvailableAt'),
|
'originally_available_at': helpers.get_xml_attr(metadata_main, 'originallyAvailableAt'),
|
||||||
'added_at': helpers.get_xml_attr(metadata_main, 'addedAt'),
|
'added_at': helpers.get_xml_attr(metadata_main, 'addedAt'),
|
||||||
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
||||||
@@ -813,32 +826,38 @@ class PmsConnect(object):
|
|||||||
'guid': helpers.get_xml_attr(metadata_main, 'guid'),
|
'guid': helpers.get_xml_attr(metadata_main, 'guid'),
|
||||||
'parent_guid': helpers.get_xml_attr(metadata_main, 'parentGuid'),
|
'parent_guid': helpers.get_xml_attr(metadata_main, 'parentGuid'),
|
||||||
'grandparent_guid': helpers.get_xml_attr(metadata_main, 'grandparentGuid'),
|
'grandparent_guid': helpers.get_xml_attr(metadata_main, 'grandparentGuid'),
|
||||||
'directors': show_details['directors'],
|
'directors': show_details.get('directors', []),
|
||||||
'writers': show_details['writers'],
|
'writers': show_details.get('writers', []),
|
||||||
'actors': show_details['actors'],
|
'actors': show_details.get('actors', []),
|
||||||
'genres': show_details['genres'],
|
'genres': show_details.get('genres', []),
|
||||||
'labels': show_details['labels'],
|
'labels': show_details.get('labels', []),
|
||||||
'collections': show_details['collections'],
|
'collections': show_details.get('collections', []),
|
||||||
'full_title': u'{} - {}'.format(helpers.get_xml_attr(metadata_main, 'parentTitle'),
|
'full_title': u'{} - {}'.format(helpers.get_xml_attr(metadata_main, 'parentTitle'),
|
||||||
helpers.get_xml_attr(metadata_main, 'title')),
|
helpers.get_xml_attr(metadata_main, 'title')),
|
||||||
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount')
|
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount'),
|
||||||
|
'live': int(helpers.get_xml_attr(metadata_main, 'live') == '1')
|
||||||
}
|
}
|
||||||
|
|
||||||
elif metadata_type == 'episode':
|
elif metadata_type == 'episode':
|
||||||
grandparent_rating_key = helpers.get_xml_attr(metadata_main, 'grandparentRatingKey')
|
grandparent_rating_key = helpers.get_xml_attr(metadata_main, 'grandparentRatingKey')
|
||||||
|
grandparent_guid = helpers.get_xml_attr(metadata_main, 'grandparentGuid')
|
||||||
|
show_details = {}
|
||||||
|
if plex_guid and grandparent_guid:
|
||||||
|
show_details = self.get_metadata_details(plex_guid=grandparent_guid)
|
||||||
|
elif not plex_guid and grandparent_rating_key:
|
||||||
show_details = self.get_metadata_details(grandparent_rating_key)
|
show_details = self.get_metadata_details(grandparent_rating_key)
|
||||||
|
|
||||||
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
|
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
|
||||||
parent_media_index = helpers.get_xml_attr(metadata_main, 'parentIndex')
|
parent_media_index = helpers.get_xml_attr(metadata_main, 'parentIndex')
|
||||||
parent_thumb = helpers.get_xml_attr(metadata_main, 'parentThumb')
|
parent_thumb = helpers.get_xml_attr(metadata_main, 'parentThumb')
|
||||||
|
|
||||||
if not parent_rating_key:
|
if not plex_guid and not parent_rating_key:
|
||||||
# Try getting the parent_rating_key from the parent_thumb
|
# Try getting the parent_rating_key from the parent_thumb
|
||||||
if parent_thumb.startswith('/library/metadata/'):
|
if parent_thumb.startswith('/library/metadata/'):
|
||||||
parent_rating_key = parent_thumb.split('/')[3]
|
parent_rating_key = parent_thumb.split('/')[3]
|
||||||
|
|
||||||
# Try getting the parent_rating_key from the grandparent's children
|
# Try getting the parent_rating_key from the grandparent's children
|
||||||
if not parent_rating_key:
|
if not parent_rating_key and grandparent_rating_key:
|
||||||
children_list = self.get_item_children(grandparent_rating_key)
|
children_list = self.get_item_children(grandparent_rating_key)
|
||||||
parent_rating_key = next((c['rating_key'] for c in children_list['children_list']
|
parent_rating_key = next((c['rating_key'] for c in children_list['children_list']
|
||||||
if c['media_index'] == parent_media_index), '')
|
if c['media_index'] == parent_media_index), '')
|
||||||
@@ -856,7 +875,7 @@ class PmsConnect(object):
|
|||||||
'sort_title': helpers.get_xml_attr(metadata_main, 'titleSort'),
|
'sort_title': helpers.get_xml_attr(metadata_main, 'titleSort'),
|
||||||
'media_index': helpers.get_xml_attr(metadata_main, 'index'),
|
'media_index': helpers.get_xml_attr(metadata_main, 'index'),
|
||||||
'parent_media_index': parent_media_index,
|
'parent_media_index': parent_media_index,
|
||||||
'studio': show_details['studio'],
|
'studio': show_details.get('studio', ''),
|
||||||
'content_rating': helpers.get_xml_attr(metadata_main, 'contentRating'),
|
'content_rating': helpers.get_xml_attr(metadata_main, 'contentRating'),
|
||||||
'summary': helpers.get_xml_attr(metadata_main, 'summary'),
|
'summary': helpers.get_xml_attr(metadata_main, 'summary'),
|
||||||
'tagline': helpers.get_xml_attr(metadata_main, 'tagline'),
|
'tagline': helpers.get_xml_attr(metadata_main, 'tagline'),
|
||||||
@@ -871,7 +890,7 @@ class PmsConnect(object):
|
|||||||
'parent_thumb': parent_thumb,
|
'parent_thumb': parent_thumb,
|
||||||
'grandparent_thumb': helpers.get_xml_attr(metadata_main, 'grandparentThumb'),
|
'grandparent_thumb': helpers.get_xml_attr(metadata_main, 'grandparentThumb'),
|
||||||
'art': helpers.get_xml_attr(metadata_main, 'art'),
|
'art': helpers.get_xml_attr(metadata_main, 'art'),
|
||||||
'banner': show_details['banner'],
|
'banner': show_details.get('banner', ''),
|
||||||
'originally_available_at': helpers.get_xml_attr(metadata_main, 'originallyAvailableAt'),
|
'originally_available_at': helpers.get_xml_attr(metadata_main, 'originallyAvailableAt'),
|
||||||
'added_at': helpers.get_xml_attr(metadata_main, 'addedAt'),
|
'added_at': helpers.get_xml_attr(metadata_main, 'addedAt'),
|
||||||
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
||||||
@@ -881,13 +900,14 @@ class PmsConnect(object):
|
|||||||
'grandparent_guid': helpers.get_xml_attr(metadata_main, 'grandparentGuid'),
|
'grandparent_guid': helpers.get_xml_attr(metadata_main, 'grandparentGuid'),
|
||||||
'directors': directors,
|
'directors': directors,
|
||||||
'writers': writers,
|
'writers': writers,
|
||||||
'actors': show_details['actors'],
|
'actors': show_details.get('actors', []),
|
||||||
'genres': show_details['genres'],
|
'genres': show_details.get('genres', []),
|
||||||
'labels': show_details['labels'],
|
'labels': show_details.get('labels', []),
|
||||||
'collections': show_details['collections'],
|
'collections': show_details.get('collections', []),
|
||||||
'full_title': u'{} - {}'.format(helpers.get_xml_attr(metadata_main, 'grandparentTitle'),
|
'full_title': u'{} - {}'.format(helpers.get_xml_attr(metadata_main, 'grandparentTitle'),
|
||||||
helpers.get_xml_attr(metadata_main, 'title')),
|
helpers.get_xml_attr(metadata_main, 'title')),
|
||||||
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount')
|
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount'),
|
||||||
|
'live': int(helpers.get_xml_attr(metadata_main, 'live') == '1')
|
||||||
}
|
}
|
||||||
|
|
||||||
elif metadata_type == 'artist':
|
elif metadata_type == 'artist':
|
||||||
@@ -934,12 +954,13 @@ class PmsConnect(object):
|
|||||||
'labels': labels,
|
'labels': labels,
|
||||||
'collections': collections,
|
'collections': collections,
|
||||||
'full_title': helpers.get_xml_attr(metadata_main, 'title'),
|
'full_title': helpers.get_xml_attr(metadata_main, 'title'),
|
||||||
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount')
|
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount'),
|
||||||
|
'live': int(helpers.get_xml_attr(metadata_main, 'live') == '1')
|
||||||
}
|
}
|
||||||
|
|
||||||
elif metadata_type == 'album':
|
elif metadata_type == 'album':
|
||||||
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
|
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
|
||||||
artist_details = self.get_metadata_details(parent_rating_key)
|
artist_details = self.get_metadata_details(parent_rating_key) if parent_rating_key else {}
|
||||||
metadata = {'media_type': metadata_type,
|
metadata = {'media_type': metadata_type,
|
||||||
'section_id': section_id,
|
'section_id': section_id,
|
||||||
'library_name': library_name,
|
'library_name': library_name,
|
||||||
@@ -955,7 +976,7 @@ class PmsConnect(object):
|
|||||||
'parent_media_index': helpers.get_xml_attr(metadata_main, 'parentIndex'),
|
'parent_media_index': helpers.get_xml_attr(metadata_main, 'parentIndex'),
|
||||||
'studio': helpers.get_xml_attr(metadata_main, 'studio'),
|
'studio': helpers.get_xml_attr(metadata_main, 'studio'),
|
||||||
'content_rating': helpers.get_xml_attr(metadata_main, 'contentRating'),
|
'content_rating': helpers.get_xml_attr(metadata_main, 'contentRating'),
|
||||||
'summary': helpers.get_xml_attr(metadata_main, 'summary') or artist_details['summary'],
|
'summary': helpers.get_xml_attr(metadata_main, 'summary') or artist_details.get('summary', ''),
|
||||||
'tagline': helpers.get_xml_attr(metadata_main, 'tagline'),
|
'tagline': helpers.get_xml_attr(metadata_main, 'tagline'),
|
||||||
'rating': helpers.get_xml_attr(metadata_main, 'rating'),
|
'rating': helpers.get_xml_attr(metadata_main, 'rating'),
|
||||||
'rating_image': helpers.get_xml_attr(metadata_main, 'ratingImage'),
|
'rating_image': helpers.get_xml_attr(metadata_main, 'ratingImage'),
|
||||||
@@ -968,7 +989,7 @@ class PmsConnect(object):
|
|||||||
'parent_thumb': helpers.get_xml_attr(metadata_main, 'parentThumb'),
|
'parent_thumb': helpers.get_xml_attr(metadata_main, 'parentThumb'),
|
||||||
'grandparent_thumb': helpers.get_xml_attr(metadata_main, 'grandparentThumb'),
|
'grandparent_thumb': helpers.get_xml_attr(metadata_main, 'grandparentThumb'),
|
||||||
'art': helpers.get_xml_attr(metadata_main, 'art'),
|
'art': helpers.get_xml_attr(metadata_main, 'art'),
|
||||||
'banner': artist_details['banner'],
|
'banner': artist_details.get('banner', ''),
|
||||||
'originally_available_at': helpers.get_xml_attr(metadata_main, 'originallyAvailableAt'),
|
'originally_available_at': helpers.get_xml_attr(metadata_main, 'originallyAvailableAt'),
|
||||||
'added_at': helpers.get_xml_attr(metadata_main, 'addedAt'),
|
'added_at': helpers.get_xml_attr(metadata_main, 'addedAt'),
|
||||||
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
||||||
@@ -984,12 +1005,13 @@ class PmsConnect(object):
|
|||||||
'collections': collections,
|
'collections': collections,
|
||||||
'full_title': u'{} - {}'.format(helpers.get_xml_attr(metadata_main, 'parentTitle'),
|
'full_title': u'{} - {}'.format(helpers.get_xml_attr(metadata_main, 'parentTitle'),
|
||||||
helpers.get_xml_attr(metadata_main, 'title')),
|
helpers.get_xml_attr(metadata_main, 'title')),
|
||||||
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount')
|
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount'),
|
||||||
|
'live': int(helpers.get_xml_attr(metadata_main, 'live') == '1')
|
||||||
}
|
}
|
||||||
|
|
||||||
elif metadata_type == 'track':
|
elif metadata_type == 'track':
|
||||||
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
|
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
|
||||||
album_details = self.get_metadata_details(parent_rating_key)
|
album_details = self.get_metadata_details(parent_rating_key) if parent_rating_key else {}
|
||||||
track_artist = helpers.get_xml_attr(metadata_main, 'originalTitle') or \
|
track_artist = helpers.get_xml_attr(metadata_main, 'originalTitle') or \
|
||||||
helpers.get_xml_attr(metadata_main, 'grandparentTitle')
|
helpers.get_xml_attr(metadata_main, 'grandparentTitle')
|
||||||
metadata = {'media_type': metadata_type,
|
metadata = {'media_type': metadata_type,
|
||||||
@@ -1015,12 +1037,12 @@ class PmsConnect(object):
|
|||||||
'audience_rating_image': helpers.get_xml_attr(metadata_main, 'audienceRatingImage'),
|
'audience_rating_image': helpers.get_xml_attr(metadata_main, 'audienceRatingImage'),
|
||||||
'user_rating': helpers.get_xml_attr(metadata_main, 'userRating'),
|
'user_rating': helpers.get_xml_attr(metadata_main, 'userRating'),
|
||||||
'duration': helpers.get_xml_attr(metadata_main, 'duration'),
|
'duration': helpers.get_xml_attr(metadata_main, 'duration'),
|
||||||
'year': album_details['year'],
|
'year': album_details.get('year', ''),
|
||||||
'thumb': helpers.get_xml_attr(metadata_main, 'thumb'),
|
'thumb': helpers.get_xml_attr(metadata_main, 'thumb'),
|
||||||
'parent_thumb': helpers.get_xml_attr(metadata_main, 'parentThumb'),
|
'parent_thumb': helpers.get_xml_attr(metadata_main, 'parentThumb'),
|
||||||
'grandparent_thumb': helpers.get_xml_attr(metadata_main, 'grandparentThumb'),
|
'grandparent_thumb': helpers.get_xml_attr(metadata_main, 'grandparentThumb'),
|
||||||
'art': helpers.get_xml_attr(metadata_main, 'art'),
|
'art': helpers.get_xml_attr(metadata_main, 'art'),
|
||||||
'banner': album_details['banner'],
|
'banner': album_details.get('banner', ''),
|
||||||
'originally_available_at': helpers.get_xml_attr(metadata_main, 'originallyAvailableAt'),
|
'originally_available_at': helpers.get_xml_attr(metadata_main, 'originallyAvailableAt'),
|
||||||
'added_at': helpers.get_xml_attr(metadata_main, 'addedAt'),
|
'added_at': helpers.get_xml_attr(metadata_main, 'addedAt'),
|
||||||
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
||||||
@@ -1031,12 +1053,13 @@ class PmsConnect(object):
|
|||||||
'directors': directors,
|
'directors': directors,
|
||||||
'writers': writers,
|
'writers': writers,
|
||||||
'actors': actors,
|
'actors': actors,
|
||||||
'genres': album_details['genres'],
|
'genres': album_details.get('genres', []),
|
||||||
'labels': album_details['labels'],
|
'labels': album_details.get('labels', []),
|
||||||
'collections': album_details['collections'],
|
'collections': album_details.get('collections', []),
|
||||||
'full_title': u'{} - {}'.format(helpers.get_xml_attr(metadata_main, 'title'),
|
'full_title': u'{} - {}'.format(helpers.get_xml_attr(metadata_main, 'title'),
|
||||||
track_artist),
|
track_artist),
|
||||||
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount')
|
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount'),
|
||||||
|
'live': int(helpers.get_xml_attr(metadata_main, 'live') == '1')
|
||||||
}
|
}
|
||||||
|
|
||||||
elif metadata_type == 'photo_album':
|
elif metadata_type == 'photo_album':
|
||||||
@@ -1083,12 +1106,13 @@ class PmsConnect(object):
|
|||||||
'labels': labels,
|
'labels': labels,
|
||||||
'collections': collections,
|
'collections': collections,
|
||||||
'full_title': helpers.get_xml_attr(metadata_main, 'title'),
|
'full_title': helpers.get_xml_attr(metadata_main, 'title'),
|
||||||
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount')
|
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount'),
|
||||||
|
'live': int(helpers.get_xml_attr(metadata_main, 'live') == '1')
|
||||||
}
|
}
|
||||||
|
|
||||||
elif metadata_type == 'photo':
|
elif metadata_type == 'photo':
|
||||||
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
|
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
|
||||||
photo_album_details = self.get_metadata_details(parent_rating_key)
|
photo_album_details = self.get_metadata_details(parent_rating_key) if parent_rating_key else {}
|
||||||
metadata = {'media_type': metadata_type,
|
metadata = {'media_type': metadata_type,
|
||||||
'section_id': section_id,
|
'section_id': section_id,
|
||||||
'library_name': library_name,
|
'library_name': library_name,
|
||||||
@@ -1128,12 +1152,13 @@ class PmsConnect(object):
|
|||||||
'directors': directors,
|
'directors': directors,
|
||||||
'writers': writers,
|
'writers': writers,
|
||||||
'actors': actors,
|
'actors': actors,
|
||||||
'genres': photo_album_details.get('genres', ''),
|
'genres': photo_album_details.get('genres', []),
|
||||||
'labels': photo_album_details.get('labels', ''),
|
'labels': photo_album_details.get('labels', []),
|
||||||
'collections': photo_album_details.get('collections', ''),
|
'collections': photo_album_details.get('collections', []),
|
||||||
'full_title': u'{} - {}'.format(helpers.get_xml_attr(metadata_main, 'parentTitle') or library_name,
|
'full_title': u'{} - {}'.format(helpers.get_xml_attr(metadata_main, 'parentTitle') or library_name,
|
||||||
helpers.get_xml_attr(metadata_main, 'title')),
|
helpers.get_xml_attr(metadata_main, 'title')),
|
||||||
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount')
|
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount'),
|
||||||
|
'live': int(helpers.get_xml_attr(metadata_main, 'live') == '1')
|
||||||
}
|
}
|
||||||
|
|
||||||
elif metadata_type == 'collection':
|
elif metadata_type == 'collection':
|
||||||
@@ -1184,7 +1209,8 @@ class PmsConnect(object):
|
|||||||
'labels': labels,
|
'labels': labels,
|
||||||
'collections': collections,
|
'collections': collections,
|
||||||
'full_title': helpers.get_xml_attr(metadata_main, 'title'),
|
'full_title': helpers.get_xml_attr(metadata_main, 'title'),
|
||||||
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount')
|
'children_count': helpers.get_xml_attr(metadata_main, 'leafCount'),
|
||||||
|
'live': int(helpers.get_xml_attr(metadata_main, 'live') == '1')
|
||||||
}
|
}
|
||||||
|
|
||||||
elif metadata_type == 'clip':
|
elif metadata_type == 'clip':
|
||||||
@@ -1232,17 +1258,31 @@ class PmsConnect(object):
|
|||||||
'collections': collections,
|
'collections': collections,
|
||||||
'full_title': helpers.get_xml_attr(metadata_main, 'title'),
|
'full_title': helpers.get_xml_attr(metadata_main, 'title'),
|
||||||
'extra_type': helpers.get_xml_attr(metadata_main, 'extraType'),
|
'extra_type': helpers.get_xml_attr(metadata_main, 'extraType'),
|
||||||
'sub_type': helpers.get_xml_attr(metadata_main, 'subtype')
|
'sub_type': helpers.get_xml_attr(metadata_main, 'subtype'),
|
||||||
|
'live': int(helpers.get_xml_attr(metadata_main, 'live') == '1')
|
||||||
}
|
}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return metadata
|
return metadata
|
||||||
|
|
||||||
|
# Get additional metadata from metadata.provider.plex.tv
|
||||||
|
if not plex_guid and metadata['live']:
|
||||||
|
metadata['section_id'] = common.LIVE_TV_SECTION_ID
|
||||||
|
metadata['library_name'] = common.LIVE_TV_SECTION_NAME
|
||||||
|
|
||||||
|
plextv_metadata = self.get_metadata_details(plex_guid=metadata['guid'])
|
||||||
|
if plextv_metadata:
|
||||||
|
keys_to_update = ['summary', 'rating', 'thumb', 'grandparent_thumb', 'duration',
|
||||||
|
'guid', 'grandparent_guid', 'genres']
|
||||||
|
for key in keys_to_update:
|
||||||
|
metadata[key] = plextv_metadata[key]
|
||||||
|
metadata['originally_available_at'] = helpers.iso_to_YMD(plextv_metadata['originally_available_at'])
|
||||||
|
|
||||||
if metadata and media_info:
|
if metadata and media_info:
|
||||||
medias = []
|
medias = []
|
||||||
media_items = metadata_main.getElementsByTagName('Media')
|
media_items = metadata_main.getElementsByTagName('Media')
|
||||||
for media in media_items:
|
for media in media_items:
|
||||||
video_full_resolution_scan_type = None
|
video_full_resolution_scan_type = ''
|
||||||
|
|
||||||
parts = []
|
parts = []
|
||||||
part_items = media.getElementsByTagName('Part')
|
part_items = media.getElementsByTagName('Part')
|
||||||
@@ -1253,8 +1293,7 @@ class PmsConnect(object):
|
|||||||
for stream in stream_items:
|
for stream in stream_items:
|
||||||
if helpers.get_xml_attr(stream, 'streamType') == '1':
|
if helpers.get_xml_attr(stream, 'streamType') == '1':
|
||||||
video_scan_type = helpers.get_xml_attr(stream, 'scanType')
|
video_scan_type = helpers.get_xml_attr(stream, 'scanType')
|
||||||
if video_full_resolution_scan_type is None:
|
video_full_resolution_scan_type = (video_full_resolution_scan_type or video_scan_type)
|
||||||
video_full_resolution_scan_type = video_scan_type
|
|
||||||
|
|
||||||
streams.append({'id': helpers.get_xml_attr(stream, 'id'),
|
streams.append({'id': helpers.get_xml_attr(stream, 'id'),
|
||||||
'type': helpers.get_xml_attr(stream, 'streamType'),
|
'type': helpers.get_xml_attr(stream, 'streamType'),
|
||||||
@@ -1314,16 +1353,14 @@ class PmsConnect(object):
|
|||||||
'selected': int(helpers.get_xml_attr(part, 'selected') == '1')
|
'selected': int(helpers.get_xml_attr(part, 'selected') == '1')
|
||||||
})
|
})
|
||||||
|
|
||||||
video_resolution = helpers.get_xml_attr(media, 'videoResolution').lower()
|
video_resolution = helpers.get_xml_attr(media, 'videoResolution').lower().rstrip('ip')
|
||||||
video_full_resolution = ''
|
|
||||||
if video_full_resolution_scan_type is not None:
|
|
||||||
video_full_resolution = common.VIDEO_RESOLUTION_OVERRIDES.get(
|
video_full_resolution = common.VIDEO_RESOLUTION_OVERRIDES.get(
|
||||||
video_resolution, video_resolution + (video_full_resolution_scan_type[:1] or 'p')
|
video_resolution, video_resolution + (video_full_resolution_scan_type[:1] or 'p')
|
||||||
)
|
)
|
||||||
|
|
||||||
audio_channels = helpers.get_xml_attr(media, 'audioChannels')
|
audio_channels = helpers.get_xml_attr(media, 'audioChannels')
|
||||||
|
|
||||||
medias.append({'id': helpers.get_xml_attr(media, 'id'),
|
media_info = {'id': helpers.get_xml_attr(media, 'id'),
|
||||||
'container': helpers.get_xml_attr(media, 'container'),
|
'container': helpers.get_xml_attr(media, 'container'),
|
||||||
'bitrate': helpers.get_xml_attr(media, 'bitrate'),
|
'bitrate': helpers.get_xml_attr(media, 'bitrate'),
|
||||||
'height': helpers.get_xml_attr(media, 'height'),
|
'height': helpers.get_xml_attr(media, 'height'),
|
||||||
@@ -1339,10 +1376,13 @@ class PmsConnect(object):
|
|||||||
'audio_channel_layout': common.AUDIO_CHANNELS.get(audio_channels, audio_channels),
|
'audio_channel_layout': common.AUDIO_CHANNELS.get(audio_channels, audio_channels),
|
||||||
'audio_profile': helpers.get_xml_attr(media, 'audioProfile'),
|
'audio_profile': helpers.get_xml_attr(media, 'audioProfile'),
|
||||||
'optimized_version': int(helpers.get_xml_attr(media, 'proxyType') == '42'),
|
'optimized_version': int(helpers.get_xml_attr(media, 'proxyType') == '42'),
|
||||||
|
'channel_call_sign': helpers.get_xml_attr(media, 'channelCallSign'),
|
||||||
|
'channel_identifier': helpers.get_xml_attr(media, 'channelIdentifier'),
|
||||||
|
'channel_thumb': helpers.get_xml_attr(media, 'channelThumb'),
|
||||||
'parts': parts
|
'parts': parts
|
||||||
})
|
}
|
||||||
|
|
||||||
video_full_resolution = helpers.get_xml_attr(media, 'videoResolution').lower()
|
medias.append(media_info)
|
||||||
|
|
||||||
metadata['media_info'] = medias
|
metadata['media_info'] = medias
|
||||||
|
|
||||||
@@ -1464,7 +1504,7 @@ class PmsConnect(object):
|
|||||||
|
|
||||||
return metadata_list
|
return metadata_list
|
||||||
|
|
||||||
def get_current_activity(self):
|
def get_current_activity(self, skip_cache=False):
|
||||||
"""
|
"""
|
||||||
Return processed and validated session list.
|
Return processed and validated session list.
|
||||||
|
|
||||||
@@ -1491,17 +1531,17 @@ class PmsConnect(object):
|
|||||||
if a.getElementsByTagName('Track'):
|
if a.getElementsByTagName('Track'):
|
||||||
session_data = a.getElementsByTagName('Track')
|
session_data = a.getElementsByTagName('Track')
|
||||||
for session_ in session_data:
|
for session_ in session_data:
|
||||||
session_output = self.get_session_each(session_)
|
session_output = self.get_session_each(session_, skip_cache=skip_cache)
|
||||||
session_list.append(session_output)
|
session_list.append(session_output)
|
||||||
if a.getElementsByTagName('Video'):
|
if a.getElementsByTagName('Video'):
|
||||||
session_data = a.getElementsByTagName('Video')
|
session_data = a.getElementsByTagName('Video')
|
||||||
for session_ in session_data:
|
for session_ in session_data:
|
||||||
session_output = self.get_session_each(session_)
|
session_output = self.get_session_each(session_, skip_cache=skip_cache)
|
||||||
session_list.append(session_output)
|
session_list.append(session_output)
|
||||||
if a.getElementsByTagName('Photo'):
|
if a.getElementsByTagName('Photo'):
|
||||||
session_data = a.getElementsByTagName('Photo')
|
session_data = a.getElementsByTagName('Photo')
|
||||||
for session_ in session_data:
|
for session_ in session_data:
|
||||||
session_output = self.get_session_each(session_)
|
session_output = self.get_session_each(session_, skip_cache=skip_cache)
|
||||||
session_list.append(session_output)
|
session_list.append(session_output)
|
||||||
|
|
||||||
session_list = sorted(session_list, key=lambda k: k['session_key'])
|
session_list = sorted(session_list, key=lambda k: k['session_key'])
|
||||||
@@ -1512,7 +1552,7 @@ class PmsConnect(object):
|
|||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def get_session_each(self, session=None):
|
def get_session_each(self, session=None, skip_cache=False):
|
||||||
"""
|
"""
|
||||||
Return selected data from current sessions.
|
Return selected data from current sessions.
|
||||||
This function processes and validates session data
|
This function processes and validates session data
|
||||||
@@ -1788,7 +1828,7 @@ class PmsConnect(object):
|
|||||||
if helpers.cast_to_int(stream_video_width) >= 3840:
|
if helpers.cast_to_int(stream_video_width) >= 3840:
|
||||||
stream_video_resolution = '4k'
|
stream_video_resolution = '4k'
|
||||||
else:
|
else:
|
||||||
stream_video_resolution = helpers.get_xml_attr(stream_media_info, 'videoResolution').rstrip('p').lower()
|
stream_video_resolution = helpers.get_xml_attr(stream_media_info, 'videoResolution').lower().rstrip('ip')
|
||||||
|
|
||||||
stream_audio_channels = helpers.get_xml_attr(stream_media_info, 'audioChannels')
|
stream_audio_channels = helpers.get_xml_attr(stream_media_info, 'audioChannels')
|
||||||
|
|
||||||
@@ -1865,13 +1905,19 @@ class PmsConnect(object):
|
|||||||
'full_title': helpers.get_xml_attr(session, 'title'),
|
'full_title': helpers.get_xml_attr(session, 'title'),
|
||||||
'container': helpers.get_xml_attr(stream_media_info, 'container') \
|
'container': helpers.get_xml_attr(stream_media_info, 'container') \
|
||||||
or helpers.get_xml_attr(stream_media_parts_info, 'container'),
|
or helpers.get_xml_attr(stream_media_parts_info, 'container'),
|
||||||
|
'bitrate': helpers.get_xml_attr(stream_media_info, 'bitrate'),
|
||||||
'height': helpers.get_xml_attr(stream_media_info, 'height'),
|
'height': helpers.get_xml_attr(stream_media_info, 'height'),
|
||||||
'width': helpers.get_xml_attr(stream_media_info, 'width'),
|
'width': helpers.get_xml_attr(stream_media_info, 'width'),
|
||||||
|
'aspect_ratio': helpers.get_xml_attr(stream_media_info, 'aspectRatio'),
|
||||||
'video_codec': helpers.get_xml_attr(stream_media_info, 'videoCodec'),
|
'video_codec': helpers.get_xml_attr(stream_media_info, 'videoCodec'),
|
||||||
'video_resolution': helpers.get_xml_attr(stream_media_info, 'videoResolution').lower(),
|
'video_resolution': helpers.get_xml_attr(stream_media_info, 'videoResolution').lower(),
|
||||||
|
'video_full_resolution': helpers.get_xml_attr(stream_media_info, 'videoResolution').lower(),
|
||||||
|
'video_framerate': helpers.get_xml_attr(stream_media_info, 'videoFrameRate'),
|
||||||
|
'video_profile': helpers.get_xml_attr(stream_media_info, 'videoProfile'),
|
||||||
'audio_codec': helpers.get_xml_attr(stream_media_info, 'audioCodec'),
|
'audio_codec': helpers.get_xml_attr(stream_media_info, 'audioCodec'),
|
||||||
'audio_channels': audio_channels,
|
'audio_channels': audio_channels,
|
||||||
'audio_channel_layout': common.AUDIO_CHANNELS.get(audio_channels, audio_channels),
|
'audio_channel_layout': common.AUDIO_CHANNELS.get(audio_channels, audio_channels),
|
||||||
|
'audio_profile': helpers.get_xml_attr(stream_media_info, 'audioProfile'),
|
||||||
'channel_icon': helpers.get_xml_attr(session, 'sourceIcon'),
|
'channel_icon': helpers.get_xml_attr(session, 'sourceIcon'),
|
||||||
'channel_title': helpers.get_xml_attr(session, 'sourceTitle'),
|
'channel_title': helpers.get_xml_attr(session, 'sourceTitle'),
|
||||||
'extra_type': helpers.get_xml_attr(session, 'extraType'),
|
'extra_type': helpers.get_xml_attr(session, 'extraType'),
|
||||||
@@ -1884,9 +1930,11 @@ class PmsConnect(object):
|
|||||||
part_id = helpers.get_xml_attr(stream_media_parts_info, 'id')
|
part_id = helpers.get_xml_attr(stream_media_parts_info, 'id')
|
||||||
|
|
||||||
if sync_id:
|
if sync_id:
|
||||||
metadata_details = self.get_metadata_details(rating_key=rating_key, sync_id=sync_id, cache_key=session_key)
|
metadata_details = self.get_metadata_details(rating_key=rating_key, sync_id=sync_id,
|
||||||
|
skip_cache=skip_cache, cache_key=session_key)
|
||||||
else:
|
else:
|
||||||
metadata_details = self.get_metadata_details(rating_key=rating_key, cache_key=session_key)
|
metadata_details = self.get_metadata_details(rating_key=rating_key,
|
||||||
|
skip_cache=skip_cache, cache_key=session_key)
|
||||||
|
|
||||||
# Get the media info, fallback to first item if match id is not found
|
# Get the media info, fallback to first item if match id is not found
|
||||||
source_medias = metadata_details.pop('media_info', [])
|
source_medias = metadata_details.pop('media_info', [])
|
||||||
@@ -1973,15 +2021,15 @@ class PmsConnect(object):
|
|||||||
|
|
||||||
# Override * in audio codecs
|
# Override * in audio codecs
|
||||||
if stream_details['stream_audio_codec'] == '*':
|
if stream_details['stream_audio_codec'] == '*':
|
||||||
stream_details['stream_audio_codec'] = source_audio_details['audio_codec']
|
stream_details['stream_audio_codec'] = source_audio_details.get('audio_codec', '')
|
||||||
if transcode_details['transcode_audio_codec'] == '*':
|
if transcode_details['transcode_audio_codec'] == '*':
|
||||||
transcode_details['transcode_audio_codec'] = source_audio_details['audio_codec']
|
transcode_details['transcode_audio_codec'] = source_audio_details.get('audio_codec', '')
|
||||||
|
|
||||||
# Override * in video codecs
|
# Override * in video codecs
|
||||||
if stream_details['stream_video_codec'] == '*':
|
if stream_details['stream_video_codec'] == '*':
|
||||||
stream_details['stream_video_codec'] = source_video_details['video_codec']
|
stream_details['stream_video_codec'] = source_video_details.get('video_codec', '')
|
||||||
if transcode_details['transcode_video_codec'] == '*':
|
if transcode_details['transcode_video_codec'] == '*':
|
||||||
transcode_details['transcode_video_codec'] = source_video_details['video_codec']
|
transcode_details['transcode_video_codec'] = source_video_details.get('video_codec', '')
|
||||||
|
|
||||||
if media_type in ('movie', 'episode', 'clip'):
|
if media_type in ('movie', 'episode', 'clip'):
|
||||||
# Set the full resolution by combining stream_video_resolution and stream_video_scan_type
|
# Set the full resolution by combining stream_video_resolution and stream_video_scan_type
|
||||||
@@ -1989,8 +2037,8 @@ class PmsConnect(object):
|
|||||||
stream_details['stream_video_resolution'],
|
stream_details['stream_video_resolution'],
|
||||||
stream_details['stream_video_resolution'] + (video_details['stream_video_scan_type'][:1] or 'p'))
|
stream_details['stream_video_resolution'] + (video_details['stream_video_scan_type'][:1] or 'p'))
|
||||||
|
|
||||||
if helpers.cast_to_int(source_video_details['video_bit_depth']) > 8 \
|
if helpers.cast_to_int(source_video_details.get('video_bit_depth')) > 8 \
|
||||||
and source_video_details['video_color_space'] == 'bt2020nc':
|
and source_video_details.get('video_color_space') == 'bt2020nc':
|
||||||
stream_details['video_dynamic_range'] = 'HDR'
|
stream_details['video_dynamic_range'] = 'HDR'
|
||||||
else:
|
else:
|
||||||
stream_details['video_dynamic_range'] = 'SDR'
|
stream_details['video_dynamic_range'] = 'SDR'
|
||||||
@@ -2032,7 +2080,7 @@ class PmsConnect(object):
|
|||||||
if stream_details['optimized_version']:
|
if stream_details['optimized_version']:
|
||||||
source_bitrate = helpers.cast_to_int(source_media_details.get('bitrate'))
|
source_bitrate = helpers.cast_to_int(source_media_details.get('bitrate'))
|
||||||
optimized_version_profile = '{} Mbps {}'.format(round(source_bitrate / 1000.0, 1),
|
optimized_version_profile = '{} Mbps {}'.format(round(source_bitrate / 1000.0, 1),
|
||||||
source_media_details['video_full_resolution'])
|
source_media_details.get('video_full_resolution'))
|
||||||
else:
|
else:
|
||||||
optimized_version_profile = ''
|
optimized_version_profile = ''
|
||||||
|
|
||||||
@@ -2681,10 +2729,14 @@ class PmsConnect(object):
|
|||||||
height = height or 1500
|
height = height or 1500
|
||||||
|
|
||||||
if img:
|
if img:
|
||||||
if refresh:
|
web_img = img.startswith('http')
|
||||||
|
|
||||||
|
if refresh and not web_img:
|
||||||
img = '{}/{}'.format(img.rstrip('/'), int(time.time()))
|
img = '{}/{}'.format(img.rstrip('/'), int(time.time()))
|
||||||
|
|
||||||
if clip:
|
if web_img:
|
||||||
|
params = {'url': '%s' % img}
|
||||||
|
elif clip:
|
||||||
params = {'url': '%s&%s' % (img, urllib.urlencode({'X-Plex-Token': self.token}))}
|
params = {'url': '%s&%s' % (img, urllib.urlencode({'X-Plex-Token': self.token}))}
|
||||||
else:
|
else:
|
||||||
params = {'url': 'http://127.0.0.1:32400%s?%s' % (img, urllib.urlencode({'X-Plex-Token': self.token}))}
|
params = {'url': 'http://127.0.0.1:32400%s?%s' % (img, urllib.urlencode({'X-Plex-Token': self.token}))}
|
||||||
|
@@ -116,6 +116,10 @@ class Users(object):
|
|||||||
'session_history_metadata.year',
|
'session_history_metadata.year',
|
||||||
'session_history_metadata.media_index',
|
'session_history_metadata.media_index',
|
||||||
'session_history_metadata.parent_media_index',
|
'session_history_metadata.parent_media_index',
|
||||||
|
'session_history_metadata.live',
|
||||||
|
'session_history_metadata.added_at',
|
||||||
|
'session_history_metadata.originally_available_at',
|
||||||
|
'session_history_metadata.guid',
|
||||||
'session_history_media_info.transcode_decision',
|
'session_history_media_info.transcode_decision',
|
||||||
'users.do_notify as do_notify',
|
'users.do_notify as do_notify',
|
||||||
'users.keep_history as keep_history',
|
'users.keep_history as keep_history',
|
||||||
@@ -179,6 +183,9 @@ class Users(object):
|
|||||||
'year': item['year'],
|
'year': item['year'],
|
||||||
'media_index': item['media_index'],
|
'media_index': item['media_index'],
|
||||||
'parent_media_index': item['parent_media_index'],
|
'parent_media_index': item['parent_media_index'],
|
||||||
|
'live': item['live'],
|
||||||
|
'originally_available_at': item['originally_available_at'],
|
||||||
|
'guid': item['guid'],
|
||||||
'transcode_decision': item['transcode_decision'],
|
'transcode_decision': item['transcode_decision'],
|
||||||
'do_notify': helpers.checked(item['do_notify']),
|
'do_notify': helpers.checked(item['do_notify']),
|
||||||
'keep_history': helpers.checked(item['keep_history']),
|
'keep_history': helpers.checked(item['keep_history']),
|
||||||
@@ -225,6 +232,10 @@ class Users(object):
|
|||||||
'session_history_metadata.year',
|
'session_history_metadata.year',
|
||||||
'session_history_metadata.media_index',
|
'session_history_metadata.media_index',
|
||||||
'session_history_metadata.parent_media_index',
|
'session_history_metadata.parent_media_index',
|
||||||
|
'session_history_metadata.live',
|
||||||
|
'session_history_metadata.added_at',
|
||||||
|
'session_history_metadata.originally_available_at',
|
||||||
|
'session_history_metadata.guid',
|
||||||
'session_history_media_info.transcode_decision',
|
'session_history_media_info.transcode_decision',
|
||||||
'session_history.user',
|
'session_history.user',
|
||||||
'session_history.user_id as custom_user_id',
|
'session_history.user_id as custom_user_id',
|
||||||
@@ -279,6 +290,9 @@ class Users(object):
|
|||||||
'year': item['year'],
|
'year': item['year'],
|
||||||
'media_index': item['media_index'],
|
'media_index': item['media_index'],
|
||||||
'parent_media_index': item['parent_media_index'],
|
'parent_media_index': item['parent_media_index'],
|
||||||
|
'live': item['live'],
|
||||||
|
'originally_available_at': item['originally_available_at'],
|
||||||
|
'guid': item['guid'],
|
||||||
'transcode_decision': item['transcode_decision'],
|
'transcode_decision': item['transcode_decision'],
|
||||||
'friendly_name': item['friendly_name'],
|
'friendly_name': item['friendly_name'],
|
||||||
'user_id': item['custom_user_id']
|
'user_id': item['custom_user_id']
|
||||||
@@ -534,11 +548,11 @@ class Users(object):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if str(user_id).isdigit():
|
if str(user_id).isdigit():
|
||||||
query = 'SELECT session_history.id, session_history.media_type, ' \
|
query = 'SELECT session_history.id, session_history.media_type, guid, ' \
|
||||||
'session_history.rating_key, session_history.parent_rating_key, session_history.grandparent_rating_key, ' \
|
'session_history.rating_key, session_history.parent_rating_key, session_history.grandparent_rating_key, ' \
|
||||||
'title, parent_title, grandparent_title, original_title, ' \
|
'title, parent_title, grandparent_title, original_title, ' \
|
||||||
'thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, ' \
|
'thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, ' \
|
||||||
'year, started, user ' \
|
'year, originally_available_at, added_at, live, started, user ' \
|
||||||
'FROM session_history_metadata ' \
|
'FROM session_history_metadata ' \
|
||||||
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
|
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
|
||||||
'WHERE user_id = ? ' \
|
'WHERE user_id = ? ' \
|
||||||
@@ -573,6 +587,9 @@ class Users(object):
|
|||||||
'media_index': row['media_index'],
|
'media_index': row['media_index'],
|
||||||
'parent_media_index': row['parent_media_index'],
|
'parent_media_index': row['parent_media_index'],
|
||||||
'year': row['year'],
|
'year': row['year'],
|
||||||
|
'originally_available_at': row['originally_available_at'],
|
||||||
|
'live': row['live'],
|
||||||
|
'guid': row['guid'],
|
||||||
'time': row['started'],
|
'time': row['started'],
|
||||||
'user': row['user']
|
'user': row['user']
|
||||||
}
|
}
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
PLEXPY_BRANCH = "master"
|
PLEXPY_BRANCH = "master"
|
||||||
PLEXPY_RELEASE_VERSION = "v2.1.44"
|
PLEXPY_RELEASE_VERSION = "v2.2.0"
|
||||||
|
@@ -115,20 +115,24 @@ def getVersion():
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
plexpy.INSTALL_TYPE = 'source'
|
plexpy.INSTALL_TYPE = 'docker' if plexpy.DOCKER else 'source'
|
||||||
|
|
||||||
version_file = os.path.join(plexpy.PROG_DIR, 'version.txt')
|
version_file = os.path.join(plexpy.PROG_DIR, 'version.txt')
|
||||||
|
branch_file = os.path.join(plexpy.PROG_DIR, 'branch.txt')
|
||||||
|
|
||||||
if not os.path.isfile(version_file):
|
if os.path.isfile(version_file):
|
||||||
return None, 'origin', common.BRANCH
|
|
||||||
|
|
||||||
with open(version_file, 'r') as f:
|
with open(version_file, 'r') as f:
|
||||||
current_version = f.read().strip(' \n\r')
|
current_version = f.read().strip(' \n\r')
|
||||||
|
|
||||||
if current_version:
|
|
||||||
return current_version, 'origin', common.BRANCH
|
|
||||||
else:
|
else:
|
||||||
return None, 'origin', common.BRANCH
|
current_version = None
|
||||||
|
|
||||||
|
if os.path.isfile(branch_file):
|
||||||
|
with open(branch_file, 'r') as f:
|
||||||
|
current_branch = f.read().strip(' \n\r')
|
||||||
|
else:
|
||||||
|
current_branch = common.BRANCH
|
||||||
|
|
||||||
|
return current_version, 'origin', current_branch
|
||||||
|
|
||||||
|
|
||||||
def check_update(auto_update=False, notify=False):
|
def check_update(auto_update=False, notify=False):
|
||||||
@@ -232,7 +236,7 @@ def check_github(auto_update=False, notify=False):
|
|||||||
'plexpy_update_commit': plexpy.LATEST_VERSION,
|
'plexpy_update_commit': plexpy.LATEST_VERSION,
|
||||||
'plexpy_update_behind': plexpy.COMMITS_BEHIND})
|
'plexpy_update_behind': plexpy.COMMITS_BEHIND})
|
||||||
|
|
||||||
if auto_update:
|
if auto_update and not plexpy.DOCKER:
|
||||||
logger.info('Running automatic update.')
|
logger.info('Running automatic update.')
|
||||||
plexpy.shutdown(restart=True, update=True)
|
plexpy.shutdown(restart=True, update=True)
|
||||||
|
|
||||||
@@ -247,23 +251,26 @@ def update():
|
|||||||
logger.info('Windows .exe updating not supported yet.')
|
logger.info('Windows .exe updating not supported yet.')
|
||||||
|
|
||||||
elif plexpy.INSTALL_TYPE == 'git':
|
elif plexpy.INSTALL_TYPE == 'git':
|
||||||
output, err = runGit('pull ' + plexpy.CONFIG.GIT_REMOTE + ' ' + plexpy.CONFIG.GIT_BRANCH)
|
output, err = runGit('pull {} {} --ff-only'.format(plexpy.CONFIG.GIT_REMOTE,
|
||||||
|
plexpy.CONFIG.GIT_BRANCH))
|
||||||
|
|
||||||
if not output:
|
if not output:
|
||||||
logger.error('Unable to download latest version')
|
logger.error('Unable to download latest version')
|
||||||
return
|
return
|
||||||
|
|
||||||
for line in output.split('\n'):
|
for line in output.split('\n'):
|
||||||
|
if 'Already up-to-date.' in line or 'Already up to date.' in line:
|
||||||
if 'Already up-to-date.' in line:
|
|
||||||
logger.info('No update available, not updating')
|
logger.info('No update available, not updating')
|
||||||
logger.info('Output: ' + str(output))
|
|
||||||
elif line.endswith(('Aborting', 'Aborting.')):
|
elif line.endswith(('Aborting', 'Aborting.')):
|
||||||
logger.error('Unable to update from git: ' + line)
|
logger.error('Unable to update from git: ' + line)
|
||||||
logger.info('Output: ' + str(output))
|
|
||||||
|
elif plexpy.INSTALL_TYPE == 'docker':
|
||||||
|
return
|
||||||
|
|
||||||
else:
|
else:
|
||||||
tar_download_url = 'https://github.com/{}/{}/tarball/{}'.format(plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.CONFIG.GIT_BRANCH)
|
tar_download_url = 'https://github.com/{}/{}/tarball/{}'.format(plexpy.CONFIG.GIT_USER,
|
||||||
|
plexpy.CONFIG.GIT_REPO,
|
||||||
|
plexpy.CONFIG.GIT_BRANCH)
|
||||||
update_dir = os.path.join(plexpy.PROG_DIR, 'update')
|
update_dir = os.path.join(plexpy.PROG_DIR, 'update')
|
||||||
version_path = os.path.join(plexpy.PROG_DIR, 'version.txt')
|
version_path = os.path.join(plexpy.PROG_DIR, 'version.txt')
|
||||||
|
|
||||||
@@ -321,10 +328,41 @@ def update():
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def reset_git_install():
|
||||||
|
if plexpy.INSTALL_TYPE == 'git':
|
||||||
|
logger.info('Attempting to reset git install to "{}/{}/{}"'.format(plexpy.CONFIG.GIT_REMOTE,
|
||||||
|
plexpy.CONFIG.GIT_BRANCH,
|
||||||
|
common.RELEASE))
|
||||||
|
|
||||||
|
output, err = runGit('remote set-url {} https://github.com/{}/{}.git'.format(plexpy.CONFIG.GIT_REMOTE,
|
||||||
|
plexpy.CONFIG.GIT_USER,
|
||||||
|
plexpy.CONFIG.GIT_REPO))
|
||||||
|
output, err = runGit('fetch {}'.format(plexpy.CONFIG.GIT_REMOTE))
|
||||||
|
output, err = runGit('checkout {}'.format(plexpy.CONFIG.GIT_BRANCH))
|
||||||
|
output, err = runGit('branch -u {}/{}'.format(plexpy.CONFIG.GIT_REMOTE,
|
||||||
|
plexpy.CONFIG.GIT_BRANCH))
|
||||||
|
output, err = runGit('reset --hard {}'.format(common.RELEASE))
|
||||||
|
|
||||||
|
if not output:
|
||||||
|
logger.error('Unable to reset Tautulli installation.')
|
||||||
|
return False
|
||||||
|
|
||||||
|
for line in output.split('\n'):
|
||||||
|
if 'Already up-to-date.' in line or 'Already up to date.' in line:
|
||||||
|
logger.info('Tautulli installation reset successfully.')
|
||||||
|
return True
|
||||||
|
elif line.endswith(('Aborting', 'Aborting.')):
|
||||||
|
logger.error('Unable to reset Tautulli installation: ' + line)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def checkout_git_branch():
|
def checkout_git_branch():
|
||||||
if plexpy.INSTALL_TYPE == 'git':
|
if plexpy.INSTALL_TYPE == 'git':
|
||||||
output, err = runGit('fetch %s' % plexpy.CONFIG.GIT_REMOTE)
|
logger.info('Attempting to checkout git branch "{}/{}"'.format(plexpy.CONFIG.GIT_REMOTE,
|
||||||
output, err = runGit('checkout %s' % plexpy.CONFIG.GIT_BRANCH)
|
plexpy.CONFIG.GIT_BRANCH))
|
||||||
|
|
||||||
|
output, err = runGit('fetch {}'.format(plexpy.CONFIG.GIT_REMOTE))
|
||||||
|
output, err = runGit('checkout {}'.format(plexpy.CONFIG.GIT_BRANCH))
|
||||||
|
|
||||||
if not output:
|
if not output:
|
||||||
logger.error('Unable to change git branch.')
|
logger.error('Unable to change git branch.')
|
||||||
@@ -333,9 +371,10 @@ def checkout_git_branch():
|
|||||||
for line in output.split('\n'):
|
for line in output.split('\n'):
|
||||||
if line.endswith(('Aborting', 'Aborting.')):
|
if line.endswith(('Aborting', 'Aborting.')):
|
||||||
logger.error('Unable to checkout from git: ' + line)
|
logger.error('Unable to checkout from git: ' + line)
|
||||||
logger.info('Output: ' + str(output))
|
return
|
||||||
|
|
||||||
output, err = runGit('pull %s %s' % (plexpy.CONFIG.GIT_REMOTE, plexpy.CONFIG.GIT_BRANCH))
|
output, err = runGit('pull {} {}'.format(plexpy.CONFIG.GIT_REMOTE,
|
||||||
|
plexpy.CONFIG.GIT_BRANCH))
|
||||||
|
|
||||||
|
|
||||||
def read_changelog(latest_only=False, since_prev_release=False):
|
def read_changelog(latest_only=False, since_prev_release=False):
|
||||||
|
@@ -277,7 +277,7 @@ class WebInterface(object):
|
|||||||
def return_plex_xml_url(self, endpoint='', plextv=False, **kwargs):
|
def return_plex_xml_url(self, endpoint='', plextv=False, **kwargs):
|
||||||
kwargs['X-Plex-Token'] = plexpy.CONFIG.PMS_TOKEN
|
kwargs['X-Plex-Token'] = plexpy.CONFIG.PMS_TOKEN
|
||||||
|
|
||||||
if plextv == 'true':
|
if helpers.bool_true(plextv):
|
||||||
base_url = 'https://plex.tv'
|
base_url = 'https://plex.tv'
|
||||||
else:
|
else:
|
||||||
if plexpy.CONFIG.PMS_URL_OVERRIDE:
|
if plexpy.CONFIG.PMS_URL_OVERRIDE:
|
||||||
@@ -382,15 +382,18 @@ class WebInterface(object):
|
|||||||
"do_notify": "Checked",
|
"do_notify": "Checked",
|
||||||
"do_notify_created": "Checked",
|
"do_notify_created": "Checked",
|
||||||
"duration": 1578037,
|
"duration": 1578037,
|
||||||
|
"guid": "com.plexapp.agents.thetvdb://121361/6/1?lang=en",
|
||||||
"id": 1128,
|
"id": 1128,
|
||||||
"keep_history": "Checked",
|
"keep_history": "Checked",
|
||||||
"labels": [],
|
"labels": [],
|
||||||
"last_accessed": 1462693216,
|
"last_accessed": 1462693216,
|
||||||
"last_played": "Game of Thrones - The Red Woman",
|
"last_played": "Game of Thrones - The Red Woman",
|
||||||
"library_art": "/:/resources/show-fanart.jpg",
|
"library_art": "/:/resources/show-fanart.jpg",
|
||||||
"library_thumb": "",
|
"library_thumb": "/:/resources/show.png",
|
||||||
|
"live": 0,
|
||||||
"media_index": 1,
|
"media_index": 1,
|
||||||
"media_type": "episode",
|
"media_type": "episode",
|
||||||
|
"originally_available_at": "2016-04-24",
|
||||||
"parent_count": 240,
|
"parent_count": 240,
|
||||||
"parent_media_index": 6,
|
"parent_media_index": 6,
|
||||||
"parent_title": "",
|
"parent_title": "",
|
||||||
@@ -523,6 +526,7 @@ class WebInterface(object):
|
|||||||
|
|
||||||
Optional parameters:
|
Optional parameters:
|
||||||
custom_thumb (str): The URL for the custom library thumbnail
|
custom_thumb (str): The URL for the custom library thumbnail
|
||||||
|
custom_art (str): The URL for the custom library background art
|
||||||
keep_history (int): 0 or 1
|
keep_history (int): 0 or 1
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -530,6 +534,7 @@ class WebInterface(object):
|
|||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
custom_thumb = kwargs.get('custom_thumb', '')
|
custom_thumb = kwargs.get('custom_thumb', '')
|
||||||
|
custom_art = kwargs.get('custom_art', '')
|
||||||
do_notify = kwargs.get('do_notify', 0)
|
do_notify = kwargs.get('do_notify', 0)
|
||||||
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)
|
||||||
@@ -539,6 +544,7 @@ class WebInterface(object):
|
|||||||
library_data = libraries.Libraries()
|
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,
|
||||||
|
custom_art=custom_art,
|
||||||
do_notify=do_notify,
|
do_notify=do_notify,
|
||||||
do_notify_created=do_notify_created,
|
do_notify_created=do_notify_created,
|
||||||
keep_history=keep_history)
|
keep_history=keep_history)
|
||||||
@@ -666,6 +672,7 @@ class WebInterface(object):
|
|||||||
"rating_key": "1219",
|
"rating_key": "1219",
|
||||||
"section_id": 2,
|
"section_id": 2,
|
||||||
"section_type": "show",
|
"section_type": "show",
|
||||||
|
"sort_title": "Game of Thrones",
|
||||||
"thumb": "/library/metadata/1219/thumb/1436265995",
|
"thumb": "/library/metadata/1219/thumb/1436265995",
|
||||||
"title": "Game of Thrones",
|
"title": "Game of Thrones",
|
||||||
"video_codec": "",
|
"video_codec": "",
|
||||||
@@ -701,7 +708,7 @@ class WebInterface(object):
|
|||||||
("play_count", True, False)]
|
("play_count", True, False)]
|
||||||
kwargs['json_data'] = build_datatables_json(kwargs, dt_columns, "sort_title")
|
kwargs['json_data'] = build_datatables_json(kwargs, dt_columns, "sort_title")
|
||||||
|
|
||||||
if refresh == 'true':
|
if helpers.bool_true(refresh):
|
||||||
refresh = True
|
refresh = True
|
||||||
else:
|
else:
|
||||||
refresh = False
|
refresh = False
|
||||||
@@ -1044,13 +1051,16 @@ class WebInterface(object):
|
|||||||
"do_notify": "Checked",
|
"do_notify": "Checked",
|
||||||
"duration": 2998290,
|
"duration": 2998290,
|
||||||
"friendly_name": "Jon Snow",
|
"friendly_name": "Jon Snow",
|
||||||
|
"guid": "com.plexapp.agents.thetvdb://121361/6/1?lang=en",
|
||||||
"id": 1121,
|
"id": 1121,
|
||||||
"ip_address": "xxx.xxx.xxx.xxx",
|
"ip_address": "xxx.xxx.xxx.xxx",
|
||||||
"keep_history": "Checked",
|
"keep_history": "Checked",
|
||||||
"last_played": "Game of Thrones - The Red Woman",
|
"last_played": "Game of Thrones - The Red Woman",
|
||||||
"last_seen": 1462591869,
|
"last_seen": 1462591869,
|
||||||
|
"live": 0,
|
||||||
"media_index": 1,
|
"media_index": 1,
|
||||||
"media_type": "episode",
|
"media_type": "episode",
|
||||||
|
"originally_available_at": "2016-04-24",
|
||||||
"parent_media_index": 6,
|
"parent_media_index": 6,
|
||||||
"parent_title": "",
|
"parent_title": "",
|
||||||
"platform": "Chrome",
|
"platform": "Chrome",
|
||||||
@@ -1256,12 +1266,15 @@ class WebInterface(object):
|
|||||||
"recordsFiltered": 10,
|
"recordsFiltered": 10,
|
||||||
"data":
|
"data":
|
||||||
[{"friendly_name": "Jon Snow",
|
[{"friendly_name": "Jon Snow",
|
||||||
|
"guid": "com.plexapp.agents.thetvdb://121361/6/1?lang=en",
|
||||||
"id": 1121,
|
"id": 1121,
|
||||||
"ip_address": "xxx.xxx.xxx.xxx",
|
"ip_address": "xxx.xxx.xxx.xxx",
|
||||||
"last_played": "Game of Thrones - The Red Woman",
|
"last_played": "Game of Thrones - The Red Woman",
|
||||||
"last_seen": 1462591869,
|
"last_seen": 1462591869,
|
||||||
|
"live": 0,
|
||||||
"media_index": 1,
|
"media_index": 1,
|
||||||
"media_type": "episode",
|
"media_type": "episode",
|
||||||
|
"originally_available_at": "2016-04-24",
|
||||||
"parent_media_index": 6,
|
"parent_media_index": 6,
|
||||||
"parent_title": "",
|
"parent_title": "",
|
||||||
"platform": "Chrome",
|
"platform": "Chrome",
|
||||||
@@ -1596,8 +1609,9 @@ class WebInterface(object):
|
|||||||
grandparent_rating_key (int): 351
|
grandparent_rating_key (int): 351
|
||||||
start_date (str): "YYYY-MM-DD"
|
start_date (str): "YYYY-MM-DD"
|
||||||
section_id (int): 2
|
section_id (int): 2
|
||||||
media_type (str): "movie", "episode", "track"
|
media_type (str): "movie", "episode", "track", "live"
|
||||||
transcode_decision (str): "direct play", "copy", "transcode",
|
transcode_decision (str): "direct play", "copy", "transcode",
|
||||||
|
guid (str): Plex guid for an item, e.g. "com.plexapp.agents.thetvdb://121361/6/1"
|
||||||
order_column (str): "date", "friendly_name", "ip_address", "platform", "player",
|
order_column (str): "date", "friendly_name", "ip_address", "platform", "player",
|
||||||
"full_title", "started", "paused_counter", "stopped", "duration"
|
"full_title", "started", "paused_counter", "stopped", "duration"
|
||||||
order_dir (str): "desc" or "asc"
|
order_dir (str): "desc" or "asc"
|
||||||
@@ -1622,10 +1636,13 @@ class WebInterface(object):
|
|||||||
"original_title": "",
|
"original_title": "",
|
||||||
"group_count": 1,
|
"group_count": 1,
|
||||||
"group_ids": "1124",
|
"group_ids": "1124",
|
||||||
|
"guid": "com.plexapp.agents.thetvdb://121361/6/1?lang=en",
|
||||||
"id": 1124,
|
"id": 1124,
|
||||||
"ip_address": "xxx.xxx.xxx.xxx",
|
"ip_address": "xxx.xxx.xxx.xxx",
|
||||||
|
"live": 0,
|
||||||
"media_index": 17,
|
"media_index": 17,
|
||||||
"media_type": "episode",
|
"media_type": "episode",
|
||||||
|
"originally_available_at": "2016-04-24",
|
||||||
"parent_media_index": 7,
|
"parent_media_index": 7,
|
||||||
"parent_rating_key": 544,
|
"parent_rating_key": 544,
|
||||||
"parent_title": "",
|
"parent_title": "",
|
||||||
@@ -1683,31 +1700,37 @@ class WebInterface(object):
|
|||||||
elif user:
|
elif user:
|
||||||
custom_where.append(['session_history.user', user])
|
custom_where.append(['session_history.user', user])
|
||||||
if 'rating_key' in kwargs:
|
if 'rating_key' in kwargs:
|
||||||
rating_key = kwargs.get('rating_key', "")
|
rating_key = kwargs.get('rating_key', '')
|
||||||
custom_where.append(['session_history.rating_key', rating_key])
|
custom_where.append(['session_history.rating_key', rating_key])
|
||||||
if 'parent_rating_key' in kwargs:
|
if 'parent_rating_key' in kwargs:
|
||||||
rating_key = kwargs.get('parent_rating_key', "")
|
rating_key = kwargs.get('parent_rating_key', '')
|
||||||
custom_where.append(['session_history.parent_rating_key', rating_key])
|
custom_where.append(['session_history.parent_rating_key', rating_key])
|
||||||
if 'grandparent_rating_key' in kwargs:
|
if 'grandparent_rating_key' in kwargs:
|
||||||
rating_key = kwargs.get('grandparent_rating_key', "")
|
rating_key = kwargs.get('grandparent_rating_key', '')
|
||||||
custom_where.append(['session_history.grandparent_rating_key', rating_key])
|
custom_where.append(['session_history.grandparent_rating_key', rating_key])
|
||||||
if 'start_date' in kwargs:
|
if 'start_date' in kwargs:
|
||||||
start_date = kwargs.get('start_date', "")
|
start_date = kwargs.get('start_date', '')
|
||||||
custom_where.append(['strftime("%Y-%m-%d", datetime(started, "unixepoch", "localtime"))', start_date])
|
custom_where.append(['strftime("%Y-%m-%d", datetime(started, "unixepoch", "localtime"))', start_date])
|
||||||
if 'reference_id' in kwargs:
|
if 'reference_id' in kwargs:
|
||||||
reference_id = kwargs.get('reference_id', "")
|
reference_id = kwargs.get('reference_id', '')
|
||||||
custom_where.append(['session_history.reference_id', reference_id])
|
custom_where.append(['session_history.reference_id', reference_id])
|
||||||
if 'section_id' in kwargs:
|
if 'section_id' in kwargs:
|
||||||
section_id = kwargs.get('section_id', "")
|
section_id = kwargs.get('section_id', '')
|
||||||
custom_where.append(['session_history_metadata.section_id', section_id])
|
custom_where.append(['session_history_metadata.section_id', section_id])
|
||||||
if 'media_type' in kwargs:
|
if 'media_type' in kwargs:
|
||||||
media_type = kwargs.get('media_type', "")
|
media_type = kwargs.get('media_type', '')
|
||||||
if media_type != 'all':
|
if media_type not in ('all', 'live'):
|
||||||
custom_where.append(['session_history.media_type', media_type])
|
custom_where.append(['session_history.media_type', media_type])
|
||||||
|
custom_where.append(['session_history_metadata.live', '0'])
|
||||||
|
elif media_type == 'live':
|
||||||
|
custom_where.append(['session_history_metadata.live', '1'])
|
||||||
if 'transcode_decision' in kwargs:
|
if 'transcode_decision' in kwargs:
|
||||||
transcode_decision = kwargs.get('transcode_decision', "")
|
transcode_decision = kwargs.get('transcode_decision', '')
|
||||||
if transcode_decision:
|
if transcode_decision:
|
||||||
custom_where.append(['session_history_media_info.transcode_decision', transcode_decision])
|
custom_where.append(['session_history_media_info.transcode_decision', transcode_decision])
|
||||||
|
if 'guid' in kwargs:
|
||||||
|
guid = kwargs.get('guid', '').split('?')[0]
|
||||||
|
custom_where.append(['session_history_metadata.guid', 'LIKE ' + guid + '%']) # SQLite LIKE wildcard
|
||||||
|
|
||||||
data_factory = datafactory.DataFactory()
|
data_factory = datafactory.DataFactory()
|
||||||
history = data_factory.get_datatables_history(kwargs=kwargs, custom_where=custom_where, grouping=grouping)
|
history = data_factory.get_datatables_history(kwargs=kwargs, custom_where=custom_where, grouping=grouping)
|
||||||
@@ -1768,6 +1791,7 @@ class WebInterface(object):
|
|||||||
"stream_video_bitrate": 527,
|
"stream_video_bitrate": 527,
|
||||||
"stream_video_codec": "h264",
|
"stream_video_codec": "h264",
|
||||||
"stream_video_decision": "transcode",
|
"stream_video_decision": "transcode",
|
||||||
|
"stream_video_dynamic_range": "SDR",
|
||||||
"stream_video_framerate": "24p",
|
"stream_video_framerate": "24p",
|
||||||
"stream_video_height": 306,
|
"stream_video_height": 306,
|
||||||
"stream_video_resolution": "SD",
|
"stream_video_resolution": "SD",
|
||||||
@@ -1782,6 +1806,7 @@ class WebInterface(object):
|
|||||||
"video_bitrate": 2500,
|
"video_bitrate": 2500,
|
||||||
"video_codec": "h264",
|
"video_codec": "h264",
|
||||||
"video_decision": "transcode",
|
"video_decision": "transcode",
|
||||||
|
"video_dynamic_range": "SDR",
|
||||||
"video_framerate": "24p",
|
"video_framerate": "24p",
|
||||||
"video_height": 816,
|
"video_height": 816,
|
||||||
"video_resolution": "1080",
|
"video_resolution": "1080",
|
||||||
@@ -1877,7 +1902,8 @@ class WebInterface(object):
|
|||||||
"series":
|
"series":
|
||||||
[{"name": "Movies", "data": [...]}
|
[{"name": "Movies", "data": [...]}
|
||||||
{"name": "TV", "data": [...]},
|
{"name": "TV", "data": [...]},
|
||||||
{"name": "Music", "data": [...]}
|
{"name": "Music", "data": [...]},
|
||||||
|
{"name": "Live TV", "data": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -1916,7 +1942,8 @@ class WebInterface(object):
|
|||||||
"series":
|
"series":
|
||||||
[{"name": "Movies", "data": [...]}
|
[{"name": "Movies", "data": [...]}
|
||||||
{"name": "TV", "data": [...]},
|
{"name": "TV", "data": [...]},
|
||||||
{"name": "Music", "data": [...]}
|
{"name": "Music", "data": [...]},
|
||||||
|
{"name": "Live TV", "data": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -1955,7 +1982,8 @@ class WebInterface(object):
|
|||||||
"series":
|
"series":
|
||||||
[{"name": "Movies", "data": [...]}
|
[{"name": "Movies", "data": [...]}
|
||||||
{"name": "TV", "data": [...]},
|
{"name": "TV", "data": [...]},
|
||||||
{"name": "Music", "data": [...]}
|
{"name": "Music", "data": [...]},
|
||||||
|
{"name": "Live TV", "data": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -1994,7 +2022,8 @@ class WebInterface(object):
|
|||||||
"series":
|
"series":
|
||||||
[{"name": "Movies", "data": [...]}
|
[{"name": "Movies", "data": [...]}
|
||||||
{"name": "TV", "data": [...]},
|
{"name": "TV", "data": [...]},
|
||||||
{"name": "Music", "data": [...]}
|
{"name": "Music", "data": [...]},
|
||||||
|
{"name": "Live TV", "data": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -2033,7 +2062,8 @@ class WebInterface(object):
|
|||||||
"series":
|
"series":
|
||||||
[{"name": "Movies", "data": [...]}
|
[{"name": "Movies", "data": [...]}
|
||||||
{"name": "TV", "data": [...]},
|
{"name": "TV", "data": [...]},
|
||||||
{"name": "Music", "data": [...]}
|
{"name": "Music", "data": [...]},
|
||||||
|
{"name": "Live TV", "data": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -2072,7 +2102,8 @@ class WebInterface(object):
|
|||||||
"series":
|
"series":
|
||||||
[{"name": "Movies", "data": [...]}
|
[{"name": "Movies", "data": [...]}
|
||||||
{"name": "TV", "data": [...]},
|
{"name": "TV", "data": [...]},
|
||||||
{"name": "Music", "data": [...]}
|
{"name": "Music", "data": [...]},
|
||||||
|
{"name": "Live TV", "data": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -3065,7 +3096,7 @@ class WebInterface(object):
|
|||||||
def install_geoip_db(self, update=False, **kwargs):
|
def install_geoip_db(self, update=False, **kwargs):
|
||||||
""" Downloads and installs the GeoLite2 database """
|
""" Downloads and installs the GeoLite2 database """
|
||||||
|
|
||||||
update = True if update == 'true' else False
|
update = helpers.bool_true(update)
|
||||||
|
|
||||||
result = helpers.install_geoip_db(update=update)
|
result = helpers.install_geoip_db(update=update)
|
||||||
|
|
||||||
@@ -3471,7 +3502,7 @@ class WebInterface(object):
|
|||||||
@cherrypy.tools.json_out()
|
@cherrypy.tools.json_out()
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
def verify_mobile_device(self, device_token='', cancel=False, **kwargs):
|
def verify_mobile_device(self, device_token='', cancel=False, **kwargs):
|
||||||
if cancel == 'true':
|
if helpers.bool_true(cancel):
|
||||||
mobile_app.TEMP_DEVICE_TOKEN = None
|
mobile_app.TEMP_DEVICE_TOKEN = None
|
||||||
return {'result': 'error', 'message': 'Device registration cancelled.'}
|
return {'result': 'error', 'message': 'Device registration cancelled.'}
|
||||||
|
|
||||||
@@ -3636,7 +3667,7 @@ class WebInterface(object):
|
|||||||
if not username and not password:
|
if not username and not password:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
force = True if force == 'true' else False
|
force = helpers.bool_true(force)
|
||||||
|
|
||||||
plex_tv = plextv.PlexTV(username=username, password=password)
|
plex_tv = plextv.PlexTV(username=username, password=password)
|
||||||
token = plex_tv.get_plexpy_pms_token(force=force)
|
token = plex_tv.get_plexpy_pms_token(force=force)
|
||||||
@@ -3699,7 +3730,7 @@ class WebInterface(object):
|
|||||||
result = {'identifier': identifier}
|
result = {'identifier': identifier}
|
||||||
|
|
||||||
if identifier:
|
if identifier:
|
||||||
if get_url == 'true':
|
if helpers.bool_true(get_url):
|
||||||
server = self.get_server_resources(pms_ip=hostname,
|
server = self.get_server_resources(pms_ip=hostname,
|
||||||
pms_port=port,
|
pms_port=port,
|
||||||
pms_ssl=ssl,
|
pms_ssl=ssl,
|
||||||
@@ -3709,7 +3740,7 @@ class WebInterface(object):
|
|||||||
result['url'] = server['pms_url']
|
result['url'] = server['pms_url']
|
||||||
result['ws'] = None
|
result['ws'] = None
|
||||||
|
|
||||||
if test_websocket == 'true':
|
if helpers.bool_true(test_websocket):
|
||||||
# Quick test websocket connection
|
# Quick test websocket connection
|
||||||
ws_url = result['url'].replace('http', 'ws', 1) + '/:/websockets/notifications'
|
ws_url = result['url'].replace('http', 'ws', 1) + '/:/websockets/notifications'
|
||||||
header = ['X-Plex-Token: %s' % plexpy.CONFIG.PMS_TOKEN]
|
header = ['X-Plex-Token: %s' % plexpy.CONFIG.PMS_TOKEN]
|
||||||
@@ -3763,7 +3794,7 @@ class WebInterface(object):
|
|||||||
logger.info(u"New API key generated.")
|
logger.info(u"New API key generated.")
|
||||||
logger._BLACKLIST_WORDS.add(apikey)
|
logger._BLACKLIST_WORDS.add(apikey)
|
||||||
|
|
||||||
if device == 'true':
|
if helpers.bool_true(device):
|
||||||
mobile_app.TEMP_DEVICE_TOKEN = apikey
|
mobile_app.TEMP_DEVICE_TOKEN = apikey
|
||||||
|
|
||||||
return apikey
|
return apikey
|
||||||
@@ -3793,13 +3824,13 @@ class WebInterface(object):
|
|||||||
versioncheck.check_update()
|
versioncheck.check_update()
|
||||||
|
|
||||||
if plexpy.UPDATE_AVAILABLE is None:
|
if plexpy.UPDATE_AVAILABLE is None:
|
||||||
return {'result': 'error',
|
update = {'result': 'error',
|
||||||
'update': None,
|
'update': None,
|
||||||
'message': 'You are running an unknown version of Tautulli.'
|
'message': 'You are running an unknown version of Tautulli.'
|
||||||
}
|
}
|
||||||
|
|
||||||
elif plexpy.UPDATE_AVAILABLE == 'release':
|
elif plexpy.UPDATE_AVAILABLE == 'release':
|
||||||
return {'result': 'success',
|
update = {'result': 'success',
|
||||||
'update': True,
|
'update': True,
|
||||||
'release': True,
|
'release': True,
|
||||||
'message': 'A new release (%s) of Tautulli is available.' % plexpy.LATEST_RELEASE,
|
'message': 'A new release (%s) of Tautulli is available.' % plexpy.LATEST_RELEASE,
|
||||||
@@ -3813,7 +3844,7 @@ class WebInterface(object):
|
|||||||
}
|
}
|
||||||
|
|
||||||
elif plexpy.UPDATE_AVAILABLE == 'commit':
|
elif plexpy.UPDATE_AVAILABLE == 'commit':
|
||||||
return {'result': 'success',
|
update = {'result': 'success',
|
||||||
'update': True,
|
'update': True,
|
||||||
'release': False,
|
'release': False,
|
||||||
'message': 'A newer version of Tautulli is available.',
|
'message': 'A newer version of Tautulli is available.',
|
||||||
@@ -3829,11 +3860,16 @@ class WebInterface(object):
|
|||||||
}
|
}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return {'result': 'success',
|
update = {'result': 'success',
|
||||||
'update': False,
|
'update': False,
|
||||||
'message': 'Tautulli is up to date.'
|
'message': 'Tautulli is up to date.'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if plexpy.DOCKER:
|
||||||
|
update['docker'] = plexpy.DOCKER
|
||||||
|
|
||||||
|
return update
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
def do_state_change(self, signal, title, timer, **kwargs):
|
def do_state_change(self, signal, title, timer, **kwargs):
|
||||||
@@ -3862,6 +3898,9 @@ class WebInterface(object):
|
|||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
def update(self, **kwargs):
|
def update(self, **kwargs):
|
||||||
|
if plexpy.DOCKER:
|
||||||
|
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT + "home")
|
||||||
|
|
||||||
# Show changelog after updating
|
# Show changelog after updating
|
||||||
plexpy.CONFIG.__setattr__('UPDATE_SHOW_CHANGELOG', 1)
|
plexpy.CONFIG.__setattr__('UPDATE_SHOW_CHANGELOG', 1)
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
@@ -3880,18 +3919,23 @@ class WebInterface(object):
|
|||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
return self.do_state_change('checkout', 'Switching Git Branches', 120)
|
return self.do_state_change('checkout', 'Switching Git Branches', 120)
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
@requireAuth(member_of("admin"))
|
||||||
|
def reset_git_install(self, **kwargs):
|
||||||
|
return self.do_state_change('reset', 'Resetting to {}'.format(common.RELEASE), 120)
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
def get_changelog(self, latest_only=False, since_prev_release=False, update_shown=False, **kwargs):
|
def get_changelog(self, latest_only=False, since_prev_release=False, update_shown=False, **kwargs):
|
||||||
latest_only = (latest_only == 'true')
|
latest_only = helpers.bool_true(latest_only)
|
||||||
since_prev_release = (since_prev_release == 'true')
|
since_prev_release = helpers.bool_true(since_prev_release)
|
||||||
|
|
||||||
if since_prev_release and plexpy.PREV_RELEASE == common.RELEASE:
|
if since_prev_release and plexpy.PREV_RELEASE == common.RELEASE:
|
||||||
latest_only = True
|
latest_only = True
|
||||||
since_prev_release = False
|
since_prev_release = False
|
||||||
|
|
||||||
# Set update changelog shown status
|
# Set update changelog shown status
|
||||||
if update_shown == 'true':
|
if helpers.bool_true(update_shown):
|
||||||
plexpy.CONFIG.__setattr__('UPDATE_SHOW_CHANGELOG', 0)
|
plexpy.CONFIG.__setattr__('UPDATE_SHOW_CHANGELOG', 0)
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
|
|
||||||
@@ -3901,7 +3945,7 @@ class WebInterface(object):
|
|||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
def info(self, rating_key=None, source=None, query=None, **kwargs):
|
def info(self, rating_key=None, guid=None, source=None, **kwargs):
|
||||||
if rating_key and not str(rating_key).isdigit():
|
if rating_key and not str(rating_key).isdigit():
|
||||||
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
|
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
|
||||||
|
|
||||||
@@ -3914,7 +3958,7 @@ class WebInterface(object):
|
|||||||
|
|
||||||
if source == 'history':
|
if source == 'history':
|
||||||
data_factory = datafactory.DataFactory()
|
data_factory = datafactory.DataFactory()
|
||||||
metadata = data_factory.get_metadata_details(rating_key=rating_key)
|
metadata = data_factory.get_metadata_details(rating_key=rating_key, guid=guid)
|
||||||
if metadata:
|
if metadata:
|
||||||
poster_info = data_factory.get_poster_info(metadata=metadata)
|
poster_info = data_factory.get_poster_info(metadata=metadata)
|
||||||
metadata.update(poster_info)
|
metadata.update(poster_info)
|
||||||
@@ -3934,12 +3978,12 @@ class WebInterface(object):
|
|||||||
if metadata['section_id'] and not allow_session_library(metadata['section_id']):
|
if metadata['section_id'] and not allow_session_library(metadata['section_id']):
|
||||||
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
|
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
|
||||||
|
|
||||||
return serve_template(templatename="info.html", data=metadata, title="Info", config=config, source=source)
|
return serve_template(templatename="info.html", metadata=metadata, title="Info", config=config, source=source)
|
||||||
else:
|
else:
|
||||||
if get_session_user_id():
|
if get_session_user_id():
|
||||||
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
|
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
|
||||||
else:
|
else:
|
||||||
return self.update_metadata(rating_key, query)
|
return self.update_metadata(rating_key)
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
@@ -4035,10 +4079,10 @@ class WebInterface(object):
|
|||||||
width (str): 300
|
width (str): 300
|
||||||
height (str): 450
|
height (str): 450
|
||||||
opacity (str): 25
|
opacity (str): 25
|
||||||
background (str): 282828
|
background (str): Hex color, e.g. 282828
|
||||||
blur (str): 3
|
blur (str): 3
|
||||||
img_format (str): png
|
img_format (str): png
|
||||||
fallback (str): "poster", "cover", "art"
|
fallback (str): "poster", "cover", "art", "poster-live", "art-live", "art-live-full"
|
||||||
refresh (bool): True or False whether to refresh the image cache
|
refresh (bool): True or False whether to refresh the image cache
|
||||||
return_hash (bool): True or False to return the self-hosted image hash instead of the image
|
return_hash (bool): True or False to return the self-hosted image hash instead of the image
|
||||||
|
|
||||||
@@ -4047,20 +4091,27 @@ class WebInterface(object):
|
|||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
if not img and not rating_key:
|
if not img and not rating_key:
|
||||||
|
if fallback in common.DEFAULT_IMAGES:
|
||||||
|
fbi = common.DEFAULT_IMAGES[fallback]
|
||||||
|
fp = os.path.join(plexpy.PROG_DIR, 'data', fbi)
|
||||||
|
return serve_file(path=fp, content_type='image/png')
|
||||||
logger.warn('No image input received.')
|
logger.warn('No image input received.')
|
||||||
return
|
return
|
||||||
|
|
||||||
return_hash = (kwargs.get('return_hash') == 'true')
|
return_hash = helpers.bool_true(kwargs.get('return_hash'))
|
||||||
|
|
||||||
if rating_key and not img:
|
if rating_key and not img:
|
||||||
if fallback == 'art':
|
if fallback and fallback.startswith('art'):
|
||||||
img = '/library/metadata/{}/art'.format(rating_key)
|
img = '/library/metadata/{}/art'.format(rating_key)
|
||||||
else:
|
else:
|
||||||
img = '/library/metadata/{}/thumb'.format(rating_key)
|
img = '/library/metadata/{}/thumb'.format(rating_key)
|
||||||
|
|
||||||
|
if img.startswith('/library/metadata'):
|
||||||
img_split = img.split('/')
|
img_split = img.split('/')
|
||||||
img = '/'.join(img_split[:5])
|
img = '/'.join(img_split[:5])
|
||||||
rating_key = rating_key or img_split[3]
|
img_rating_key = img_split[3]
|
||||||
|
if rating_key != img_rating_key:
|
||||||
|
rating_key = img_rating_key
|
||||||
|
|
||||||
img_hash = notification_handler.set_hash_image_info(
|
img_hash = notification_handler.set_hash_image_info(
|
||||||
img=img, rating_key=rating_key, width=width, height=height,
|
img=img, rating_key=rating_key, width=width, height=height,
|
||||||
@@ -4077,7 +4128,7 @@ class WebInterface(object):
|
|||||||
if not os.path.exists(c_dir):
|
if not os.path.exists(c_dir):
|
||||||
os.mkdir(c_dir)
|
os.mkdir(c_dir)
|
||||||
|
|
||||||
clip = True if clip == 'true' else False
|
clip = helpers.bool_true(clip)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not plexpy.CONFIG.CACHE_IMAGES or refresh or 'indexes' in img:
|
if not plexpy.CONFIG.CACHE_IMAGES or refresh or 'indexes' in img:
|
||||||
@@ -4111,15 +4162,8 @@ class WebInterface(object):
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(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
|
if fallback in common.DEFAULT_IMAGES:
|
||||||
if fallback == 'poster':
|
fbi = common.DEFAULT_IMAGES[fallback]
|
||||||
fbi = common.DEFAULT_POSTER_THUMB
|
|
||||||
elif fallback == 'cover':
|
|
||||||
fbi = common.DEFAULT_COVER_THUMB
|
|
||||||
elif fallback == 'art':
|
|
||||||
fbi = common.DEFAULT_ART
|
|
||||||
|
|
||||||
if fbi:
|
|
||||||
fp = os.path.join(plexpy.PROG_DIR, 'data', fbi)
|
fp = os.path.join(plexpy.PROG_DIR, 'data', fbi)
|
||||||
return serve_file(path=fp, content_type='image/png')
|
return serve_file(path=fp, content_type='image/png')
|
||||||
|
|
||||||
@@ -4137,14 +4181,8 @@ class WebInterface(object):
|
|||||||
|
|
||||||
img_hash = args[0].split('.')[0]
|
img_hash = args[0].split('.')[0]
|
||||||
|
|
||||||
if img_hash in ('poster', 'cover', 'art'):
|
if img_hash in common.DEFAULT_IMAGES:
|
||||||
if img_hash == 'poster':
|
fbi = common.DEFAULT_IMAGES[img_hash]
|
||||||
fbi = common.DEFAULT_POSTER_THUMB
|
|
||||||
elif img_hash == 'cover':
|
|
||||||
fbi = common.DEFAULT_COVER_THUMB
|
|
||||||
elif img_hash == 'art':
|
|
||||||
fbi = common.DEFAULT_ART
|
|
||||||
|
|
||||||
fp = os.path.join(plexpy.PROG_DIR, 'data', fbi)
|
fp = os.path.join(plexpy.PROG_DIR, 'data', fbi)
|
||||||
return serve_file(path=fp, content_type='image/png')
|
return serve_file(path=fp, content_type='image/png')
|
||||||
|
|
||||||
@@ -4293,7 +4331,7 @@ class WebInterface(object):
|
|||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
|
|
||||||
delete_all = (delete_all == 'true')
|
delete_all = helpers.bool_true(delete_all)
|
||||||
|
|
||||||
data_factory = datafactory.DataFactory()
|
data_factory = datafactory.DataFactory()
|
||||||
result = data_factory.delete_img_info(rating_key=rating_key, service=service, delete_all=delete_all)
|
result = data_factory.delete_img_info(rating_key=rating_key, service=service, delete_all=delete_all)
|
||||||
@@ -4406,7 +4444,7 @@ class WebInterface(object):
|
|||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
def update_metadata(self, rating_key=None, query=None, update=False, **kwargs):
|
def update_metadata(self, rating_key=None, query=None, update=False, **kwargs):
|
||||||
query_string = query
|
query_string = query
|
||||||
update = True if update == 'True' else False
|
update = helpers.bool_true(update)
|
||||||
|
|
||||||
data_factory = datafactory.DataFactory()
|
data_factory = datafactory.DataFactory()
|
||||||
query = data_factory.get_search_query(rating_key=rating_key)
|
query = data_factory.get_search_query(rating_key=rating_key)
|
||||||
@@ -4579,6 +4617,7 @@ class WebInterface(object):
|
|||||||
"labels": [],
|
"labels": [],
|
||||||
"last_viewed_at": "1462165717",
|
"last_viewed_at": "1462165717",
|
||||||
"library_name": "TV Shows",
|
"library_name": "TV Shows",
|
||||||
|
"live": 0,
|
||||||
"media_index": "1",
|
"media_index": "1",
|
||||||
"media_info": [
|
"media_info": [
|
||||||
{
|
{
|
||||||
@@ -4588,6 +4627,9 @@ class WebInterface(object):
|
|||||||
"audio_codec": "ac3",
|
"audio_codec": "ac3",
|
||||||
"audio_profile": "",
|
"audio_profile": "",
|
||||||
"bitrate": "10617",
|
"bitrate": "10617",
|
||||||
|
"channel_call_sign": "",
|
||||||
|
"channel_identifier": "",
|
||||||
|
"channel_thumb": "",
|
||||||
"container": "mkv",
|
"container": "mkv",
|
||||||
"height": "1078",
|
"height": "1078",
|
||||||
"id": "257925",
|
"id": "257925",
|
||||||
@@ -4606,6 +4648,10 @@ class WebInterface(object):
|
|||||||
"video_bitrate": "10233",
|
"video_bitrate": "10233",
|
||||||
"video_codec": "h264",
|
"video_codec": "h264",
|
||||||
"video_codec_level": "41",
|
"video_codec_level": "41",
|
||||||
|
"video_color_primaries": "",
|
||||||
|
"video_color_range": "tv",
|
||||||
|
"video_color_space": "bt709",
|
||||||
|
"video_color_trc": "",
|
||||||
"video_frame_rate": "23.976",
|
"video_frame_rate": "23.976",
|
||||||
"video_height": "1078",
|
"video_height": "1078",
|
||||||
"video_language": "",
|
"video_language": "",
|
||||||
@@ -4665,7 +4711,7 @@ class WebInterface(object):
|
|||||||
"rating_image": "rottentomatoes://image.rating.ripe",
|
"rating_image": "rottentomatoes://image.rating.ripe",
|
||||||
"rating_key": "153037",
|
"rating_key": "153037",
|
||||||
"section_id": "2",
|
"section_id": "2",
|
||||||
"sort_title": "Game of Thrones",
|
"sort_title": "Red Woman",
|
||||||
"studio": "HBO",
|
"studio": "HBO",
|
||||||
"summary": "Jon Snow is dead. Daenerys meets a strong man. Cersei sees her daughter again.",
|
"summary": "Jon Snow is dead. Daenerys meets a strong man. Cersei sees her daughter again.",
|
||||||
"tagline": "",
|
"tagline": "",
|
||||||
@@ -4708,22 +4754,59 @@ class WebInterface(object):
|
|||||||
Returns:
|
Returns:
|
||||||
json:
|
json:
|
||||||
{"recently_added":
|
{"recently_added":
|
||||||
[{"added_at": "1461572396",
|
[{"actors": [
|
||||||
|
"Kit Harington",
|
||||||
|
"Emilia Clarke",
|
||||||
|
"Isaac Hempstead-Wright",
|
||||||
|
"Maisie Williams",
|
||||||
|
"Liam Cunningham",
|
||||||
|
],
|
||||||
|
"added_at": "1461572396",
|
||||||
|
"art": "/library/metadata/1219/art/1462175063",
|
||||||
|
"audience_rating": "8",
|
||||||
|
"audience_rating_image": "rottentomatoes://image.rating.upright",
|
||||||
|
"banner": "/library/metadata/1219/banner/1462175063",
|
||||||
|
"directors": [
|
||||||
|
"Jeremy Podeswa"
|
||||||
|
],
|
||||||
|
"duration": "2998290",
|
||||||
|
"full_title": "Game of Thrones - The Red Woman",
|
||||||
|
"genres": [
|
||||||
|
"Adventure",
|
||||||
|
"Drama",
|
||||||
|
"Fantasy"
|
||||||
|
],
|
||||||
"grandparent_rating_key": "1219",
|
"grandparent_rating_key": "1219",
|
||||||
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
|
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
|
||||||
"grandparent_title": "Game of Thrones",
|
"grandparent_title": "Game of Thrones",
|
||||||
"library_name": "",
|
"guid": "com.plexapp.agents.thetvdb://121361/6/1?lang=en",
|
||||||
|
"labels": [],
|
||||||
|
"last_viewed_at": "1462165717",
|
||||||
|
"library_name": "TV Shows",
|
||||||
"media_index": "1",
|
"media_index": "1",
|
||||||
"media_type": "episode",
|
"media_type": "episode",
|
||||||
"original_title": "",
|
"original_title": "",
|
||||||
|
"originally_available_at": "2016-04-24",
|
||||||
"parent_media_index": "6",
|
"parent_media_index": "6",
|
||||||
"parent_rating_key": "153036",
|
"parent_rating_key": "153036",
|
||||||
"parent_thumb": "/library/metadata/153036/thumb/1462175062",
|
"parent_thumb": "/library/metadata/153036/thumb/1462175062",
|
||||||
"parent_title": "",
|
"parent_title": "",
|
||||||
|
"rating": "7.8",
|
||||||
|
"rating_image": "rottentomatoes://image.rating.ripe",
|
||||||
"rating_key": "153037",
|
"rating_key": "153037",
|
||||||
"section_id": "2",
|
"section_id": "2",
|
||||||
|
"sort_title": "Red Woman",
|
||||||
|
"studio": "HBO",
|
||||||
|
"summary": "Jon Snow is dead. Daenerys meets a strong man. Cersei sees her daughter again.",
|
||||||
|
"tagline": "",
|
||||||
"thumb": "/library/metadata/153037/thumb/1462175060",
|
"thumb": "/library/metadata/153037/thumb/1462175060",
|
||||||
"title": "The Red Woman",
|
"title": "The Red Woman",
|
||||||
|
"user_rating": "9.0",
|
||||||
|
"updated_at": "1462175060",
|
||||||
|
"writers": [
|
||||||
|
"David Benioff",
|
||||||
|
"D. B. Weiss"
|
||||||
|
],
|
||||||
"year": "2016"
|
"year": "2016"
|
||||||
},
|
},
|
||||||
{...},
|
{...},
|
||||||
@@ -4946,7 +5029,11 @@ class WebInterface(object):
|
|||||||
"banner": "/library/metadata/1219/banner/1503306930",
|
"banner": "/library/metadata/1219/banner/1503306930",
|
||||||
"bif_thumb": "/library/parts/274169/indexes/sd/1000",
|
"bif_thumb": "/library/parts/274169/indexes/sd/1000",
|
||||||
"bitrate": "10617",
|
"bitrate": "10617",
|
||||||
|
"channel_call_sign": "",
|
||||||
|
"channel_identifier": "",
|
||||||
"channel_stream": 0,
|
"channel_stream": 0,
|
||||||
|
"channel_thumb": "",
|
||||||
|
"children_count": "",
|
||||||
"collections": [],
|
"collections": [],
|
||||||
"container": "mkv",
|
"container": "mkv",
|
||||||
"content_rating": "TV-MA",
|
"content_rating": "TV-MA",
|
||||||
@@ -4978,13 +5065,15 @@ class WebInterface(object):
|
|||||||
"ip_address": "10.10.10.1",
|
"ip_address": "10.10.10.1",
|
||||||
"ip_address_public": "64.123.23.111",
|
"ip_address_public": "64.123.23.111",
|
||||||
"is_admin": 1,
|
"is_admin": 1,
|
||||||
"is_allow_sync": null,
|
"is_allow_sync": 1,
|
||||||
"is_home_user": 1,
|
"is_home_user": 1,
|
||||||
"is_restricted": 0,
|
"is_restricted": 0,
|
||||||
"keep_history": 1,
|
"keep_history": 1,
|
||||||
"labels": [],
|
"labels": [],
|
||||||
"last_viewed_at": "1462165717",
|
"last_viewed_at": "1462165717",
|
||||||
"library_name": "TV Shows",
|
"library_name": "TV Shows",
|
||||||
|
"live": 0,
|
||||||
|
"live_uuid": "",
|
||||||
"local": "1",
|
"local": "1",
|
||||||
"location": "lan",
|
"location": "lan",
|
||||||
"machine_id": "lmd93nkn12k29j2lnm",
|
"machine_id": "lmd93nkn12k29j2lnm",
|
||||||
@@ -4993,8 +5082,8 @@ class WebInterface(object):
|
|||||||
"optimized_version": 0,
|
"optimized_version": 0,
|
||||||
"optimized_version_profile": "",
|
"optimized_version_profile": "",
|
||||||
"optimized_version_title": "",
|
"optimized_version_title": "",
|
||||||
"originally_available_at": "2016-04-24",
|
|
||||||
"original_title": "",
|
"original_title": "",
|
||||||
|
"originally_available_at": "2016-04-24",
|
||||||
"parent_guid": "com.plexapp.agents.thetvdb://121361/6?lang=en",
|
"parent_guid": "com.plexapp.agents.thetvdb://121361/6?lang=en",
|
||||||
"parent_media_index": "6",
|
"parent_media_index": "6",
|
||||||
"parent_rating_key": "153036",
|
"parent_rating_key": "153036",
|
||||||
@@ -5014,6 +5103,7 @@ class WebInterface(object):
|
|||||||
"rating_key": "153037",
|
"rating_key": "153037",
|
||||||
"relay": 0,
|
"relay": 0,
|
||||||
"section_id": "2",
|
"section_id": "2",
|
||||||
|
"secure": 1,
|
||||||
"session_id": "helf15l3rxgw01xxe0jf3l3d",
|
"session_id": "helf15l3rxgw01xxe0jf3l3d",
|
||||||
"session_key": "27",
|
"session_key": "27",
|
||||||
"shared_libraries": [
|
"shared_libraries": [
|
||||||
@@ -5052,15 +5142,21 @@ class WebInterface(object):
|
|||||||
"stream_subtitle_location": "",
|
"stream_subtitle_location": "",
|
||||||
"stream_video_bit_depth": "8",
|
"stream_video_bit_depth": "8",
|
||||||
"stream_video_bitrate": "10233",
|
"stream_video_bitrate": "10233",
|
||||||
|
"stream_video_chroma_subsampling": "4:2:0",
|
||||||
"stream_video_codec": "h264",
|
"stream_video_codec": "h264",
|
||||||
"stream_video_codec_level": "41",
|
"stream_video_codec_level": "41",
|
||||||
|
"stream_video_color_primaries": "",
|
||||||
|
"stream_video_color_range": "tv",
|
||||||
|
"stream_video_color_space": "bt709",
|
||||||
|
"stream_video_color_trc": "",
|
||||||
"stream_video_decision": "direct play",
|
"stream_video_decision": "direct play",
|
||||||
|
"stream_video_dynamic_range": "SDR",
|
||||||
"stream_video_framerate": "24p",
|
"stream_video_framerate": "24p",
|
||||||
|
"stream_video_full_resolution": "1080p",
|
||||||
"stream_video_height": "1078",
|
"stream_video_height": "1078",
|
||||||
"stream_video_language": "",
|
"stream_video_language": "",
|
||||||
"stream_video_language_code": "",
|
"stream_video_language_code": "",
|
||||||
"stream_video_ref_frames": "4",
|
"stream_video_ref_frames": "4",
|
||||||
"stream_video_full_resolution": "1080p",
|
|
||||||
"stream_video_resolution": "1080",
|
"stream_video_resolution": "1080",
|
||||||
"stream_video_scan_type": "progressive",
|
"stream_video_scan_type": "progressive",
|
||||||
"stream_video_width": "1920",
|
"stream_video_width": "1920",
|
||||||
@@ -5110,9 +5206,15 @@ class WebInterface(object):
|
|||||||
"username": "LordCommanderSnow",
|
"username": "LordCommanderSnow",
|
||||||
"video_bit_depth": "8",
|
"video_bit_depth": "8",
|
||||||
"video_bitrate": "10233",
|
"video_bitrate": "10233",
|
||||||
|
"video_chroma_subsampling": "4:2:0",
|
||||||
"video_codec": "h264",
|
"video_codec": "h264",
|
||||||
"video_codec_level": "41",
|
"video_codec_level": "41",
|
||||||
|
"video_color_primaries": "",
|
||||||
|
"video_color_range": "tv",
|
||||||
|
"video_color_space": "bt709",
|
||||||
|
"video_color_trc": ",
|
||||||
"video_decision": "direct play",
|
"video_decision": "direct play",
|
||||||
|
"video_dynamic_range": "SDR",
|
||||||
"video_frame_rate": "23.976",
|
"video_frame_rate": "23.976",
|
||||||
"video_framerate": "24p",
|
"video_framerate": "24p",
|
||||||
"video_full_resolution": "1080p",
|
"video_full_resolution": "1080p",
|
||||||
@@ -5366,8 +5468,10 @@ class WebInterface(object):
|
|||||||
[{"content_rating": "TV-MA",
|
[{"content_rating": "TV-MA",
|
||||||
"friendly_name": "",
|
"friendly_name": "",
|
||||||
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
|
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
|
||||||
|
"guid": "com.plexapp.agents.thetvdb://121361/6/1?lang=en",
|
||||||
"labels": [],
|
"labels": [],
|
||||||
"last_play": 1462380698,
|
"last_play": 1462380698,
|
||||||
|
"live": 0,
|
||||||
"media_type": "episode",
|
"media_type": "episode",
|
||||||
"platform": "",
|
"platform": "",
|
||||||
"platform_type": "",
|
"platform_type": "",
|
||||||
@@ -5873,8 +5977,8 @@ class WebInterface(object):
|
|||||||
subject=newsletter['subject'],
|
subject=newsletter['subject'],
|
||||||
body=newsletter['body'],
|
body=newsletter['body'],
|
||||||
message=newsletter['message'])
|
message=newsletter['message'])
|
||||||
preview = (preview == 'true')
|
preview = helpers.bool_true(preview)
|
||||||
raw = (raw == 'true')
|
raw = helpers.bool_true(raw)
|
||||||
|
|
||||||
if raw:
|
if raw:
|
||||||
cherrypy.response.headers['Content-Type'] = 'application/json;charset=UTF-8'
|
cherrypy.response.headers['Content-Type'] = 'application/json;charset=UTF-8'
|
||||||
|
Reference in New Issue
Block a user