mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-06 21:21:15 -07:00
Merge branch 'nightly' into python3
# Conflicts: # data/interfaces/default/current_activity_instance.html # plexpy/activity_handler.py # plexpy/graphs.py # plexpy/helpers.py # plexpy/pmsconnect.py # plexpy/version.py # plexpy/webserve.py
This commit is contained in:
commit
8d5bc88fd9
75 changed files with 2227 additions and 794 deletions
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
|
120
API.md
120
API.md
|
@ -395,7 +395,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 +431,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 +448,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 +469,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 +508,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 +572,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 +690,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 +717,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 +781,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 +885,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 +986,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 +1153,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 +1163,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 +1184,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 +1247,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 +1543,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 +1570,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 +1597,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 +1702,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 +1729,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 +1756,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 +1845,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 +2079,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 +2094,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 +2248,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 +2456,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 +2604,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
|
||||||
|
|
||||||
|
|
56
CHANGELOG.md
56
CHANGELOG.md
|
@ -1,5 +1,61 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v2.2.0-beta (2020-02-27)
|
||||||
|
|
||||||
|
* Important Note!
|
||||||
|
* All Live TV changes requires Plex Media Server 1.18.7 or higher.
|
||||||
|
* Monitoring:
|
||||||
|
* 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.
|
||||||
|
* API:
|
||||||
|
* New: Added ability to filter history using a "live" media type and by guid for the get_history 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)
|
||||||
|
|
||||||
|
* Monitoring:
|
||||||
|
* Fix: SDR source video being identified as HDR stream video.
|
||||||
|
* Notifications:
|
||||||
|
* Fix: Unable to select condition operator for video color parameters.
|
||||||
|
* UI:
|
||||||
|
* Fix: Capitalization for platforms on history tables.
|
||||||
|
|
||||||
|
|
||||||
|
## v2.1.43 (2020-02-03)
|
||||||
|
|
||||||
|
* Monitoring:
|
||||||
|
* New: Added HDR indicator on activity card.
|
||||||
|
* New: Added dynamic range to history steam info modal.
|
||||||
|
* Notifications:
|
||||||
|
* Fix: Webhook notification body sent as incorrect data type when Content-Type header is overridden.
|
||||||
|
* Fix: Telegram notification character limit incorrect for unicode characters.
|
||||||
|
* New: Added color and dynamic range notification parameters.
|
||||||
|
* Newsletters:
|
||||||
|
* Fix: Episodes and Albums plural spelling on recently added newsletter section headers.
|
||||||
|
* UI:
|
||||||
|
* Fix: Windows and macOS platform capitalization.
|
||||||
|
* Fix: Season number 0 not shown for episodes on history tables.
|
||||||
|
* Other:
|
||||||
|
* Change: Mask email addresses in logs.
|
||||||
|
* Change: Update deprecated GitHub access token URL parameter to Authorization header.
|
||||||
|
|
||||||
|
|
||||||
## v2.1.42 (2020-01-04)
|
## v2.1.42 (2020-01-04)
|
||||||
|
|
||||||
* Other:
|
* Other:
|
||||||
|
|
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.
|
|
@ -34,7 +34,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
|
||||||
|
@ -115,7 +115,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:
|
||||||
|
|
|
@ -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>
|
||||||
|
@ -318,21 +318,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 === null) {
|
if (result.update === false) {
|
||||||
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) {
|
|
||||||
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) {
|
|
||||||
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 />' +
|
|
||||||
'<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>';
|
|
||||||
$('#updatebar').html(msg).fadeIn();
|
|
||||||
} else if (result.update === false) {
|
|
||||||
showMsg('<i class="fa fa-check"></i> ' + result.message, false, true, 2000);
|
showMsg('<i class="fa fa-check"></i> ' + result.message, false, true, 2000);
|
||||||
|
} else {
|
||||||
|
if (result.update === null) {
|
||||||
|
msg = 'You are running an unknown version of Tautulli.<br />';
|
||||||
|
} 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 />';
|
||||||
|
} 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 />' +
|
||||||
|
'You are '+ result.commits_behind + ' commit' + (result.commits_behind > 1 ? 's' : '') + ' behind.<br />';
|
||||||
|
}
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
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],
|
||||||
|
@ -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;
|
||||||
|
@ -3134,6 +3134,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: cover;
|
||||||
|
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 +4014,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 +4067,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 six.moves.urllib.parse 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
|
% endif
|
||||||
% if data['live'] == 1:
|
% if data['live']:
|
||||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(images/poster-live.png);"></div>
|
% 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
|
||||||
% 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)'
|
||||||
|
@ -326,8 +330,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 +352,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 +382,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 +406,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 +440,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 +464,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>
|
||||||
|
|
|
@ -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>
|
||||||
|
@ -171,7 +184,7 @@ DOCUMENTATION :: END
|
||||||
% endif
|
% endif
|
||||||
% endfor
|
% endfor
|
||||||
<script>
|
<script>
|
||||||
$('.dashboard-stats-instance .dashboard-stats-info-scroller').scrollbar()
|
$('.dashboard-stats-instance .dashboard-stats-info-scroller').scrollbar();
|
||||||
|
|
||||||
function changeImages(elem) {
|
function changeImages(elem) {
|
||||||
var stat_id = $(elem).data('stat_id');
|
var stat_id = $(elem).data('stat_id');
|
||||||
|
@ -180,20 +193,25 @@ DOCUMENTATION :: END
|
||||||
var user_id = $(elem).data('user_id');
|
var user_id = $(elem).data('user_id');
|
||||||
var user_thumb = $(elem).data('user_thumb');
|
var user_thumb = $(elem).data('user_thumb');
|
||||||
var rating_key = $(elem).data('rating_key');
|
var rating_key = $(elem).data('rating_key');
|
||||||
var [height, fallback] = ($.inArray(stat_id, ['top_music', 'popular_music']) > -1) ? [300, 'cover'] : [450, 'poster'];
|
var guid = $(elem).data('guid');
|
||||||
var href;
|
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') {
|
if (stat_id === 'most_concurrent') {
|
||||||
return
|
return
|
||||||
} else if (stat_id == 'top_users') {
|
} else if (stat_id === 'top_users') {
|
||||||
$('#stats-thumb-' + stat_id).css('background-image', 'url(' + (user_thumb || 'images/gravatar-default.png') + ')');
|
$('#stats-thumb-' + stat_id).css('background-image', 'url(' + (user_thumb || 'images/gravatar-default.png') + ')');
|
||||||
if (user_id) {
|
if (user_id) {
|
||||||
href = 'user?user_id=' + user_id;
|
href = page('user', user_id);
|
||||||
} else {
|
|
||||||
href = '#';
|
|
||||||
}
|
}
|
||||||
$('#stats-thumb-url-' + stat_id).attr('href', href).prop('title', $(elem).data('friendly_name'));
|
$('#stats-thumb-url-' + stat_id).attr('href', href).prop('title', $(elem).data('friendly_name'));
|
||||||
} else if (stat_id == 'top_platforms') {
|
} else if (stat_id === 'top_platforms') {
|
||||||
$('#stats-thumb-' + stat_id).removeClass(function (index, className) {
|
$('#stats-thumb-' + stat_id).removeClass(function (index, className) {
|
||||||
return (className.match (/(^|\s)platform-\S+/g) || []).join(' ');
|
return (className.match (/(^|\s)platform-\S+/g) || []).join(' ');
|
||||||
}).addClass('platform-' + $(elem).data('platform'));
|
}).addClass('platform-' + $(elem).data('platform'));
|
||||||
|
@ -202,42 +220,35 @@ DOCUMENTATION :: END
|
||||||
}).addClass('platform-' + $(elem).data('platform') + '-rgba');
|
}).addClass('platform-' + $(elem).data('platform') + '-rgba');
|
||||||
} else {
|
} else {
|
||||||
if (rating_key) {
|
if (rating_key) {
|
||||||
href = 'info?rating_key=' + rating_key;
|
if (live) {
|
||||||
} else {
|
href = page('info', rating_key, guid, true, live);
|
||||||
href = '#';
|
} else {
|
||||||
|
href = page('info', rating_key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$('#stats-thumb-url-' + stat_id).attr('href', href).prop('title', $(elem).data('title'));
|
$('#stats-thumb-url-' + stat_id).attr('href', href).prop('title', $(elem).data('title'));
|
||||||
if (art) {
|
$('#stats-background-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', art, rating_key, 500, 280, 40, '282828', 3, fallback_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)');
|
$('#stats-thumb-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', thumb, rating_key, 300, height, null, null, null, fallback_poster) + ')');
|
||||||
} else {
|
$('#stats-thumb-' + stat_id + '-bg').css('background-image', 'url(' + page('pms_image_proxy', thumb, rating_key, 300, height, 60, '282828', 3, fallback_poster) + ')');
|
||||||
$('#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 () {
|
$('.dashboard-stats-info-item').mouseenter(function () {
|
||||||
changeImages(this)
|
changeImages(this);
|
||||||
if ($(this).data('stat_id') == 'last_watched') {
|
if ($(this).data('stat_id') === 'last_watched') {
|
||||||
var friendly_name = $(this).data('friendly_name');
|
var friendly_name = $(this).data('friendly_name');
|
||||||
var last_watch = moment($(this).data('last_watch'), 'X').format(date_format);
|
var last_watch = moment($(this).data('last_watch'), 'X').format(date_format);
|
||||||
$('#last-watched-header-info').html(friendly_name);
|
$('#last-watched-header-info').html(friendly_name);
|
||||||
} else if ($(this).data('stat_id') == 'most_concurrent') {
|
} else if ($(this).data('stat_id') === 'most_concurrent') {
|
||||||
var started = moment($(this).data('started'), 'X').format(date_format + ' ' + time_format);
|
var started = moment($(this).data('started'), 'X').format(date_format + ' ' + time_format);
|
||||||
$('#most-concurrent-header-info').html(started);
|
$('#most-concurrent-header-info').html(started);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$('.dashboard-stats-instance').mouseleave(function () {
|
$('.dashboard-stats-instance').mouseleave(function () {
|
||||||
changeImages($(this).find('.dashboard-stats-info-item').first())
|
changeImages($(this).find('.dashboard-stats-info-item').first());
|
||||||
if ($(this).data('stat_id') == 'last_watched') {
|
if ($(this).data('stat_id') === 'last_watched') {
|
||||||
$('#last-watched-header-info').text($(this).find('.dashboard-stats-info-item').first().data('friendly_name'));
|
$('#last-watched-header-info').text($(this).find('.dashboard-stats-info-item').first().data('friendly_name'));
|
||||||
} else if ($(this).data('stat_id') == 'most_concurrent') {
|
} else if ($(this).data('stat_id') === 'most_concurrent') {
|
||||||
$('#most-concurrent-header-info').text('streams');
|
$('#most-concurrent-header-info').text('streams');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
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,10 +547,12 @@
|
||||||
// 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 + '%');
|
||||||
var progress_bar = $('#progress-bar-' + key);
|
if (s.live !== 1) {
|
||||||
progress_bar.data('state', s.state);
|
var progress_bar = $('#progress-bar-' + key);
|
||||||
if (progress_bar.data('last_view_offset') !== s.view_offset) {
|
progress_bar.data('state', s.state);
|
||||||
progress_bar.data('last_view_offset', s.view_offset).data('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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add temporary class so we know which instances are still active
|
// Add temporary class so we know which instances are still active
|
||||||
|
@ -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');
|
||||||
|
|
||||||
|
|
|
@ -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.items():
|
for pattern, file_type in MEDIA_FLAGS_VIDEO.items():
|
||||||
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: {
|
||||||
|
|
|
@ -717,3 +717,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);
|
||||||
|
@ -115,7 +115,7 @@ history_table_options = {
|
||||||
"data": "platform",
|
"data": "platform",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== '') {
|
if (cellData !== '') {
|
||||||
$(td).html(capitalizeFirstLetter(cellData));
|
$(td).html(cellData);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"width": "10%",
|
"width": "10%",
|
||||||
|
@ -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') {
|
||||||
|
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>';
|
||||||
if (rowData['rating_key']) {
|
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>';
|
||||||
if (rowData['parent_title']) { parent_info = ' (' + rowData['parent_title'] + ')'; }
|
$(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="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=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>');
|
|
||||||
} else {
|
|
||||||
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,29 +82,37 @@ 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 {
|
|
||||||
$(td).html('n/a');
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$(td).html('n/a');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"width": "30%",
|
"width": "30%",
|
||||||
|
|
|
@ -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,7 +61,7 @@ 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'][:4] == '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(${data['library_thumb']});"></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>
|
||||||
|
@ -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')),
|
||||||
|
@ -35,7 +37,7 @@ DOCUMENTATION :: END
|
||||||
% if section_type in data:
|
% if section_type in data:
|
||||||
<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', '/:/resources/' + section_type + '-fanart.jpg', None, 500, 280, 40, '282828', 3, fallback='art')});">
|
||||||
<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>
|
||||||
<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">
|
||||||
|
@ -49,7 +51,7 @@ DOCUMENTATION :: END
|
||||||
<li class="dashboard-stats-info-item ${'expanded' if loop.index == 0 else ''}">
|
<li class="dashboard-stats-info-item ${'expanded' if loop.index == 0 else ''}">
|
||||||
<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,19 @@
|
||||||
</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 to the latest "${config['git_remote']}/${config['git_branch']}" branch.
|
||||||
|
</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 +2167,13 @@ $(document).ready(function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#reset_git_install").click(function () {
|
||||||
|
var msg = 'Are you sure you want to reset your Tautulli installtion?';
|
||||||
|
var url = 'reset_git_install';
|
||||||
|
confirmAjaxCall(url, msg);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
$('#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 +2551,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>' +
|
||||||
|
@ -2868,11 +2889,13 @@ $(document).ready(function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#install_geoip_db").click(function () {
|
$("#install_geoip_db").click(function () {
|
||||||
if ($.trim($("#maxmind_license_key").val()) === "") {
|
var maxmind_license_key = $("#maxmind_license_key");
|
||||||
$("#maxmind_license_key").focus();
|
maxmind_license_key.val($.trim(maxmind_license_key.val()));
|
||||||
|
if (maxmind_license_key.val() === "") {
|
||||||
|
maxmind_license_key.focus();
|
||||||
showMsg('<i class="fa fa-exclamation-circle"></i> Maxmind License Key is required.', false, true, 5000, true);
|
showMsg('<i class="fa fa-exclamation-circle"></i> Maxmind License Key is required.', false, true, 5000, true);
|
||||||
return false;
|
return false;
|
||||||
} else if (!(saveSettings())){
|
} else if (!(saveSettings())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var msg = 'Are you sure you want to install the GeoLite2 database?<br /><br />' +
|
var msg = 'Are you sure you want to install the GeoLite2 database?<br /><br />' +
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -590,6 +590,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, '
|
||||||
|
@ -609,7 +610,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)'
|
||||||
)
|
)
|
||||||
|
@ -657,7 +659,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
|
||||||
|
@ -1225,6 +1227,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')
|
||||||
|
@ -1332,6 +1370,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')
|
||||||
|
@ -1574,6 +1630,15 @@ def dbcheck():
|
||||||
c_db.execute(
|
c_db.execute(
|
||||||
'ALTER TABLE session_history_media_info ADD COLUMN stream_video_dynamic_range TEXT '
|
'ALTER TABLE session_history_media_info ADD COLUMN stream_video_dynamic_range TEXT '
|
||||||
)
|
)
|
||||||
|
|
||||||
|
result = c_db.execute('SELECT * FROM session_history_media_info '
|
||||||
|
'WHERE video_dynamic_range = "SDR" AND stream_video_dynamic_range = "HDR"').fetchone()
|
||||||
|
if result:
|
||||||
|
c_db.execute(
|
||||||
|
'UPDATE session_history_media_info SET stream_video_dynamic_range = "SDR" '
|
||||||
|
'WHERE video_dynamic_range = "SDR" AND stream_video_dynamic_range = "HDR"'
|
||||||
|
)
|
||||||
|
|
||||||
# Upgrade users table from earlier versions
|
# Upgrade users table from earlier versions
|
||||||
try:
|
try:
|
||||||
c_db.execute('SELECT do_notify FROM users')
|
c_db.execute('SELECT do_notify FROM users')
|
||||||
|
|
|
@ -63,9 +63,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']:
|
||||||
|
@ -99,7 +109,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
|
||||||
|
@ -112,9 +122,9 @@ class ActivityHandler(object):
|
||||||
if not session:
|
if not session:
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.debug("Tautulli ActivityHandler :: Session %s started by user %s (%s) with ratingKey %s (%s)."
|
logger.debug("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'})
|
||||||
|
|
||||||
|
@ -274,11 +284,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
|
||||||
|
|
|
@ -66,6 +66,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', ''),
|
||||||
|
@ -130,6 +133,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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,6 +154,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):
|
||||||
|
@ -240,7 +250,12 @@ class ActivityProcessor(object):
|
||||||
if not is_import:
|
if not is_import:
|
||||||
logger.debug("Tautulli ActivityProcessor :: Fetching metadata for item ratingKey %s" % session['rating_key'])
|
logger.debug("Tautulli ActivityProcessor :: Fetching metadata for item ratingKey %s" % session['rating_key'])
|
||||||
pms_connect = pmsconnect.PmsConnect()
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
metadata = pms_connect.get_metadata_details(rating_key=str(session['rating_key']))
|
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']))
|
||||||
if not metadata:
|
if not metadata:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
|
@ -284,38 +299,57 @@ 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)
|
||||||
|
|
||||||
# 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 ' \
|
|
||||||
'WHERE user_id = ? AND rating_key = ? ORDER BY id DESC LIMIT 2 '
|
|
||||||
|
|
||||||
args = [session['user_id'], session['rating_key']]
|
|
||||||
|
|
||||||
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
|
# Get the last insert row id
|
||||||
last_id = self.db.last_insert_id()
|
last_id = self.db.last_insert_id()
|
||||||
|
new_session = prev_session = None
|
||||||
|
prev_progress_percent = media_watched_percent = 0
|
||||||
|
|
||||||
if len(result) > 1:
|
if session['live']:
|
||||||
new_session = {'id': result[0]['id'],
|
# Check if we should group the session, select the last guid from the user
|
||||||
'rating_key': result[0]['rating_key'],
|
query = 'SELECT session_history.id, session_history_metadata.guid, session_history.reference_id ' \
|
||||||
'view_offset': result[0]['view_offset'],
|
'FROM session_history ' \
|
||||||
'user_id': result[0]['user_id'],
|
'JOIN session_history_metadata ON session_history.id == session_history_metadata.id ' \
|
||||||
'reference_id': result[0]['reference_id']}
|
'WHERE session_history.user_id = ? ORDER BY session_history.id DESC LIMIT 1 '
|
||||||
|
|
||||||
prev_session = {'id': result[1]['id'],
|
args = [session['user_id']]
|
||||||
'rating_key': result[1]['rating_key'],
|
|
||||||
'view_offset': result[1]['view_offset'],
|
|
||||||
'user_id': result[1]['user_id'],
|
|
||||||
'reference_id': result[1]['reference_id']}
|
|
||||||
|
|
||||||
watched_percent = {'movie': plexpy.CONFIG.MOVIE_WATCHED_PERCENT,
|
result = self.db.select(query=query, args=args)
|
||||||
'episode': plexpy.CONFIG.TV_WATCHED_PERCENT,
|
|
||||||
'track': plexpy.CONFIG.MUSIC_WATCHED_PERCENT
|
if len(result) > 0:
|
||||||
}
|
new_session = {'id': last_id,
|
||||||
prev_progress_percent = helpers.get_percent(prev_session['view_offset'], session['duration'])
|
'guid': metadata['guid'],
|
||||||
media_watched_percent = watched_percent.get(session['media_type'], 0)
|
'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
|
||||||
|
query = 'SELECT id, rating_key, view_offset, reference_id FROM session_history ' \
|
||||||
|
'WHERE user_id = ? AND rating_key = ? ORDER BY id DESC LIMIT 2 '
|
||||||
|
|
||||||
|
args = [session['user_id'], session['rating_key']]
|
||||||
|
|
||||||
|
result = self.db.select(query=query, args=args)
|
||||||
|
|
||||||
|
if len(result) > 1:
|
||||||
|
new_session = {'id': result[0]['id'],
|
||||||
|
'rating_key': result[0]['rating_key'],
|
||||||
|
'view_offset': result[0]['view_offset'],
|
||||||
|
'reference_id': result[0]['reference_id']}
|
||||||
|
|
||||||
|
prev_session = {'id': result[1]['id'],
|
||||||
|
'rating_key': result[1]['rating_key'],
|
||||||
|
'view_offset': result[1]['view_offset'],
|
||||||
|
'reference_id': result[1]['reference_id']}
|
||||||
|
|
||||||
|
watched_percent = {'movie': plexpy.CONFIG.MOVIE_WATCHED_PERCENT,
|
||||||
|
'episode': plexpy.CONFIG.TV_WATCHED_PERCENT,
|
||||||
|
'track': plexpy.CONFIG.MUSIC_WATCHED_PERCENT
|
||||||
|
}
|
||||||
|
prev_progress_percent = helpers.get_percent(prev_session['view_offset'], session['duration'])
|
||||||
|
media_watched_percent = watched_percent.get(session['media_type'], 0)
|
||||||
|
|
||||||
query = 'UPDATE session_history SET reference_id = ? WHERE id = ? '
|
query = 'UPDATE session_history SET reference_id = ? WHERE id = ? '
|
||||||
|
|
||||||
|
@ -326,7 +360,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']]
|
||||||
|
@ -458,7 +493,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("Tautulli ActivityProcessor :: Writing sessionKey %s session_history_metadata transaction..."
|
# logger.debug("Tautulli ActivityProcessor :: Writing sessionKey %s session_history_metadata transaction..."
|
||||||
|
|
|
@ -120,7 +120,7 @@ class API2(object):
|
||||||
# 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'):
|
||||||
|
|
|
@ -41,11 +41,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',
|
||||||
|
@ -358,6 +373,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'},
|
||||||
|
@ -371,8 +389,8 @@ NOTIFICATION_PARAMETERS = [
|
||||||
{'name': 'Stream Video Bitrate', 'type': 'int', 'value': 'stream_video_bitrate', 'description': 'The video bitrate (in kbps) of the stream.'},
|
{'name': 'Stream Video Bitrate', 'type': 'int', 'value': 'stream_video_bitrate', 'description': 'The video bitrate (in kbps) of the stream.'},
|
||||||
{'name': 'Stream Video Bit Depth', 'type': 'int', 'value': 'stream_video_bit_depth', 'description': 'The video bit depth of the stream.'},
|
{'name': 'Stream Video Bit Depth', 'type': 'int', 'value': 'stream_video_bit_depth', 'description': 'The video bit depth of the stream.'},
|
||||||
{'name': 'Stream Video Chroma Subsampling', 'type': 'str', 'value': 'stream_video_chroma_subsampling', 'description': 'The video chroma subsampling of the stream.'},
|
{'name': 'Stream Video Chroma Subsampling', 'type': 'str', 'value': 'stream_video_chroma_subsampling', 'description': 'The video chroma subsampling of the stream.'},
|
||||||
{'name': 'Stream Video Color Primaries', 'type': 'srt', 'value': 'stream_video_color_primaries', 'description': 'The video color primaries of the stream.'},
|
{'name': 'Stream Video Color Primaries', 'type': 'str', 'value': 'stream_video_color_primaries', 'description': 'The video color primaries of the stream.'},
|
||||||
{'name': 'Stream Video Color Range', 'type': 'srt', 'value': 'stream_video_color_range', 'description': 'The video color range of the stream.'},
|
{'name': 'Stream Video Color Range', 'type': 'str', 'value': 'stream_video_color_range', 'description': 'The video color range of the stream.'},
|
||||||
{'name': 'Stream Video Color Space', 'type': 'str', 'value': 'stream_video_color_space', 'description': 'The video color space of the stream.'},
|
{'name': 'Stream Video Color Space', 'type': 'str', 'value': 'stream_video_color_space', 'description': 'The video color space of the stream.'},
|
||||||
{'name': 'Stream Video Color Transfer Function', 'type': 'str', 'value': 'stream_video_color_trc', 'description': 'The video transfer function of the stream.'},
|
{'name': 'Stream Video Color Transfer Function', 'type': 'str', 'value': 'stream_video_color_trc', 'description': 'The video transfer function of the stream.'},
|
||||||
{'name': 'Stream Video Dynamic Range', 'type': 'str', 'value': 'stream_video_dynamic_range', 'description': 'The video dynamic range of the stream.', 'example': 'HDR or SDR'},
|
{'name': 'Stream Video Dynamic Range', 'type': 'str', 'value': 'stream_video_dynamic_range', 'description': 'The video dynamic range of the stream.', 'example': 'HDR or SDR'},
|
||||||
|
@ -484,8 +502,8 @@ NOTIFICATION_PARAMETERS = [
|
||||||
{'name': 'Video Bitrate', 'type': 'int', 'value': 'video_bitrate', 'description': 'The video bitrate of the original media.'},
|
{'name': 'Video Bitrate', 'type': 'int', 'value': 'video_bitrate', 'description': 'The video bitrate of the original media.'},
|
||||||
{'name': 'Video Bit Depth', 'type': 'int', 'value': 'video_bit_depth', 'description': 'The video bit depth of the original media.'},
|
{'name': 'Video Bit Depth', 'type': 'int', 'value': 'video_bit_depth', 'description': 'The video bit depth of the original media.'},
|
||||||
{'name': 'Video Chroma Subsampling', 'type': 'str', 'value': 'video_chroma_subsampling', 'description': 'The video chroma subsampling of the original media.'},
|
{'name': 'Video Chroma Subsampling', 'type': 'str', 'value': 'video_chroma_subsampling', 'description': 'The video chroma subsampling of the original media.'},
|
||||||
{'name': 'Video Color Primaries', 'type': 'srt', 'value': 'video_color_primaries', 'description': 'The video color primaries of the original media.'},
|
{'name': 'Video Color Primaries', 'type': 'str', 'value': 'video_color_primaries', 'description': 'The video color primaries of the original media.'},
|
||||||
{'name': 'Video Color Range', 'type': 'srt', 'value': 'video_color_range', 'description': 'The video color range of the original media.'},
|
{'name': 'Video Color Range', 'type': 'str', 'value': 'video_color_range', 'description': 'The video color range of the original media.'},
|
||||||
{'name': 'Video Color Space', 'type': 'str', 'value': 'video_color_space', 'description': 'The video color space of the original media.'},
|
{'name': 'Video Color Space', 'type': 'str', 'value': 'video_color_space', 'description': 'The video color space of the original media.'},
|
||||||
{'name': 'Video Color Transfer Function', 'type': 'str', 'value': 'video_color_trc', 'description': 'The video transfer function of the original media.'},
|
{'name': 'Video Color Transfer Function', 'type': 'str', 'value': 'video_color_trc', 'description': 'The video transfer function of the original media.'},
|
||||||
{'name': 'Video Dynamic Range', 'type': 'str', 'value': 'video_dynamic_range', 'description': 'The video dynamic range of the original media.', 'example': 'HDR or SDR'},
|
{'name': 'Video Dynamic Range', 'type': 'str', 'value': 'video_dynamic_range', 'description': 'The video dynamic range of the original media.', 'example': 'HDR or SDR'},
|
||||||
|
|
|
@ -73,6 +73,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', ''),
|
||||||
|
@ -944,3 +945,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
|
||||||
|
|
|
@ -104,6 +104,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',
|
||||||
|
@ -152,6 +156,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',
|
||||||
|
@ -216,6 +224,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'] >= old_div(watched_percent[item['media_type']],2):
|
elif item['percent_complete'] >= old_div(watched_percent[item['media_type']],2):
|
||||||
|
@ -240,6 +251,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'],
|
||||||
|
@ -253,6 +265,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,
|
||||||
|
@ -296,7 +310,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) ' \
|
||||||
|
@ -333,6 +347,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)
|
||||||
|
@ -346,7 +362,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) - ' \
|
||||||
|
@ -382,6 +398,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)
|
||||||
|
@ -394,7 +412,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) ' \
|
||||||
|
@ -418,7 +436,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'],
|
||||||
|
@ -430,6 +448,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)
|
||||||
|
@ -443,7 +463,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) - ' \
|
||||||
|
@ -466,7 +486,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'],
|
||||||
|
@ -479,6 +499,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)
|
||||||
|
@ -492,7 +514,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) ' \
|
||||||
|
@ -528,6 +550,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)
|
||||||
|
@ -542,7 +566,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) - ' \
|
||||||
|
@ -578,6 +602,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)
|
||||||
|
@ -694,7 +720,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, ' \
|
||||||
|
@ -740,6 +766,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)
|
||||||
|
@ -1002,10 +1030,17 @@ class DataFactory(object):
|
||||||
stream_output = {k: v or '' for k, v in list(stream_output.items())}
|
stream_output = {k: v or '' for k, v in list(stream_output.items())}
|
||||||
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, ' \
|
||||||
|
@ -1025,15 +1060,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 = []
|
||||||
|
|
||||||
|
@ -1050,9 +1088,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'],
|
||||||
|
@ -1066,6 +1108,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'],
|
||||||
|
@ -1088,6 +1131,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)
|
||||||
|
|
|
@ -146,6 +146,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_)
|
||||||
|
@ -153,6 +156,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])
|
||||||
|
|
255
plexpy/graphs.py
255
plexpy/graphs.py
|
@ -27,6 +27,7 @@ import plexpy
|
||||||
from plexpy import common
|
from plexpy import common
|
||||||
from plexpy import database
|
from plexpy import database
|
||||||
from plexpy import logger
|
from plexpy import logger
|
||||||
|
from plexpy import libraries
|
||||||
from plexpy import session
|
from plexpy import session
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,10 +56,12 @@ class Graphs(object):
|
||||||
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' \
|
||||||
|
@ -68,13 +71,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)
|
||||||
|
@ -93,6 +100,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')
|
||||||
|
@ -100,20 +108,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}
|
||||||
|
@ -121,9 +133,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):
|
||||||
|
@ -154,10 +178,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' \
|
||||||
|
@ -175,13 +201,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)
|
||||||
|
@ -202,26 +232,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}
|
||||||
|
@ -229,9 +264,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):
|
||||||
|
@ -254,10 +301,12 @@ class Graphs(object):
|
||||||
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' \
|
||||||
|
@ -267,13 +316,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)
|
||||||
|
@ -283,35 +336,40 @@ class Graphs(object):
|
||||||
logger.warn("Tautulli Graphs :: Unable to execute database query for get_total_plays_per_hourofday: %s." % e)
|
logger.warn("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}
|
||||||
|
@ -319,14 +377,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'
|
||||||
|
|
||||||
|
@ -346,10 +414,12 @@ class Graphs(object):
|
||||||
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' \
|
||||||
|
@ -359,13 +429,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)
|
||||||
|
@ -391,6 +465,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')
|
||||||
|
@ -398,20 +473,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}
|
||||||
|
@ -419,9 +498,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):
|
||||||
|
@ -444,11 +535,15 @@ class Graphs(object):
|
||||||
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 ' \
|
||||||
|
@ -457,15 +552,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 ' \
|
||||||
|
@ -480,12 +579,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}
|
||||||
|
@ -493,9 +594,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):
|
||||||
|
@ -521,11 +634,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 ' \
|
||||||
|
@ -538,15 +655,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 ' \
|
||||||
|
@ -562,6 +683,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()
|
||||||
|
|
||||||
|
@ -573,6 +695,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}
|
||||||
|
@ -580,9 +703,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):
|
||||||
|
|
|
@ -26,6 +26,7 @@ from builtins import str
|
||||||
from past.builtins import basestring
|
from past.builtins import basestring
|
||||||
from past.utils import old_div
|
from past.utils import old_div
|
||||||
|
|
||||||
|
import arrow
|
||||||
import base64
|
import base64
|
||||||
import certifi
|
import certifi
|
||||||
import cloudinary
|
import cloudinary
|
||||||
|
@ -56,6 +57,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
|
||||||
|
@ -237,6 +239,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 = ''
|
||||||
|
@ -1256,3 +1274,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
|
||||||
|
|
|
@ -96,6 +96,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
|
||||||
|
|
||||||
|
@ -293,6 +324,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'
|
||||||
|
@ -356,6 +391,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'])
|
||||||
|
@ -707,7 +745,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):
|
||||||
|
@ -887,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 = ? ' \
|
||||||
|
@ -925,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'],
|
||||||
|
|
|
@ -547,8 +547,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
|
||||||
|
@ -700,12 +707,13 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
|
||||||
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)
|
||||||
|
@ -829,6 +837,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'],
|
||||||
|
@ -1248,14 +1259,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)
|
||||||
|
|
||||||
img_split = img.split('/')
|
if img.startswith('/library/metadata'):
|
||||||
img = '/'.join(img_split[:5])
|
img_split = img.split('/')
|
||||||
rating_key = rating_key or img_split[3]
|
img = '/'.join(img_split[:5])
|
||||||
|
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()
|
||||||
|
|
||||||
|
@ -1265,7 +1279,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
|
||||||
|
@ -1349,14 +1363,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)
|
||||||
|
|
||||||
img_split = img.split('/')
|
if img.startswith('/library/metadata'):
|
||||||
img = '/'.join(img_split[:5])
|
img_split = img.split('/')
|
||||||
rating_key = rating_key or img_split[3]
|
img = '/'.join(img_split[:5])
|
||||||
|
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)
|
||||||
|
|
|
@ -3533,7 +3533,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):
|
||||||
|
@ -3579,8 +3579,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'}
|
||||||
|
|
|
@ -581,7 +581,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.
|
||||||
|
|
||||||
|
@ -591,7 +592,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)
|
||||||
|
|
||||||
|
@ -606,14 +607,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
|
||||||
|
|
||||||
|
@ -729,7 +734,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.cast_to_int(helpers.get_xml_attr(metadata_main, 'leafCount'))
|
'children_count': helpers.cast_to_int(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':
|
||||||
|
@ -781,12 +787,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.cast_to_int(helpers.get_xml_attr(metadata_main, 'leafCount'))
|
'children_count': helpers.cast_to_int(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')
|
||||||
show_details = self.get_metadata_details(parent_rating_key)
|
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)
|
||||||
|
|
||||||
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,
|
||||||
|
@ -800,22 +813,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'),
|
||||||
|
@ -823,32 +836,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': '{} - {}'.format(helpers.get_xml_attr(metadata_main, 'parentTitle'),
|
'full_title': '{} - {}'.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.cast_to_int(helpers.get_xml_attr(metadata_main, 'leafCount'))
|
'children_count': helpers.cast_to_int(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')
|
||||||
show_details = self.get_metadata_details(grandparent_rating_key)
|
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)
|
||||||
|
|
||||||
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), '')
|
||||||
|
@ -866,7 +885,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'),
|
||||||
|
@ -881,7 +900,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'),
|
||||||
|
@ -891,13 +910,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': '{} - {}'.format(helpers.get_xml_attr(metadata_main, 'grandparentTitle'),
|
'full_title': '{} - {}'.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.cast_to_int(helpers.get_xml_attr(metadata_main, 'leafCount'))
|
'children_count': helpers.cast_to_int(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':
|
||||||
|
@ -944,12 +964,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.cast_to_int(helpers.get_xml_attr(metadata_main, 'leafCount'))
|
'children_count': helpers.cast_to_int(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,
|
||||||
|
@ -965,7 +986,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'),
|
||||||
|
@ -978,7 +999,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'),
|
||||||
|
@ -994,12 +1015,13 @@ class PmsConnect(object):
|
||||||
'collections': collections,
|
'collections': collections,
|
||||||
'full_title': '{} - {}'.format(helpers.get_xml_attr(metadata_main, 'parentTitle'),
|
'full_title': '{} - {}'.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.cast_to_int(helpers.get_xml_attr(metadata_main, 'leafCount'))
|
'children_count': helpers.cast_to_int(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,
|
||||||
|
@ -1025,12 +1047,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'),
|
||||||
|
@ -1041,12 +1063,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': '{} - {}'.format(helpers.get_xml_attr(metadata_main, 'title'),
|
'full_title': '{} - {}'.format(helpers.get_xml_attr(metadata_main, 'title'),
|
||||||
track_artist),
|
track_artist),
|
||||||
'children_count': helpers.cast_to_int(helpers.get_xml_attr(metadata_main, 'leafCount'))
|
'children_count': helpers.cast_to_int(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':
|
||||||
|
@ -1093,12 +1116,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.cast_to_int(helpers.get_xml_attr(metadata_main, 'leafCount'))
|
'children_count': helpers.cast_to_int(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,
|
||||||
|
@ -1138,12 +1162,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': '{} - {}'.format(helpers.get_xml_attr(metadata_main, 'parentTitle') or library_name,
|
'full_title': '{} - {}'.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.cast_to_int(helpers.get_xml_attr(metadata_main, 'leafCount'))
|
'children_count': helpers.cast_to_int(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':
|
||||||
|
@ -1194,7 +1219,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.cast_to_int(helpers.get_xml_attr(metadata_main, 'leafCount'))
|
'children_count': helpers.cast_to_int(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':
|
||||||
|
@ -1242,17 +1268,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')
|
||||||
|
@ -1263,8 +1303,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'),
|
||||||
|
@ -1324,35 +1363,36 @@ 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 = ''
|
video_full_resolution = common.VIDEO_RESOLUTION_OVERRIDES.get(
|
||||||
if video_full_resolution_scan_type is not None:
|
video_resolution, video_resolution + (video_full_resolution_scan_type[:1] or 'p')
|
||||||
video_full_resolution = common.VIDEO_RESOLUTION_OVERRIDES.get(
|
)
|
||||||
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'),
|
||||||
'width': helpers.get_xml_attr(media, 'width'),
|
'width': helpers.get_xml_attr(media, 'width'),
|
||||||
'aspect_ratio': helpers.get_xml_attr(media, 'aspectRatio'),
|
'aspect_ratio': helpers.get_xml_attr(media, 'aspectRatio'),
|
||||||
'video_codec': helpers.get_xml_attr(media, 'videoCodec'),
|
'video_codec': helpers.get_xml_attr(media, 'videoCodec'),
|
||||||
'video_resolution': video_resolution,
|
'video_resolution': video_resolution,
|
||||||
'video_full_resolution': video_full_resolution,
|
'video_full_resolution': video_full_resolution,
|
||||||
'video_framerate': helpers.get_xml_attr(media, 'videoFrameRate'),
|
'video_framerate': helpers.get_xml_attr(media, 'videoFrameRate'),
|
||||||
'video_profile': helpers.get_xml_attr(media, 'videoProfile'),
|
'video_profile': helpers.get_xml_attr(media, 'videoProfile'),
|
||||||
'audio_codec': helpers.get_xml_attr(media, 'audioCodec'),
|
'audio_codec': helpers.get_xml_attr(media, '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(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'),
|
||||||
'parts': parts
|
'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
|
||||||
|
}
|
||||||
|
|
||||||
video_full_resolution = helpers.get_xml_attr(media, 'videoResolution').lower()
|
medias.append(media_info)
|
||||||
|
|
||||||
metadata['media_info'] = medias
|
metadata['media_info'] = medias
|
||||||
|
|
||||||
|
@ -1474,7 +1514,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.
|
||||||
|
|
||||||
|
@ -1501,17 +1541,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'])
|
||||||
|
@ -1522,7 +1562,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
|
||||||
|
@ -1798,7 +1838,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')
|
||||||
|
|
||||||
|
@ -1875,13 +1915,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'),
|
||||||
|
@ -1894,9 +1940,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', [])
|
||||||
|
@ -1983,15 +2031,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
|
||||||
|
@ -1999,13 +2047,15 @@ 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'
|
||||||
|
|
||||||
if helpers.cast_to_int(video_details['stream_video_bit_depth']) > 8 \
|
if stream_details['video_dynamic_range'] == 'HDR' \
|
||||||
|
and video_details['stream_video_decision'] != 'transcode' \
|
||||||
|
or helpers.cast_to_int(video_details['stream_video_bit_depth']) > 8 \
|
||||||
and video_details['stream_video_color_space'] == 'bt2020nc':
|
and video_details['stream_video_color_space'] == 'bt2020nc':
|
||||||
stream_details['stream_video_dynamic_range'] = 'HDR'
|
stream_details['stream_video_dynamic_range'] = 'HDR'
|
||||||
else:
|
else:
|
||||||
|
@ -2040,7 +2090,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 = ''
|
||||||
|
|
||||||
|
@ -2689,10 +2739,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.parse.urlencode({'X-Plex-Token': self.token}))}
|
params = {'url': '%s&%s' % (img, urllib.parse.urlencode({'X-Plex-Token': self.token}))}
|
||||||
else:
|
else:
|
||||||
params = {'url': 'http://127.0.0.1:32400%s?%s' % (img, urllib.parse.urlencode({'X-Plex-Token': self.token}))}
|
params = {'url': 'http://127.0.0.1:32400%s?%s' % (img, urllib.parse.urlencode({'X-Plex-Token': self.token}))}
|
||||||
|
|
|
@ -126,6 +126,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',
|
||||||
|
@ -189,6 +193,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']),
|
||||||
|
@ -235,6 +242,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',
|
||||||
|
@ -289,6 +300,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']
|
||||||
|
@ -544,11 +558,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 = ? ' \
|
||||||
|
@ -563,30 +577,33 @@ class Users(object):
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
for row in result:
|
for row in result:
|
||||||
if row['media_type'] == 'episode' and row['parent_thumb']:
|
if row['media_type'] == 'episode' and row['parent_thumb']:
|
||||||
thumb = row['parent_thumb']
|
thumb = row['parent_thumb']
|
||||||
elif row['media_type'] == 'episode':
|
elif row['media_type'] == 'episode':
|
||||||
thumb = row['grandparent_thumb']
|
thumb = row['grandparent_thumb']
|
||||||
else:
|
else:
|
||||||
thumb = row['thumb']
|
thumb = row['thumb']
|
||||||
|
|
||||||
recent_output = {'row_id': row['id'],
|
recent_output = {'row_id': row['id'],
|
||||||
'media_type': row['media_type'],
|
'media_type': row['media_type'],
|
||||||
'rating_key': row['rating_key'],
|
'rating_key': row['rating_key'],
|
||||||
'parent_rating_key': row['parent_rating_key'],
|
'parent_rating_key': row['parent_rating_key'],
|
||||||
'grandparent_rating_key': row['grandparent_rating_key'],
|
'grandparent_rating_key': row['grandparent_rating_key'],
|
||||||
'title': row['title'],
|
'title': row['title'],
|
||||||
'parent_title': row['parent_title'],
|
'parent_title': row['parent_title'],
|
||||||
'grandparent_title': row['grandparent_title'],
|
'grandparent_title': row['grandparent_title'],
|
||||||
'original_title': row['original_title'],
|
'original_title': row['original_title'],
|
||||||
'thumb': thumb,
|
'thumb': thumb,
|
||||||
'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'],
|
||||||
'time': row['started'],
|
'originally_available_at': row['originally_available_at'],
|
||||||
'user': row['user']
|
'live': row['live'],
|
||||||
}
|
'guid': row['guid'],
|
||||||
recently_watched.append(recent_output)
|
'time': row['started'],
|
||||||
|
'user': row['user']
|
||||||
|
}
|
||||||
|
recently_watched.append(recent_output)
|
||||||
|
|
||||||
return recently_watched
|
return recently_watched
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,21 @@
|
||||||
from __future__ import unicode_literals
|
# -*- coding: utf-8 -*-
|
||||||
PLEXPY_BRANCH = "master"
|
|
||||||
PLEXPY_RELEASE_VERSION = "v2.1.42"
|
# This file is part of Tautulli.
|
||||||
|
#
|
||||||
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
PLEXPY_BRANCH = "beta"
|
||||||
|
PLEXPY_RELEASE_VERSION = "v2.2.0-beta"
|
||||||
|
|
|
@ -124,20 +124,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:
|
||||||
|
current_version = f.read().strip(' \n\r')
|
||||||
with open(version_file, 'r') as f:
|
|
||||||
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):
|
||||||
|
@ -167,13 +171,17 @@ def check_update(auto_update=False, notify=False):
|
||||||
def check_github(auto_update=False, notify=False):
|
def check_github(auto_update=False, notify=False):
|
||||||
plexpy.COMMITS_BEHIND = 0
|
plexpy.COMMITS_BEHIND = 0
|
||||||
|
|
||||||
|
if plexpy.CONFIG.GIT_TOKEN:
|
||||||
|
headers = {'Authorization': 'token {}'.format(plexpy.CONFIG.GIT_TOKEN)}
|
||||||
|
else:
|
||||||
|
headers = {}
|
||||||
|
|
||||||
# Get the latest version available from github
|
# Get the latest version available from github
|
||||||
logger.info('Retrieving latest version information from GitHub')
|
logger.info('Retrieving latest version information from GitHub')
|
||||||
url = 'https://api.github.com/repos/%s/%s/commits/%s' % (plexpy.CONFIG.GIT_USER,
|
url = 'https://api.github.com/repos/%s/%s/commits/%s' % (plexpy.CONFIG.GIT_USER,
|
||||||
plexpy.CONFIG.GIT_REPO,
|
plexpy.CONFIG.GIT_REPO,
|
||||||
plexpy.CONFIG.GIT_BRANCH)
|
plexpy.CONFIG.GIT_BRANCH)
|
||||||
if plexpy.CONFIG.GIT_TOKEN: url = url + '?access_token=%s' % plexpy.CONFIG.GIT_TOKEN
|
version = request.request_json(url, headers=headers, timeout=20, validator=lambda x: type(x) == dict)
|
||||||
version = request.request_json(url, timeout=20, validator=lambda x: type(x) == dict)
|
|
||||||
|
|
||||||
if version is None:
|
if version is None:
|
||||||
logger.warn('Could not get the latest version from GitHub. Are you running a local development version?')
|
logger.warn('Could not get the latest version from GitHub. Are you running a local development version?')
|
||||||
|
@ -196,8 +204,8 @@ def check_github(auto_update=False, notify=False):
|
||||||
plexpy.CONFIG.GIT_REPO,
|
plexpy.CONFIG.GIT_REPO,
|
||||||
plexpy.LATEST_VERSION,
|
plexpy.LATEST_VERSION,
|
||||||
plexpy.CURRENT_VERSION)
|
plexpy.CURRENT_VERSION)
|
||||||
if plexpy.CONFIG.GIT_TOKEN: url = url + '?access_token=%s' % plexpy.CONFIG.GIT_TOKEN
|
commits = request.request_json(url, headers=headers, timeout=20, whitelist_status_code=404,
|
||||||
commits = request.request_json(url, timeout=20, whitelist_status_code=404, validator=lambda x: type(x) == dict)
|
validator=lambda x: type(x) == dict)
|
||||||
|
|
||||||
if commits is None:
|
if commits is None:
|
||||||
logger.warn('Could not get commits behind from GitHub.')
|
logger.warn('Could not get commits behind from GitHub.')
|
||||||
|
@ -237,7 +245,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)
|
||||||
|
|
||||||
|
@ -252,23 +260,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')
|
||||||
|
|
||||||
|
@ -326,6 +337,34 @@ def update():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def reset():
|
||||||
|
if plexpy.INSTALL_TYPE == 'git':
|
||||||
|
logger.info('Attempting to reset git install to "%s/%s"' % (plexpy.CONFIG.GIT_REMOTE, plexpy.CONFIG.GIT_BRANCH))
|
||||||
|
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(plexpy.CONFIG.GIT_REMOTE,
|
||||||
|
plexpy.CONFIG.GIT_BRANCH))
|
||||||
|
output, err = runGit('pull {} {}'.format(plexpy.CONFIG.GIT_REMOTE,
|
||||||
|
plexpy.CONFIG.GIT_BRANCH))
|
||||||
|
|
||||||
|
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)
|
output, err = runGit('fetch %s' % plexpy.CONFIG.GIT_REMOTE)
|
||||||
|
@ -338,9 +377,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):
|
||||||
|
|
|
@ -288,7 +288,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:
|
||||||
|
@ -393,15 +393,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": "",
|
||||||
|
@ -677,6 +680,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": "",
|
||||||
|
@ -712,7 +716,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
|
||||||
|
@ -1055,13 +1059,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",
|
||||||
|
@ -1267,12 +1274,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",
|
||||||
|
@ -1607,8 +1617,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"
|
||||||
|
@ -1633,10 +1644,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": "",
|
||||||
|
@ -1694,31 +1708,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)
|
||||||
|
@ -1779,6 +1799,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",
|
||||||
|
@ -1793,6 +1814,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",
|
||||||
|
@ -1888,7 +1910,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": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -1927,7 +1950,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": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -1966,7 +1990,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": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -2005,7 +2030,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": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -2044,7 +2070,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": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -2083,7 +2110,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": [...]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -3076,7 +3104,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)
|
||||||
|
|
||||||
|
@ -3482,7 +3510,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.'}
|
||||||
|
|
||||||
|
@ -3647,7 +3675,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)
|
||||||
|
@ -3710,7 +3738,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,
|
||||||
|
@ -3720,7 +3748,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]
|
||||||
|
@ -3774,7 +3802,7 @@ class WebInterface(object):
|
||||||
logger.info("New API key generated.")
|
logger.info("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
|
||||||
|
@ -3804,46 +3832,51 @@ 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,
|
||||||
'current_release': plexpy.common.RELEASE,
|
'current_release': plexpy.common.RELEASE,
|
||||||
'latest_release': plexpy.LATEST_RELEASE,
|
'latest_release': plexpy.LATEST_RELEASE,
|
||||||
'release_url': helpers.anon_url(
|
'release_url': helpers.anon_url(
|
||||||
'https://github.com/%s/%s/releases/tag/%s'
|
'https://github.com/%s/%s/releases/tag/%s'
|
||||||
% (plexpy.CONFIG.GIT_USER,
|
% (plexpy.CONFIG.GIT_USER,
|
||||||
plexpy.CONFIG.GIT_REPO,
|
plexpy.CONFIG.GIT_REPO,
|
||||||
plexpy.LATEST_RELEASE))
|
plexpy.LATEST_RELEASE))
|
||||||
}
|
}
|
||||||
|
|
||||||
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.',
|
||||||
'current_version': plexpy.CURRENT_VERSION,
|
'current_version': plexpy.CURRENT_VERSION,
|
||||||
'latest_version': plexpy.LATEST_VERSION,
|
'latest_version': plexpy.LATEST_VERSION,
|
||||||
'commits_behind': plexpy.COMMITS_BEHIND,
|
'commits_behind': plexpy.COMMITS_BEHIND,
|
||||||
'compare_url': helpers.anon_url(
|
'compare_url': helpers.anon_url(
|
||||||
'https://github.com/%s/%s/compare/%s...%s'
|
'https://github.com/%s/%s/compare/%s...%s'
|
||||||
% (plexpy.CONFIG.GIT_USER,
|
% (plexpy.CONFIG.GIT_USER,
|
||||||
plexpy.CONFIG.GIT_REPO,
|
plexpy.CONFIG.GIT_REPO,
|
||||||
plexpy.CURRENT_VERSION,
|
plexpy.CURRENT_VERSION,
|
||||||
plexpy.LATEST_VERSION))
|
plexpy.LATEST_VERSION))
|
||||||
}
|
}
|
||||||
|
|
||||||
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"))
|
||||||
|
@ -3873,6 +3906,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()
|
||||||
|
@ -3891,18 +3927,30 @@ 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
|
||||||
|
@cherrypy.tools.json_out()
|
||||||
|
@requireAuth(member_of("admin"))
|
||||||
|
def reset_git_install(self, **kwargs):
|
||||||
|
result = versioncheck.reset()
|
||||||
|
|
||||||
|
if result:
|
||||||
|
return {'result': 'success', 'message': 'Tautulli installation reset.'}
|
||||||
|
else:
|
||||||
|
return {'result': 'error', 'message': 'Reset installation failed.'}
|
||||||
|
|
||||||
|
|
||||||
@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()
|
||||||
|
|
||||||
|
@ -3912,7 +3960,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)
|
||||||
|
|
||||||
|
@ -3925,7 +3973,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)
|
||||||
|
@ -3945,12 +3993,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()
|
||||||
|
@ -4046,10 +4094,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
|
||||||
|
|
||||||
|
@ -4058,20 +4106,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)
|
||||||
|
|
||||||
img_split = img.split('/')
|
if img.startswith('/library/metadata'):
|
||||||
img = '/'.join(img_split[:5])
|
img_split = img.split('/')
|
||||||
rating_key = rating_key or img_split[3]
|
img = '/'.join(img_split[:5])
|
||||||
|
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,
|
||||||
|
@ -4088,7 +4143,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:
|
||||||
|
@ -4121,16 +4176,9 @@ class WebInterface(object):
|
||||||
raise Exception('PMS image request failed')
|
raise Exception('PMS image request failed')
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn('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')
|
||||||
|
|
||||||
|
@ -4148,14 +4196,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')
|
||||||
|
|
||||||
|
@ -4304,7 +4346,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)
|
||||||
|
@ -4417,7 +4459,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)
|
||||||
|
@ -4590,6 +4632,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": [
|
||||||
{
|
{
|
||||||
|
@ -4599,6 +4642,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",
|
||||||
|
@ -4617,6 +4663,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": "",
|
||||||
|
@ -4676,7 +4726,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": "",
|
||||||
|
@ -4719,22 +4769,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"
|
||||||
},
|
},
|
||||||
{...},
|
{...},
|
||||||
|
@ -4957,7 +5044,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",
|
||||||
|
@ -4989,13 +5080,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",
|
||||||
|
@ -5004,8 +5097,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",
|
||||||
|
@ -5025,6 +5118,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": [
|
||||||
|
@ -5063,15 +5157,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",
|
||||||
|
@ -5121,9 +5221,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",
|
||||||
|
@ -5377,8 +5483,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": "",
|
||||||
|
@ -5884,8 +5992,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'
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue