Compare commits

...

1627 Commits

Author SHA1 Message Date
JonnyWong16
70b6bd4efd v2.1.13 2018-06-16 16:42:20 -07:00
JonnyWong16
4f4a99d695 Fix soft crash when viewing photos not in an album 2018-06-16 16:38:06 -07:00
JonnyWong16
f65baa22f1 Fix font awesome icon in setting alerts 2018-06-12 19:28:33 -07:00
JonnyWong16
a1fb081d47 Fix font awesome info page breadcrumb icon 2018-06-11 11:36:50 -07:00
JonnyWong16
63ac3eec98 Fix font awesome remove ajax loader icon 2018-06-11 11:30:51 -07:00
JonnyWong16
73c11c053d Add clip to notification param media type example 2018-06-11 11:11:51 -07:00
JonnyWong16
85c398ce05 Change graph resolution font awesome icon 2018-06-10 19:55:31 -07:00
JonnyWong16
7387cb8322 Add date and time parameters for notifications and newsletters 2018-06-10 19:48:46 -07:00
JonnyWong16
37841b6e8c Fix font awesome icons in notifier text accordions 2018-06-10 19:36:32 -07:00
JonnyWong16
af1355e220 Fix blank font awesome icons 2018-06-10 18:23:22 -07:00
JonnyWong16
37bd005907 Update Discord links 2018-06-10 10:48:05 -07:00
JonnyWong16
311030b58e Add buttons to Discord/Reddit on support page 2018-06-10 10:47:48 -07:00
JonnyWong16
bdd124327f Update to Font Awesome v5 2018-06-10 10:15:49 -07:00
JonnyWong16
70e5e698fa Add support page 2018-06-09 21:28:40 -07:00
JonnyWong16
33e799955e Correct sessions.product column type 2018-06-09 00:03:23 -07:00
JonnyWong16
331be52327 v2.1.12 2018-06-08 22:12:51 -07:00
JonnyWong16
6ece690e23 Fix grouping plays on graphs with new grouping logic 2018-06-08 18:20:51 -07:00
JonnyWong16
6b63a1399e Add collection tag to raw newsletter data 2018-06-08 17:42:20 -07:00
JonnyWong16
5c77cf652b Fix typo in Join notifier help text 2018-06-08 17:18:05 -07:00
JonnyWong16
d6f9a82edb Fix mutable default arguments 2018-06-07 18:51:52 -07:00
JonnyWong16
a887489666 Change notifier link sources to blank for disabled 2018-06-07 18:51:20 -07:00
JonnyWong16
8c0bcd0059 Ability to stop a stream using session key 2018-06-05 20:30:07 -07:00
JonnyWong16
c18ee81130 Fix typo in http handler 2018-06-03 12:25:15 -07:00
JonnyWong16
44428cc6e5 Update logger blacklist for newsleter/notifier configs 2018-06-03 11:01:58 -07:00
JonnyWong16
c19cc858bd v2.1.11-beta 2018-06-02 10:39:32 -07:00
JonnyWong16
668913fd60 Allow manual PMS URL override in config file for XML shortcuts 2018-06-02 09:55:39 -07:00
JonnyWong16
50c5407a46 Fix Monitor Remote Access checkbox (Plex server update chaged bool to int) 2018-06-02 09:32:05 -07:00
JonnyWong16
939755d3b7 Add Plex XML shortcuts to libraries, users, and sync headers 2018-06-02 08:58:55 -07:00
JonnyWong16
54f4696713 Refactor open Plex XML script 2018-06-02 08:53:53 -07:00
JonnyWong16
c85af521fe Add Plex XML shortcuts for metadata and server resources 2018-06-02 08:26:30 -07:00
JonnyWong16
917d19db85 Fix grouping or new plays not previously in history 2018-06-01 18:45:58 -07:00
JonnyWong16
7292f25eb9 Reword group play history setting 2018-05-31 09:10:44 -07:00
JonnyWong16
22a2ad4bc7 Fix progress percent in grouping logic 2018-05-31 08:34:58 -07:00
JonnyWong16
95e56f5ea5 Fix activity progress bar not updating in some cases 2018-05-31 08:33:50 -07:00
JonnyWong16
ed24232a0a Improve logic for grouping history items 2018-05-30 22:18:41 -07:00
JonnyWong16
15225faee7 Add filename to notification parameters 2018-05-30 21:52:18 -07:00
JonnyWong16
041a35a35a Fallback to title if missing index for update metadata 2018-05-30 21:46:31 -07:00
JonnyWong16
6d365c174a Update X-Plex headers 2018-05-30 21:39:45 -07:00
JonnyWong16
b5f2f55972 v2.1.10-beta 2018-05-28 17:22:16 -07:00
JonnyWong16
ac207260c8 Do not send newsletter if failed to render template 2018-05-27 23:02:56 -07:00
JonnyWong16
e93808381c Fix track listing layout on info pages 2018-05-27 22:43:56 -07:00
JonnyWong16
7acb8f7dc5 Fix artist summary not showing up on newsletter 2018-05-27 22:35:54 -07:00
JonnyWong16
ba9f4a1f9e Use track artist for music 2018-05-27 22:24:43 -07:00
JonnyWong16
8502c28e25 Fallback poster_key and poster_title for clip notification 2018-05-27 15:39:28 -07:00
JonnyWong16
10add90451 Merge pull request #1295 from samwiseg00/feature-add-timestamp-discord
Add timestamps for rich metadata info on discord
2018-05-27 14:47:53 -07:00
samwiseg00
ddb7fa04ca add timestamps for rich metadata info on discord 2018-05-27 17:44:35 -04:00
JonnyWong16
e21a13b7ff Revert "Hack to check for live tv stopped websocket event"
This reverts commit 1245b4fbd3.
2018-05-27 14:13:24 -07:00
JonnyWong16
1245b4fbd3 Hack to check for live tv stopped websocket event 2018-05-27 14:04:47 -07:00
JonnyWong16
94b00c75c2 Enable notifications for clip media type 2018-05-27 13:41:56 -07:00
JonnyWong16
2edcf26110 Use HTTPS for cloudinary urls 2018-05-27 13:07:18 -07:00
JonnyWong16
a9fdf73e8b Check live tv websocket event using key instead of rating key 2018-05-27 13:00:34 -07:00
JonnyWong16
4884cee309 Fix live tv stream resolution 2018-05-27 10:13:42 -07:00
JonnyWong16
b3c7256bcf Newsletter footer inherit styles 2018-05-26 17:29:21 -07:00
JonnyWong16
2c9a7ced13 Forgot product in session db write 2018-05-26 10:14:54 -07:00
JonnyWong16
aa365eb6a3 Improved checking of live tv session websocket events 2018-05-26 10:14:36 -07:00
JonnyWong16
2366a8811b Catch exception from failed SMTP connection 2018-05-25 12:19:46 -07:00
JonnyWong16
53aafbd19e Fix typo from d5bffc3 2018-05-25 12:18:29 -07:00
JonnyWong16
d5bffc374c Fallback to blank poster/art on newsletter if image hosting is disabled 2018-05-25 08:26:25 -07:00
JonnyWong16
5cd5c36d8c Actually add live notification parameter 2018-05-23 17:17:47 -07:00
JonnyWong16
7f9e8f6211 Clean up script.js 2018-05-23 17:13:20 -07:00
JonnyWong16
f743a817ba Update python-twitter to 3.4.1 2018-05-23 17:12:19 -07:00
JonnyWong16
8e4aba7ed4 v2.1.9 2018-05-21 09:07:12 -07:00
JonnyWong16
8c0ef75d4c Fix typos and some cleanup 2018-05-21 09:07:01 -07:00
JonnyWong16
76c4b3bb71 Add Live to notification parameter 2018-05-21 08:49:35 -07:00
JonnyWong16
112b1c7984 Refactor css pointer class 2018-05-20 17:04:55 -07:00
JonnyWong16
c22a2513e3 Update CONTRIBUTING.md 2018-05-19 09:12:13 -07:00
JonnyWong16
f336782fc1 v2.1.8-beta 2018-05-19 09:07:18 -07:00
JonnyWong16
c19afa06de Fallback to originally available at for episode number on info pages 2018-05-18 17:47:19 -07:00
JonnyWong16
e003850d31 Update Facebook permissions scope 2018-05-18 17:41:42 -07:00
JonnyWong16
23cf790079 Return proper status codes for API (Fixes Tautulli/Tautulli-Issues#82) 2018-05-18 17:41:23 -07:00
JonnyWong16
e7f930bd0f Check for Tautulli footer in newsletters 2018-05-17 10:31:55 -07:00
JonnyWong16
348707b6b9 Revert back to HTTP newsletter images from tautulli.com 2018-05-17 09:30:34 -07:00
JonnyWong16
7ad78b4536 Allow images through newsletter password auth 2018-05-17 08:40:58 -07:00
JonnyWong16
a408a62234 Check newsletter auth setting when checking guest access enabled 2018-05-17 08:34:36 -07:00
JonnyWong16
a1e9e7e87f Add newsletter password to newsletter parameters 2018-05-16 23:20:53 -07:00
JonnyWong16
fa99f6e684 Add self-hosted newsletter authentication metnods 2018-05-16 23:11:28 -07:00
JonnyWong16
11e9bd2d54 Fix incorrect <div> tag 2018-05-16 21:59:15 -07:00
JonnyWong16
50165af4b7 Update tautulli.com URLs to HTTPS 2018-05-15 20:38:25 -07:00
JonnyWong16
5dd22c23f2 Patch Twitter str encoding for Python 2 2018-05-15 08:44:13 -07:00
JonnyWong16
79b45c1c46 Auto quality when fetching cloudinary transform 2018-05-15 08:43:20 -07:00
JonnyWong16
af917c4915 Add session key to activity processor log messages 2018-05-14 09:03:18 -07:00
JonnyWong16
c3238b5a83 Fix Imgur database migration again 2018-05-14 09:02:32 -07:00
JonnyWong16
908dbc3243 v2.1.7-beta 2018-05-13 12:10:12 -07:00
JonnyWong16
14b6df8c25 Add newsletter commands to API docs 2018-05-13 11:46:58 -07:00
JonnyWong16
d3e53cb97f Add button to delete all Imgur/Cloudinary uploads 2018-05-13 11:29:59 -07:00
JonnyWong16
445eea5c1e Add plaintext message to newsletter email 2018-05-12 12:16:33 -07:00
JonnyWong16
c5918d7d6c Add option to use inline css styles 2018-05-11 21:43:26 -07:00
JonnyWong16
b8e025193e Add max-width to newsletter card titles 2018-05-11 21:23:19 -07:00
JonnyWong16
85772cdd83 Strip whitespace before sending newsletters 2018-05-11 19:18:05 -07:00
JonnyWong16
7f2bab3082 Switch to header styles for newsletter template 2018-05-11 18:27:31 -07:00
JonnyWong16
8185cc1c40 Keep /newsletter/image proxy for backwards compatibility 2018-05-11 09:40:47 -07:00
JonnyWong16
63bfe96124 Add get_stream_data to API 2018-05-11 08:08:26 -07:00
JonnyWong16
88b640f5e2 Self-hosted newsletter images to use /image endpoint instead of proxying through newsletter 2018-05-10 20:28:42 -07:00
JonnyWong16
26b2342956 Fix typo 2018-05-10 12:04:52 -07:00
JonnyWong16
883280be09 Add Linux distro to Google Analytics 2018-05-10 08:52:28 -07:00
JonnyWong16
7c76b0678a Log platform info on startup 2018-05-10 08:47:54 -07:00
JonnyWong16
e91ba46265 v2.1.6-beta 2018-05-09 20:26:06 -07:00
JonnyWong16
62104c95e3 Move newsletter filename setting and rename config tab 2018-05-08 19:39:27 -07:00
JonnyWong16
178bd89e7c Better init config checkboxes JS 2018-05-08 17:40:17 -07:00
JonnyWong16
365260401c Hide newsletter agent options when save only checked 2018-05-08 17:25:25 -07:00
JonnyWong16
04029bd4d3 Fix NoneType error in newsletter ID name for parameters 2018-05-08 12:56:12 -07:00
JonnyWong16
9cf1128712 Update newsletter preview note for image hosting 2018-05-08 11:22:16 -07:00
JonnyWong16
2eebce9f6c Add HTTP root to newsletter ID name note 2018-05-08 11:01:20 -07:00
JonnyWong16
b08e071b81 Note newesletter ID name and filename as optional 2018-05-08 10:59:00 -07:00
JonnyWong16
7778d84728 Add setting to specify newsletter ID name for static URLs 2018-05-08 10:54:07 -07:00
JonnyWong16
8e3fe7bfa2 v2.1.5-beta 2018-05-07 21:22:46 -07:00
JonnyWong16
6f22c823be Typo in static newsletter URL help text 2018-05-07 21:03:09 -07:00
JonnyWong16
34d7c67813 Merge pull request #1287 from RafaelSchridi/patch-3
Typo in Newsletter Parameters
2018-05-07 21:02:25 -07:00
JonnyWong16
862ed5ce9f Add option to save newsletter only 2018-05-07 20:49:37 -07:00
JonnyWong16
84406e6797 Add setting to enable static newsletter URL 2018-05-07 20:39:04 -07:00
JonnyWong16
19cf567366 Add option to change the newsletter filename 2018-05-07 20:02:04 -07:00
JonnyWong16
8af697a157 Add URL to retrieve latest scheduled newsletter 2018-05-07 19:42:04 -07:00
JonnyWong16
76122bea5d Fix Imgur URL database upgrade migration 2018-05-07 19:09:35 -07:00
JonnyWong16
1a12422908 Show local note on newsletter preview if image hosting enabled 2018-05-07 18:26:40 -07:00
JonnyWong16
2df9f0b48b Add Cloudinary versioning when retrieving the image 2018-05-07 16:13:00 -07:00
JonnyWong16
8540b80e57 Refresh image when uploading to image hosting 2018-05-07 15:32:21 -07:00
JonnyWong16
8ad565a444 Add visible Plex server identifier in the settings 2018-05-07 09:13:16 -07:00
JonnyWong16
f91b6481b3 Close email SMTP connection cleanly if exception 2018-05-06 22:43:55 -07:00
JonnyWong16
826db082c9 Add setting for custom newsletter templates folder 2018-05-06 15:37:07 -07:00
Rafael Schridi
f3d64a7886 Typo in Newsletter Parameters 2018-05-06 23:05:36 +02:00
JonnyWong16
031d078bc2 Add Cache-Control header for newsletter images (Fixes Tautulli/Tautulli-Issues#71) 2018-05-06 08:34:21 -07:00
JonnyWong16
04fcd78102 Uncoulpe self-hosted newsletter and image setting 2018-05-06 08:33:28 -07:00
JonnyWong16
53d1e0f541 Remove HTTP root from newsletter preview iframe 2018-05-05 23:40:44 -07:00
JonnyWong16
9719f0b25b Update newsletter warning message 2018-05-05 22:59:10 -07:00
JonnyWong16
6d1d5bc822 Check for disabled image hosting 2018-05-05 13:06:20 -07:00
JonnyWong16
0d7bbe044d Don't fetch recently added on homepage if Plex Cloud server is sleeping 2018-05-05 11:54:13 -07:00
JonnyWong16
b1dc5816a4 v2.1.4 2018-05-05 11:21:03 -07:00
JonnyWong16
476011a783 Fix newsletter URL with no HTTP root 2018-05-05 11:13:27 -07:00
JonnyWong16
e038c57c4c v2.1.3-beta 2018-05-04 22:36:11 -07:00
JonnyWong16
a989a53750 Encode image title for Cloudinary upload 2018-05-04 16:11:42 -07:00
JonnyWong16
d8cfdea704 Log individual condition evalutation 2018-05-04 15:52:04 -07:00
JonnyWong16
ed4722c4ce Improve refreshing of cached Plex images 2018-05-03 20:29:23 -07:00
JonnyWong16
17ab5f05ed Patch apshceduler sun-sat as 0-6 2018-05-03 17:58:28 -07:00
JonnyWong16
71ab2248d7 Make sure Cloudinary parameters are strings 2018-05-03 08:34:32 -07:00
JonnyWong16
4fb4410552 Fix potential XSS in search 2018-05-02 10:26:05 -07:00
JonnyWong16
a915d2333f Catch failed hostname resolution (Fixes Tautulli/Tautulli-Issues#68) 2018-05-01 16:57:43 -07:00
JonnyWong16
aaf5a18251 Forgot missing '/' 2018-05-01 15:51:23 -07:00
JonnyWong16
b90026801b Fix double HTTP root in newsletter URL 2018-05-01 15:37:37 -07:00
JonnyWong16
e9676e3651 v2.1.2-beta 2018-05-01 08:47:32 -07:00
JonnyWong16
c16d3288d8 Update Imgur and Cloudinary help text 2018-04-29 21:18:01 -07:00
JonnyWong16
0d7ade8ca4 Transform images on Cloudinary 2018-04-29 18:46:46 -07:00
JonnyWong16
87b1118e98 Add delete from Cloudinary 2018-04-29 17:49:53 -07:00
JonnyWong16
9f6422cc8d Fix Imgur poster lookup on imfo pages 2018-04-29 16:04:46 -07:00
JonnyWong16
df1a42a4ee Fix update metadata z-index 2018-04-29 15:15:57 -07:00
JonnyWong16
6554136a8f Add Cloudinary image hosting option 2018-04-29 00:11:47 -07:00
JonnyWong16
81e04269fd Remove ratelimit library 2018-04-29 00:10:58 -07:00
JonnyWong16
b6c6590a12 Update six v1.11.0 2018-04-28 21:44:34 -07:00
JonnyWong16
136260a822 Add cloudinary v1.11.0 2018-04-28 21:44:19 -07:00
JonnyWong16
5710bcb43c Hardcode Pushover sounds list (Fixes Tautulli/Tautulli-Issues#65) 2018-04-28 20:07:36 -07:00
JonnyWong16
30bc3f8a66 Fix incorrect {action} for new device (Fixes Tautulli/Tautulli-Issues#63) 2018-04-28 19:59:23 -07:00
JonnyWong16
e0e7d68df2 API success result for empty response data (Fixes Tautulli/Tautulli-Issues#56) 2018-04-28 18:39:42 -07:00
JonnyWong16
cf73639281 Fix Twitter notification with self-hosted images (Fixes Tautulli/Tautulli-Issues#54) 2018-04-28 18:23:10 -07:00
JonnyWong16
008e04d5cf Re-factor script timeout code 2018-04-28 18:12:43 -07:00
JonnyWong16
5f7991665c Only notify Tautulli updates when checked as a scheduled task (Fixes Tautulli/Tautulli-Issues#46) 2018-04-28 17:59:53 -07:00
JonnyWong16
5e000162c6 Merge branch 'nightly' of https://github.com/Tautulli/Tautulli into nightly 2018-04-28 17:54:18 -07:00
JonnyWong16
ea1aba2c87 Merge pull request #1286 from Dam64/patch-1
add Message-ID on mails
2018-04-28 17:54:02 -07:00
JonnyWong16
f321bb869c Add Plex Cloud sleeping message 2018-04-28 17:51:52 -07:00
JonnyWong16
abe496668a Fix typo in Activity Refresh Interval setting 2018-04-28 17:48:55 -07:00
Dam64
9cefc7f701 add Message-ID on mails 2018-04-27 01:17:18 +02:00
JonnyWong16
1d3cd431eb v2.1.1-beta 2018-04-11 21:59:39 -07:00
JonnyWong16
8f8318da6d Fix Imgur fallback to cover on newsletters 2018-04-11 21:42:14 -07:00
JonnyWong16
36ce751875 Explicit white font colour on newsletter cards 2018-04-11 12:04:00 -07:00
JonnyWong16
858ea33680 Fix fallback to cover for albums on newsletter 2018-04-11 11:58:57 -07:00
JonnyWong16
eee759d0d0 Log newsletter start time and end time in database 2018-04-10 22:44:11 -07:00
JonnyWong16
dbe3b492fd Check if the newsletter has data before saving the html file 2018-04-10 22:28:48 -07:00
JonnyWong16
4e4fde2e9a Move time frame to global newsletter configs 2018-04-10 21:34:18 -07:00
JonnyWong16
5283126608 Week number of the year 2018-04-10 21:31:25 -07:00
JonnyWong16
df72ecebf5 Add hours as time frame for newsletters 2018-04-10 21:16:16 -07:00
JonnyWong16
d316aa34e2 Merge pull request #1283 from samip5/week_number-patch
Adding the week number parameter
2018-04-10 20:17:07 -07:00
JonnyWong16
405aec8bb8 User helper for casting condition values 2018-04-10 19:57:40 -07:00
samip5
4a62f8c395 Fixed a typo. 2018-04-10 20:15:26 +03:00
samip5
eabea2deeb Made the requested changes.
The requested changes by JonnyWong16 in the PR request were done in this
commit.
2018-04-10 20:07:56 +03:00
samip5
3742021dcc Removed the non-needed imports. 2018-04-10 13:20:30 +03:00
samip5
9c4219b42e Edited newsletters.py
It wouldn't want to work without the edit.
2018-04-10 13:19:29 +03:00
samip5
f624908302 Added a new branch, edited the code to include the week_number 2018-04-10 12:10:32 +03:00
samip5
ab9132cdd4 Made sure the syntax is understandable. 2018-04-09 17:27:13 +03:00
samip5
0186363753 Added the week number parameter. 2018-04-09 17:20:51 +03:00
JonnyWong16
653ad36f17 Move transcode decision after live session override 2018-04-08 15:14:35 -07:00
JonnyWong16
5073f82d53 Another fix for Live TV stream transcode decision 2018-04-08 15:09:23 -07:00
JonnyWong16
833937eced Fix Live TV transcode details (Fixes Tautulli/Tautulli-Issues#45) 2018-04-08 11:16:43 -07:00
JonnyWong16
32df79bb83 Only sanitize script output when viewing the logs in the UI 2018-04-08 10:44:47 -07:00
JonnyWong16
fabced9942 Add tqdm v4.21.0 2018-04-08 10:44:04 -07:00
JonnyWong16
8aa34321c9 Add plexapi v3.0.6 2018-04-08 10:43:33 -07:00
JonnyWong16
b144ded87b v2.1.0-beta 2018-04-07 15:23:03 -07:00
JonnyWong16
ef8c91ee56 Fix new email config showing when HTML formatted email is unchecked 2018-04-07 15:22:29 -07:00
JonnyWong16
d76ded3ebe Remove "Notify on" from notification trigger text 2018-04-07 15:13:20 -07:00
JonnyWong16
c4fc94ea34 Fix unicode log errors 2018-04-07 10:35:28 -07:00
JonnyWong16
ad61e23d92 Don't fallback to art on newsletters 2018-04-05 19:35:37 -07:00
JonnyWong16
fcd7593764 Add temporary watched state for sessions 2018-04-04 22:05:30 -07:00
JonnyWong16
8465df5095 Replace Imgur with Tautulli hosted newsletter assets 2018-04-04 21:37:50 -07:00
JonnyWong16
95697a3367 Fix homepage max 50 recently added items 2018-04-04 21:37:14 -07:00
JonnyWong16
978ae7d8cb Note that HTML support must be enabled for eamil 2018-04-04 21:01:29 -07:00
JonnyWong16
366e8514b6 Fix centering last item on newsletter 2018-04-04 20:45:34 -07:00
JonnyWong16
45c646c062 Fix test newsletter warning message 2018-04-02 15:27:27 -07:00
JonnyWong16
4b482938a1 Make sure simple cron is set when saving 2018-04-02 15:01:07 -07:00
JonnyWong16
9699129a38 Catch invalid cron entry and reset to default 2018-04-02 14:50:01 -07:00
JonnyWong16
5ef8947532 Merge v2.0.28 into v2-newsletters 2018-04-02 14:33:52 -07:00
JonnyWong16
f335ffa8d5 v2.0.28 2018-04-02 14:27:34 -07:00
JonnyWong16
793665d62a Revert home activity header 2018-04-02 14:25:54 -07:00
JonnyWong16
7da5730c73 Fix activity header text 2018-04-02 14:21:34 -07:00
JonnyWong16
1f587ed698 v2.0.27 2018-04-02 14:17:48 -07:00
JonnyWong16
1032fdfe7a Move refresh interval setting back to the settings page 2018-04-02 14:13:52 -07:00
JonnyWong16
35e3f7dccc Change crontab anchor text 2018-04-02 14:10:52 -07:00
JonnyWong16
909cbc90df Add toggle for simple/custom crontab 2018-04-02 13:10:29 -07:00
JonnyWong16
77ed94bbef Separate newsletter message and body text 2018-04-02 11:12:37 -07:00
JonnyWong16
c260543586 Add custom cron to newsletter schedule 2018-04-02 10:17:51 -07:00
JonnyWong16
a4de63095f Fix View on Plex overlay 2018-03-30 17:45:50 -07:00
JonnyWong16
817335b42e Separate values in img hash 2018-03-30 13:44:36 -07:00
JonnyWong16
818e7723ff v2.0.26-beta 2018-03-30 09:29:47 -07:00
JonnyWong16
a69008e179 Send Telegram notification separately if caption is longer than 200 characters (Closes Tautulli/Tautulli-Issues#20) 2018-03-30 09:23:38 -07:00
JonnyWong16
91c647f9ae Show extra type on activity cards 2018-03-29 19:54:43 -07:00
JonnyWong16
36b80aa6d3 Make sure all datatables are using POST 2018-03-28 18:08:57 -07:00
JonnyWong16
c35fcc727c Change default refresh to 10 seconds 2018-03-27 22:08:12 -07:00
JonnyWong16
749e1fcebe Move refresh interval setting to homepage 2018-03-26 08:53:40 -07:00
JonnyWong16
80506b8541 Add login redirect uri 2018-03-25 14:26:47 -07:00
JonnyWong16
80df2b0fad Add Imgur rate limiting 2018-03-25 13:47:49 -07:00
JonnyWong16
084732706d Add setting to change homepage refresh interval 2018-03-25 13:25:18 -07:00
JonnyWong16
2aff7713cd Fix invalid link to playlist in sync table (Fixes Tautulli/Tautulli-Issues#34) 2018-03-25 12:39:20 -07:00
JonnyWong16
683a782723 Fix typo (Closes Tautulli/Tautulli-Issues#35) 2018-03-25 11:58:57 -07:00
JonnyWong16
5108e1bb09 Add quick websocket test when verifying server 2018-03-25 11:38:35 -07:00
JonnyWong16
d8298a12eb Clear PMS selectize when dropdown opens 2018-03-25 11:00:58 -07:00
JonnyWong16
dec5931fd4 Fix some typos 2018-03-25 10:12:03 -07:00
JonnyWong16
71d79266f6 Offload homepage image processing to the Plex server 2018-03-25 00:31:04 -07:00
JonnyWong16
d3f6812178 Merge branch 'nightly' into v2-newsletter 2018-03-24 23:35:21 -07:00
JonnyWong16
042b48c1fd Fix repeating renaming notifiers on startup 2018-03-24 23:32:53 -07:00
JonnyWong16
38613f24fe Scroll to setting position 2018-03-24 23:09:30 -07:00
JonnyWong16
e23b1a0603 Add self-hosted notificaation images 2018-03-24 22:09:37 -07:00
JonnyWong16
90f3d597dc Reorganize all Imgur info in database 2018-03-24 20:02:23 -07:00
JonnyWong16
d166b77ea9 Link to season or episode 2018-03-24 18:09:36 -07:00
JonnyWong16
feb74b157f Move custom message into the body of the newsletter 2018-03-24 14:53:21 -07:00
JonnyWong16
4aeafdae2d Add custom body line to formatted email 2018-03-24 14:34:47 -07:00
JonnyWong16
f12de78370 Add warning about Imgur or self-hosting enabled 2018-03-24 13:46:15 -07:00
JonnyWong16
d2415c92ea Add option to send to a newsletter message to other notification agents 2018-03-24 13:45:59 -07:00
JonnyWong16
646ca1d9fa Add genre badges 2018-03-24 11:58:06 -07:00
JonnyWong16
c8c93c69ab Align text left on newsletter cards for Outlook 2018-03-24 11:17:50 -07:00
JonnyWong16
2c8c20af02 Add link to view full newsletter 2018-03-24 10:30:07 -07:00
JonnyWong16
a877da3de8 Fix newsletter header image sizes 2018-03-24 09:45:27 -07:00
JonnyWong16
1b7cfd7f8a Fix helper import 2018-03-24 09:05:20 -07:00
JonnyWong16
3f7edc3635 Redo newsletter template using tables 2018-03-24 00:02:31 -07:00
JonnyWong16
8fac54aa71 Typo 2018-03-22 22:11:11 -07:00
JonnyWong16
244008d539 v2.0.25 2018-03-22 22:06:01 -07:00
JonnyWong16
502b807e45 Fix websocket not scheduling reconnect 2018-03-22 21:03:11 -07:00
JonnyWong16
35914b9a48 Remove unicode from websocket logger error 2018-03-22 20:32:37 -07:00
JonnyWong16
24ac34d5e2 Make sure user has Plex Pass if checking for synced stream 2018-03-22 19:39:46 -07:00
JonnyWong16
e1035a49fd Move newsletter loader css to main file 2018-03-21 19:57:55 -07:00
JonnyWong16
511f4a916b Automatically append HTTP root to newsletter URL 2018-03-21 19:18:49 -07:00
JonnyWong16
1f10668838 Allow additional parameters for newsletter preview 2018-03-21 13:05:46 -07:00
JonnyWong16
a9a08a959c Don't return error messages if missing newsletter files 2018-03-21 12:14:18 -07:00
JonnyWong16
341f4040ff Hash image with UUID 2018-03-21 08:23:05 -07:00
JonnyWong16
e9a1b2ea38 Add self-hosted static images 2018-03-21 00:10:39 -07:00
JonnyWong16
7f67213ff7 Store image hash for self-hosted newsletters 2018-03-20 22:54:36 -07:00
JonnyWong16
e9bdbb863c Make self-hosted option global 2018-03-20 11:24:12 -07:00
JonnyWong16
04641c7c63 Encode UTF-8 when saving newsletter 2018-03-20 10:51:33 -07:00
JonnyWong16
15cc96a005 As self-hosted config option 2018-03-20 10:39:33 -07:00
JonnyWong16
b712874ed2 Fix email config for newsletters 2018-03-20 10:07:06 -07:00
JonnyWong16
5b1ff402bc Queue notification instead of waiting for send 2018-03-20 09:15:41 -07:00
JonnyWong16
eda0e73eb6 Queue newsletters instead of waiting for send 2018-03-20 09:09:49 -07:00
JonnyWong16
a5807f21b4 Flush temporary sessions automatically if failed to check sessions on startup 2018-03-19 23:24:09 -07:00
JonnyWong16
e3b71a729e Revert negative operator values to "OR" (UI change only) 2018-03-19 23:18:27 -07:00
JonnyWong16
f810f50ea9 Adjust newsletter log table widths 2018-03-19 23:10:25 -07:00
JonnyWong16
2b0f83e036 Newsletter body text for test 2018-03-19 23:07:19 -07:00
JonnyWong16
4977b3def1 Remove trailing slash 2018-03-19 23:04:09 -07:00
JonnyWong16
1cb5f0b635 Add newsletter base URL setting 2018-03-19 22:57:38 -07:00
JonnyWong16
7e11af1fd0 Add body text to newsletters 2018-03-19 20:20:57 -07:00
JonnyWong16
6f6fb485fe Log message no libraries selected for newsletter 2018-03-19 09:21:40 -07:00
JonnyWong16
964f24d6ab Fix music background on newsletter 2018-03-19 09:15:06 -07:00
JonnyWong16
1474f144fe View sent newsletters without authentication 2018-03-18 23:01:23 -07:00
JonnyWong16
8d25b0c973 Open Sans for newsletters 2018-03-18 21:56:44 -07:00
JonnyWong16
50b37d6b3a Add newsletter logs table 2018-03-18 21:40:57 -07:00
JonnyWong16
b9b82b23f7 Save newsletters to html file 2018-03-18 21:02:39 -07:00
JonnyWong16
b6bd305694 Merge branch 'nightly' into v2-newsletter 2018-03-18 17:49:14 -07:00
JonnyWong16
ebb287e1ee v2.0.24 2018-03-18 17:46:17 -07:00
JonnyWong16
bd3497b2bf Rename notifiers in database 2018-03-18 17:44:24 -07:00
JonnyWong16
034f3ee308 Anon URL to FAQ for pycryptodome does not work with anchors 2018-03-18 17:33:02 -07:00
JonnyWong16
a946879fc1 Better OSX register button 2018-03-18 17:22:44 -07:00
JonnyWong16
9f964b5a87 Move notification agent instructions to wiki 2018-03-18 17:05:30 -07:00
JonnyWong16
2245e38d40 Retrieve newsletter using uuid 2018-03-18 00:45:27 -07:00
JonnyWong16
c9618322c2 Log newsletter start/end date and uuid 2018-03-17 23:58:39 -07:00
JonnyWong16
960e147e10 Update Arrow to 0.10.0 2018-03-17 23:08:06 -07:00
JonnyWong16
bbca0b3b42 Add newsletter template folder config option 2018-03-17 20:32:55 -07:00
JonnyWong16
ed0b41cd19 Add punctuation to Arnold 2018-03-17 18:44:15 -07:00
JonnyWong16
dc87591992 Show historical stream data (Fixes Tautulli/Tautulli-Issues#27) 2018-03-17 16:36:24 -07:00
JonnyWong16
1f7be7a4d5 Offload image processing to the Plex server 2018-03-17 14:03:27 -07:00
JonnyWong16
d05e80e573 Make sure all exisiting environment variables are included for scripts 2018-03-17 13:30:12 -07:00
JonnyWong16
003e890844 Some small fixes after rebasing 2018-03-17 11:04:17 -07:00
JonnyWong16
afa16cd656 Newsletter preview by default 2018-03-17 10:42:00 -07:00
JonnyWong16
9aff61f670 Add wait message to newsletter loader 2018-03-17 10:42:00 -07:00
JonnyWong16
8b1c7df3ce Add generating newsletter loader 2018-03-17 10:42:00 -07:00
JonnyWong16
25355f29ce Add server name to newsletter 2018-03-17 10:41:18 -07:00
JonnyWong16
09ea81ccd2 Refactor some newsletter code 2018-03-17 10:41:18 -07:00
JonnyWong16
28efaf73c7 Patch apscheduler weekday (Sunday=0) 2018-03-17 10:41:18 -07:00
JonnyWong16
0057481efb Add funcsigs 1.0.2 2018-03-17 10:41:18 -07:00
JonnyWong16
827b012978 Fix float clear for odd newsletter card 2018-03-17 10:41:18 -07:00
JonnyWong16
0e419695cf Change newsletter job name 2018-03-17 10:41:18 -07:00
JonnyWong16
46f26cc307 Add message for missing Pillow library 2018-03-17 10:41:18 -07:00
JonnyWong16
46f7a92c97 Schedule newsletters 2018-03-17 10:39:30 -07:00
JonnyWong16
2a24ea4cdf Patch apscheduler to use datetime.isoweekday() 2018-03-17 10:39:30 -07:00
JonnyWong16
8e13bf4f93 Update apscheduler 3.5.0 2018-03-17 10:36:04 -07:00
JonnyWong16
aa844b76fc Sort newsletter libraries when rendered 2018-03-17 10:36:04 -07:00
JonnyWong16
0e5bb7b188 Add select/remove all for newsletter libraries 2018-03-17 10:36:04 -07:00
JonnyWong16
49a6cf8809 Add newsletter star rating on hover 2018-03-17 10:36:04 -07:00
JonnyWong16
2adad24684 Fix import on newsletter templates 2018-03-17 10:36:04 -07:00
JonnyWong16
d4d5ff9de7 Add newsletter handler 2018-03-17 10:36:04 -07:00
JonnyWong16
33c2315384 Add view on Plex overlay on newsletter 2018-03-17 10:34:08 -07:00
JonnyWong16
4577704f19 Redo newsletter CSS 2018-03-17 10:34:08 -07:00
JonnyWong16
a13d93f239 Add selectize input for email for newsletters 2018-03-17 10:31:20 -07:00
JonnyWong16
5ac5b3cd29 Add email subject line and sending newsletters 2018-03-17 10:22:04 -07:00
JonnyWong16
d104ec216c Fix newsletter save new email config 2018-03-17 10:22:04 -07:00
JonnyWong16
32645c374e Change to include libraries instead of exclude 2018-03-17 10:22:04 -07:00
JonnyWong16
d1f982847b Add exclude libraries option to newsletter
* Remove individual media type toggles
2018-03-17 10:22:04 -07:00
JonnyWong16
7770431b67 Add email config to newsletters 2018-03-17 10:22:04 -07:00
JonnyWong16
edeb6ae4e4 Add season count to newsletter tv cards 2018-03-17 10:19:28 -07:00
JonnyWong16
af3501a6a6 Add view on Plex to newsletter 2018-03-17 10:19:28 -07:00
JonnyWong16
0f39201774 Initial newsletter support 2018-03-17 10:17:39 -07:00
JonnyWong16
b73d2ff1f7 Add shared libraries for admin user 2018-03-17 10:11:49 -07:00
JonnyWong16
6009fb24b6 Add server token and shared libraries to user refresh 2018-03-17 10:11:49 -07:00
JonnyWong16
522684b2ab v2.0.23-beta 2018-03-16 19:59:06 -07:00
JonnyWong16
feab16b351 Update API docs for get_server_id 2018-03-16 19:47:49 -07:00
JonnyWong16
ee041db63d Pass common environment variable to scripts 2018-03-16 18:37:50 -07:00
JonnyWong16
2479533d07 Show Plex Server URL in settings 2018-03-16 17:43:32 -07:00
JonnyWong16
d045fd5834 Update Facebook Graph API version 2018-03-16 15:39:41 -07:00
JonnyWong16
8407f27fed Add value3 to IFTTT notifications (Closes #1279) 2018-03-16 09:45:30 -07:00
JonnyWong16
b505286caf Add season/episode/album/track count to notification parameters 2018-03-16 09:42:32 -07:00
JonnyWong16
feb762ce8b Beta/nightly update check to include non-beta releases 2018-03-16 08:37:50 -07:00
JonnyWong16
8acdb5af83 Use media stream info for transcode decision (Fixes Tautulli/Tautulli-Issues#24) 2018-03-14 19:45:47 -07:00
JonnyWong16
5af1294f71 Make websocket thread daemon 2018-03-14 16:19:22 -07:00
JonnyWong16
87d2d273d3 Attempt at fixing custom condition json error 2018-03-13 22:16:23 -07:00
JonnyWong16
b5c52ac71e Add logging for failed custom condition json 2018-03-13 20:45:41 -07:00
JonnyWong16
efe9a15f72 Cast Email username/password to string 2018-03-13 20:41:07 -07:00
JonnyWong16
525f1e4b0b Use cherrypy remote for login IP info 2018-03-13 10:00:08 -07:00
JonnyWong16
d18820b832 Use cherrypy base for login host info 2018-03-13 09:42:01 -07:00
JonnyWong16
7e024fd736 Remove test comment in c9c5989 2018-03-13 09:09:27 -07:00
JonnyWong16
c9c5989474 Fix login logs for Plex admin user 2018-03-13 09:08:09 -07:00
JonnyWong16
ce9f96d3be Exit if failed to move database instead of continuing 2018-03-12 19:43:46 -07:00
JonnyWong16
7362dd0bf4 Close websocket cleanly on shutdown 2018-03-12 19:38:19 -07:00
JonnyWong16
9905ebc144 Don't empty results if message in API response (Fixes Tautulli/Tautulli-Issues#13) 2018-03-12 08:56:43 -07:00
JonnyWong16
8f8010884b Add git pull after checkout from interface 2018-03-12 08:20:20 -07:00
JonnyWong16
37afd141be Catch invalid json for custom conditions 2018-03-11 20:59:18 -07:00
JonnyWong16
a3643b4302 Fix typos 2018-03-10 20:54:21 -08:00
JonnyWong16
02cfd8d9b7 Fix git branch select box height 2018-03-10 20:33:18 -08:00
JonnyWong16
941ce439b4 Update API message for remote app settings 2018-03-10 18:03:23 -08:00
JonnyWong16
a08bce2073 v2.0.22 2018-03-10 09:32:08 -08:00
JonnyWong16
4e9c8322c3 Don't overwrite tautulli db on move 2018-03-10 09:32:05 -08:00
JonnyWong16
89bfe85be3 Workaround for duration reported as minutes for a show 2018-03-10 08:58:15 -08:00
JonnyWong16
98d994591c Fix runtime round to minutes 2018-03-09 19:12:12 -08:00
JonnyWong16
a29bc7f4f9 v2.0.22-beta 2018-03-09 17:58:40 -08:00
JonnyWong16
288f4c5f7f Fix expanding selectize box 2018-03-09 15:50:53 -08:00
JonnyWong16
a6bf78ed56 Check is schedulers running before shutdown 2018-03-08 18:32:47 -08:00
JonnyWong16
8dbb05931e Fix library refresh when missing library 2018-03-08 18:23:12 -08:00
JonnyWong16
ac8a712ff0 Fix refreshing activity after losing connection 2018-03-06 20:01:11 -08:00
JonnyWong16
39406c25c3 Add retry and expire for Pushover priority 2 2018-03-06 09:57:06 -08:00
JonnyWong16
48d7c2c54c Fix photo library count and media info table 2018-03-05 09:49:48 -08:00
JonnyWong16
0217188274 Fix update check 2018-03-04 22:49:32 -08:00
JonnyWong16
fd762e71de Fix cherrypy sending wrong Content-Type header for svg 2018-03-04 22:32:26 -08:00
JonnyWong16
4d5c3b6df0 v2.0.21-beta 2018-03-04 14:51:27 -08:00
JonnyWong16
7df54e4d1b Replace Flattr with Patreon 2018-03-04 14:25:38 -08:00
JonnyWong16
5d085de9d3 Rename logger name 2018-03-04 12:24:25 -08:00
JonnyWong16
a8a4299086 Add execute permission to PlexPy.py 2018-03-04 12:17:09 -08:00
JonnyWong16
86f0e8425c Add execute permission to Tautulli.py 2018-03-04 12:15:05 -08:00
JonnyWong16
d2e879be4a Add PlexPy.py file to run Tautulli.py 2018-03-04 12:01:31 -08:00
JonnyWong16
544114fffe Rename css files to tautulli 2018-03-04 11:40:38 -08:00
JonnyWong16
3b3e207b11 Rename log files to tautulli 2018-03-04 11:38:31 -08:00
JonnyWong16
84aad638ac Rename database backup to tautulli 2018-03-04 11:28:35 -08:00
JonnyWong16
2bb691966e Rename default notifier settings to tautulli 2018-03-04 11:18:04 -08:00
JonnyWong16
8f5e788270 Rename plexpy.db to tautulli.db 2018-03-04 11:17:35 -08:00
JonnyWong16
7c43ea2f46 Rename PlexPy.py to Tautulli.py 2018-03-04 11:17:11 -08:00
JonnyWong16
8146e1e3cf Capitalize Tautulli folder in init scripts 2018-03-04 10:28:28 -08:00
JonnyWong16
51b1ff6d4a Rename variables in Ubuntu script 2018-03-04 10:17:16 -08:00
JonnyWong16
403e8dfbea Update all init scripts to Tautulli 2018-03-04 09:44:02 -08:00
JonnyWong16
9d08717c83 Fix missing country in whois lookup causing error 2018-03-02 15:39:05 -08:00
JonnyWong16
66167d5960 Remove word "allowed" 2018-03-02 10:24:28 -08:00
JonnyWong16
624863d826 Hide number input spinners on Firefox 2018-03-02 08:48:31 -08:00
JonnyWong16
d4b3810fbc Reduce number input width 2018-03-01 19:34:52 -08:00
JonnyWong16
6056e1d3b9 Hide arrows on number inputes 2018-03-01 13:08:43 -08:00
JonnyWong16
1a293d525f Update database session on state change 2018-02-28 13:34:21 -08:00
JonnyWong16
b87eb68bdd Identify if a stream is using Plex Relay 2018-02-27 20:03:31 -08:00
JonnyWong16
8620546d07 Move import from a082109 2018-02-27 15:17:35 -08:00
JonnyWong16
a082109045 Don't ping for activity if websocket is not connected 2018-02-27 15:02:17 -08:00
JonnyWong16
559a9b393e Catch failure to send analytics event 2018-02-24 15:08:58 -08:00
JonnyWong16
ae41b22e59 Forgot one version number in 754fd24 2018-02-24 14:51:19 -08:00
JonnyWong16
754fd24421 Refactor some code 2018-02-24 10:09:02 -08:00
JonnyWong16
ab34a74210 v2.0.20-beta 2018-02-24 09:22:47 -08:00
JonnyWong16
cfa6de4d91 Remove content group 2018-02-24 09:02:46 -08:00
JonnyWong16
a5608c7a1e Revert to png for logos 2018-02-22 19:30:10 -08:00
JonnyWong16
88a7b52e51 Add content group metric dev/production 2018-02-22 12:39:32 -08:00
JonnyWong16
e444bad4de Switch metric dimensions 2018-02-22 12:28:22 -08:00
JonnyWong16
5403b0b547 Install or update event 2018-02-22 11:41:22 -08:00
JonnyWong16
51b5e615f5 Add some more system metrics 2018-02-22 09:20:58 -08:00
JonnyWong16
700547b63b Separate system analytics 2018-02-22 08:12:15 -08:00
JonnyWong16
3f3d1962c7 Hash client ID 2018-02-22 07:29:56 -08:00
JonnyWong16
655a359ef4 Clean up tracker 2018-02-22 07:28:13 -08:00
JonnyWong16
90647628c9 Test sending install metrics on startup 2018-02-21 10:28:03 -08:00
JonnyWong16
681c3ed6e3 Add Google Universal Analytics 2018-02-21 10:27:28 -08:00
JonnyWong16
7f255943c6 Commit to link to the commit 2018-02-20 15:48:50 -08:00
JonnyWong16
b6e73b5dea Fix fallback thumb for home stats cards 2018-02-20 13:39:41 -08:00
JonnyWong16
eacb7f6ae5 Proper image name for poster uploads 2018-02-19 19:38:36 -08:00
JonnyWong16
7b300bb87e Add "Note" tag for Imgur and 3rd party API message 2018-02-19 19:19:27 -08:00
JonnyWong16
a81ad27d85 Add include subject line for Pushover 2018-02-19 19:10:08 -08:00
JonnyWong16
8eed14ff3b Add posters to Pushbullet notifications 2018-02-19 19:08:52 -08:00
JonnyWong16
82446acdf0 Telegram upload image in single message 2018-02-19 19:05:44 -08:00
JonnyWong16
88770b8805 Imgur upload not required for Pushover posters 2018-02-19 12:36:12 -08:00
JonnyWong16
f9f05bbea3 Add posters to Pushover notifications 2018-02-19 12:32:35 -08:00
JonnyWong16
17dd767c22 Send HipChat header 2018-02-19 11:57:21 -08:00
JonnyWong16
25b1dc6dd8 Fix refresh login logs on user page 2018-02-19 11:42:14 -08:00
JonnyWong16
b2b1277e37 Don't reload table again when switching tabs on user and library pages 2018-02-19 10:59:40 -08:00
JonnyWong16
8e1a588ced Fix conflicting history and sync delete mode on user page 2018-02-19 10:59:10 -08:00
JonnyWong16
9eddfafeae Correct poster height on the watch statistic cards 2018-02-19 10:05:19 -08:00
JonnyWong16
d24a922ccb Adjust media screen size for button bar 2018-02-19 10:00:17 -08:00
JonnyWong16
bbc6482c99 Add edit mode to sync table on user page 2018-02-19 09:11:35 -08:00
JonnyWong16
36ff1fb674 Fix button layout on mobile site 2018-02-19 08:39:27 -08:00
JonnyWong16
f0aa793262 Update wording for group history setting 2018-02-18 13:01:09 -08:00
JonnyWong16
681627a656 Fix user filtering on graphs with grouping 2018-02-18 12:58:40 -08:00
JonnyWong16
87c6ad66fb Add grouping to the remaining graphs 2018-02-18 12:50:28 -08:00
JonnyWong16
4ab9eb3bfa Fix popovers in history table modal 2018-02-18 12:15:11 -08:00
JonnyWong16
2d56ac027b Add plays graph grouping to API docs 2018-02-18 11:06:17 -08:00
JonnyWong16
836c4293d6 Respect group history setting in graphs 2018-02-18 11:04:31 -08:00
JonnyWong16
07092e8aa5 Don't reconnect server when saving settings if server settings are not changed 2018-02-18 11:03:57 -08:00
JonnyWong16
66743c1401 Add conditions bypass message for manual recently added notification trigger 2018-02-18 08:41:55 -08:00
JonnyWong16
bfe34e060b Fix KeyError from 868aeb3 2018-02-18 08:36:53 -08:00
JonnyWong16
5ed4236a22 "Commit" if only one commit behind 2018-02-18 08:33:14 -08:00
JonnyWong16
868aeb3902 Fix notification update parameter types 2018-02-18 08:29:40 -08:00
JonnyWong16
cbcdac5b04 Update message to show release instead of commits for master and beta 2018-02-18 08:28:44 -08:00
JonnyWong16
d473bb3058 Prevent dismissing the modal on the shutdown page 2018-02-17 15:05:54 -08:00
JonnyWong16
066a95d209 v2.0.19-beta 2018-02-16 22:22:51 -08:00
JonnyWong16
c7cc476623 Change "Close" to "Dismiss" in update bar 2018-02-16 15:24:48 -08:00
JonnyWong16
bd44eb7fe4 Redraw table after refresh 2018-02-16 11:22:39 -08:00
JonnyWong16
6ec4f51077 Don't delete session cache folder on startup 2018-02-16 11:18:56 -08:00
JonnyWong16
b4a4f60b04 Fix manual refreshing the libraries/users list 2018-02-16 11:17:30 -08:00
JonnyWong16
dc4e6edc9a Fix update bar dismiss if it was not shown originally 2018-02-16 11:00:01 -08:00
JonnyWong16
60b362b19e Transparent update bar 2018-02-16 10:58:00 -08:00
JonnyWong16
7e81ce8c06 Fade in/out update message 2018-02-16 10:47:59 -08:00
JonnyWong16
c7f9e2f721 Change update bar css 2018-02-16 10:31:22 -08:00
JonnyWong16
cab8b1c041 Check for updates without refreshing the page 2018-02-16 10:24:55 -08:00
JonnyWong16
16f270691d Check on watched notification states before adding to the queue 2018-02-15 15:16:50 -08:00
JonnyWong16
d94a1efe75 Add media info table refresh to API docs 2018-02-15 15:15:36 -08:00
JonnyWong16
12755970b7 Fix failure to make session cache folder on startup 2018-02-15 12:21:44 -08:00
JonnyWong16
93e4853ea2 Fix delete media info cache 2018-02-14 11:19:53 -08:00
JonnyWong16
5e0c0365fb Change button colours on setup wizard 2018-02-14 09:48:04 -08:00
JonnyWong16
c2713c53dd Only connect if first run is complete 2018-02-14 08:53:49 -08:00
JonnyWong16
90443b4028 Catch failed to retrieve Plex Cloud status 2018-02-14 08:53:27 -08:00
JonnyWong16
e0109ed179 Combine connection function for cloud and non-cloud servers 2018-02-14 08:45:45 -08:00
JonnyWong16
a53afe05a2 Check cloud status on startup before connecting websocket 2018-02-14 06:55:44 -08:00
JonnyWong16
a5d2467bfe Less log spam of cloud server status 2018-02-14 06:39:42 -08:00
JonnyWong16
8447663e27 Fix server up/down status on Tautulli startup 2018-02-14 06:35:59 -08:00
JonnyWong16
64d67d8209 Hide remote access check message 2018-02-13 22:48:28 -08:00
JonnyWong16
78034b82a9 Send Use SSL and Remote Server checkbox values when disabled 2018-02-13 22:06:09 -08:00
JonnyWong16
f77bd6c17b Move server selectize dropdown container 2018-02-13 19:30:20 -08:00
JonnyWong16
2621da7d36 Add server selection dropdown to settings 2018-02-13 19:22:11 -08:00
JonnyWong16
e1dca1509a Reconnect Plex Cloud without keeping the server awake 2018-02-13 10:49:11 -08:00
JonnyWong16
df016243dd Refactor some websocket connection code 2018-02-13 08:48:54 -08:00
JonnyWong16
be72693fec Catch WebSocketException when attempting to reconnect 2018-02-13 07:08:35 -08:00
JonnyWong16
33a1ebdb1a Show location for masked session info 2018-02-12 17:40:11 -08:00
JonnyWong16
030f9d334b Improve server selectize on setup wizard 2018-02-12 17:33:35 -08:00
JonnyWong16
dc743ac378 Fix show full changelog on fresh install 2018-02-12 17:16:43 -08:00
JonnyWong16
0010cbe21f Update masked info for guest access 2018-02-12 11:35:34 -08:00
JonnyWong16
3a5d5918de v2.0.18-beta 2018-02-12 09:44:57 -08:00
JonnyWong16
3380e39de2 Add button to delete 3rd party API lookup info 2018-02-12 09:31:44 -08:00
JonnyWong16
7d31079897 Change group history table on by default 2018-02-12 08:20:58 -08:00
JonnyWong16
c287b6df77 Fix DepreciationWarning error for URIs with query string parameters 2018-02-12 08:15:21 -08:00
JonnyWong16
dab1f8ba20 Save The Movie Database info after lookup 2018-02-11 22:03:15 -08:00
JonnyWong16
a26de7f6c2 Move repository 2018-02-11 20:23:37 -08:00
JonnyWong16
ab32b2cbc2 Compressed screenshot for readme 2018-02-11 19:15:20 -08:00
JonnyWong16
503c249fc3 Update API docs 2018-02-11 19:11:31 -08:00
JonnyWong16
2a03ce757e Add toggle for advanced settings 2018-02-11 17:55:37 -08:00
JonnyWong16
373a15524f Remove redundant settings headers 2018-02-11 17:17:08 -08:00
JonnyWong16
13036183d3 Move extra settings to other tabs 2018-02-11 16:38:21 -08:00
JonnyWong16
170591c79e Move some settings, split notifications agents back out 2018-02-11 16:11:00 -08:00
JonnyWong16
a15d225a5f Fix missing Host in login logs for Firefox 2018-02-10 12:23:05 -08:00
JonnyWong16
a0106874e2 Fix paused and resume notifications only triggering once 2018-02-08 21:19:43 -08:00
JonnyWong16
ab157d1c0e Fix default text on Tautulli update notification 2018-02-08 12:21:21 -08:00
JonnyWong16
0b95c9fe2e Add Imgur poster deletion 2018-02-07 17:59:08 -08:00
JonnyWong16
d693514ca9 Notification exclusion tags change media item to media type 2018-02-07 11:44:16 -08:00
JonnyWong16
56987b3aaa Add note to notification exclusion tags 2018-02-07 11:42:17 -08:00
JonnyWong16
3ca1bd5d78 Change custom conditions negative operators to "and" 2018-02-03 17:02:13 -08:00
JonnyWong16
5d2219f2f8 v2.0.17-beta 2018-02-03 09:35:05 -08:00
JonnyWong16
56dc28eed3 Clear session metadata cache on startup 2018-02-03 09:06:05 -08:00
JonnyWong16
3e723d4373 Fix photo album media type 2018-02-02 23:49:38 -08:00
JonnyWong16
f5e341e655 Don't sanitize tags for Slack and Discord 2018-02-02 23:22:41 -08:00
JonnyWong16
3c81100957 Fix media info table sorting 2018-02-02 23:03:48 -08:00
JonnyWong16
304378f93b Add Zapier notification agent 2018-02-01 22:11:33 -08:00
JonnyWong16
de6b6e8124 Check for any falsy value in sync item filters 2018-01-31 08:59:37 -08:00
JonnyWong16
d15223fb1a v2.0.16-beta 2018-01-30 23:20:34 -08:00
JonnyWong16
d29a12b6db Add user filter to the synced table 2018-01-30 23:07:21 -08:00
JonnyWong16
9100e25a21 Pass copy of notification data to prevent multithreading issues 2018-01-30 23:04:44 -08:00
JonnyWong16
7672f1955e Fix sync table not loading 2018-01-30 21:19:37 -08:00
JonnyWong16
5f52171fc4 Add "Use Server Setting" as Plex update channel 2018-01-30 19:56:48 -08:00
JonnyWong16
31ac82ad71 Comment out logging for writing session history to database 2018-01-30 19:06:10 -08:00
JonnyWong16
38ca4e37a6 Fix matching of synced playback 2018-01-30 19:04:30 -08:00
JonnyWong16
3c55550702 Add logging for writing session history to database 2018-01-30 10:04:28 -08:00
JonnyWong16
7dff6b121b Log force stopped message 2018-01-30 09:31:13 -08:00
JonnyWong16
d77d889695 Fix activity callback function argument 2018-01-30 09:13:06 -08:00
JonnyWong16
318a21438f Fix sometimes time showing as "0:60" 2018-01-28 20:19:49 -08:00
JonnyWong16
7175b57a28 Fix "unknown" stream resolution in graphs 2018-01-28 10:06:47 -08:00
JonnyWong16
e1e5a050c2 v2.0.15-beta 2018-01-27 11:08:45 -08:00
JonnyWong16
58996c1115 Unused now time 2018-01-27 10:59:48 -08:00
JonnyWong16
7301fe5f6e Remove 24 hour limit for recently added 2018-01-26 12:29:38 -08:00
JonnyWong16
a27c423569 Line up cards on the homepage 2018-01-24 21:37:02 -08:00
JonnyWong16
19680d3bc7 Refresh stream location on activity cards 2018-01-24 21:14:18 -08:00
JonnyWong16
ecaca4e5dc Change hover text from "View in" to "View on" 2018-01-24 21:07:12 -08:00
JonnyWong16
191de0b577 Add "View On" to Plex Web click-through 2018-01-24 21:04:34 -08:00
JonnyWong16
ebcc073b32 Add more server notification parameters. Rename plexpy parameters to tautulli. 2018-01-22 17:50:48 -08:00
JonnyWong16
043b3fd57b Update state for "Check server response" task 2018-01-22 13:44:51 -08:00
JonnyWong16
dd50502dcb Update Discord link to welcome channel 2018-01-22 11:27:04 -08:00
JonnyWong16
f159a1014d Don't add view_offset to live progress bar 2018-01-21 19:46:23 -08:00
JonnyWong16
abb801535c Add line break for Live progress 2018-01-21 16:09:48 -08:00
JonnyWong16
2732dbf1b1 Fix progress time for live tv 2018-01-21 16:07:32 -08:00
JonnyWong16
095d893005 Improve Live TV info on activity cards 2018-01-21 15:54:38 -08:00
JonnyWong16
5d8455d141 Get rating key for live sessions from websocket data 2018-01-21 13:09:02 -08:00
JonnyWong16
aa3450bfcc Add Labels and Collections to notification parameters 2018-01-20 20:01:01 -08:00
JonnyWong16
770f12b632 Hide advanced settings 2018-01-20 14:03:23 -08:00
JonnyWong16
45c2ccdffe v2.0.14-beta 2018-01-20 11:42:36 -08:00
JonnyWong16
fc14c3165f Remove email line break message 2018-01-20 11:30:11 -08:00
JonnyWong16
0fad245148 Try to cleanly shutdown loggers 2018-01-20 11:27:58 -08:00
JonnyWong16
79609c384e Show all changelogs when updated since previous version 2018-01-20 10:27:08 -08:00
JonnyWong16
09054ddb4b Correct clear logs message 2018-01-19 19:11:55 -08:00
JonnyWong16
6f912d4aa2 Add date header to Emails and do not add HTML line breaks automatically 2018-01-19 15:54:58 -08:00
JonnyWong16
96033a8214 Rename Tautulli update notification parameters 2018-01-19 14:59:00 -08:00
JonnyWong16
5ca65f4797 Catch json ValueError in metadata cache 2018-01-19 07:13:53 -08:00
JonnyWong16
d2fccbde68 Json dump custom conditions 2018-01-18 14:02:47 -08:00
JonnyWong16
e6b48d7baf Check for browser proxy compatibility 2018-01-17 21:02:31 -08:00
JonnyWong16
3e51310511 Re-enable browser notifications 2018-01-17 17:01:44 -08:00
JonnyWong16
32b43202c2 Attempt at fixing stuck sessions which require flishing the database 2018-01-15 18:55:37 -08:00
JonnyWong16
446170f8de Reduce websocket logging to playing and timeline only 2018-01-15 17:59:12 -08:00
JonnyWong16
c5a9ecd4ac Make sure websocket events are for library items 2018-01-15 14:49:49 -08:00
JonnyWong16
2af5f817a3 Plex Web url for tracks should go to the album page 2018-01-15 14:37:40 -08:00
JonnyWong16
4e55cf3cd4 Add all other bandwidth to WAN 2018-01-15 14:25:42 -08:00
JonnyWong16
eeb0478813 Use font-awesome arrow on activity cards 2018-01-14 20:45:27 -08:00
JonnyWong16
33739f1cb2 Fix check activity session write success 2018-01-13 21:16:07 -08:00
JonnyWong16
515e6a8071 Sort selectize when rendered 2018-01-13 17:47:24 -08:00
JonnyWong16
2b22f8eb4f Add select/remove all options for emails 2018-01-13 17:18:09 -08:00
JonnyWong16
e9725a0081 v2.0.13-beta 2018-01-13 12:34:57 -08:00
JonnyWong16
8fd159d2fe Use added_at to check recently added more than 24 hours ago 2018-01-12 12:34:07 -08:00
JonnyWong16
3d7e6c8b2c Update circle logo 2018-01-12 09:01:48 -08:00
JonnyWong16
0c048d61b1 Add message that Imgur upload may be required 2018-01-12 01:00:58 -08:00
JonnyWong16
f05b8e5cd1 Add error message when notification subject/body is required 2018-01-12 00:48:53 -08:00
JonnyWong16
0b38fec827 Add more options for Join notifications 2018-01-12 00:35:37 -08:00
JonnyWong16
547dc9ed33 Fix checking login permissions 2018-01-11 23:28:10 -08:00
JonnyWong16
896a37bea9 Allow Plex admin to login as Tautulli admin 2018-01-11 22:58:30 -08:00
JonnyWong16
3f90037db3 Make custom conditions message clearer 2018-01-11 22:52:52 -08:00
JonnyWong16
380ca11ced Fix some parameter types 2018-01-11 22:07:29 -08:00
JonnyWong16
ab3a288e49 Add "or" between condition values 2018-01-10 18:31:14 -08:00
JonnyWong16
638e225f80 Add selectize resources 2018-01-10 00:36:01 -08:00
JonnyWong16
5089ede207 Add selectize for email input 2018-01-10 00:32:24 -08:00
JonnyWong16
a3e6e76158 Implement JWT instead of using cherrypy sessions 2018-01-08 22:25:52 -08:00
JonnyWong16
7c4c7bfc90 Add pyjwt 1.4.0 2018-01-08 22:24:36 -08:00
JonnyWong16
644fea6665 v2.0.12-beta 2018-01-07 23:44:18 -08:00
JonnyWong16
a1349ff8a6 Add css for selectize to match input boxes 2018-01-07 23:37:18 -08:00
JonnyWong16
71c20002b8 Update build notify text error message 2018-01-07 18:45:55 -08:00
JonnyWong16
157af84226 Only update the database sessions every 60 seconds while playing 2018-01-07 17:10:33 -08:00
JonnyWong16
9b4536f132 Move webserver notify to API 2018-01-07 14:46:01 -08:00
JonnyWong16
29ab470e42 Make metadata cache an advanced config option 2018-01-07 10:01:17 -08:00
JonnyWong16
c67fa480a7 Make condition logic optional
* Implicit "and" between all conditions if logic is blank
2018-01-07 09:42:57 -08:00
JonnyWong16
0a1a691c73 Fix Plex URL notification parameter 2018-01-07 08:28:06 -08:00
JonnyWong16
48588f23bf Add LAN/WAN bandwidth to activity header 2018-01-06 23:06:21 -08:00
JonnyWong16
cf14fbc3f0 v2.0.11-beta 2018-01-05 21:50:35 -08:00
JonnyWong16
e471d5207d Remove experimental tag from calculate file sizes 2018-01-05 21:50:24 -08:00
JonnyWong16
5722a52082 Fix None values in stream data for pre v2 history 2018-01-05 21:37:54 -08:00
JonnyWong16
08c32e875e Fix login using hashed password 2018-01-05 21:01:32 -08:00
JonnyWong16
7d3ee3afb3 Fix recently added show title 2018-01-05 21:01:10 -08:00
JonnyWong16
def8600f5c Reload notify params from raw stream info 2018-01-05 14:22:20 -08:00
JonnyWong16
74a68f3c7d v2.0.10-beta 2018-01-04 19:55:13 -08:00
JonnyWong16
64c9247dd1 Remove library/user notification toggles
* Filter out notifications using custom conditions
2018-01-04 19:39:16 -08:00
JonnyWong16
1bfcd34247 Some formatting for common.py 2018-01-04 13:40:34 -08:00
JonnyWong16
19864e97e6 Fix media type in collection header 2018-01-04 13:40:34 -08:00
JonnyWong16
ec5c5e1420 Merge pull request #1195 from Tommatheussen/patch-1
Update date formats
2018-01-04 13:39:25 -08:00
Tom Matheussen
803f4e14ca Added some additional formats 2018-01-04 22:18:40 +01:00
Tom Matheussen
6cc254b80a Update Date Formats
Added correct Year date formats, replaced generic numeric values with actual examples
2018-01-04 21:32:59 +01:00
JonnyWong16
59593ab1aa Fix HW indicator on activity refresh 2018-01-03 20:29:52 -08:00
JonnyWong16
65a0a0eb7d v2.0.9-beta 2018-01-03 19:37:12 -08:00
JonnyWong16
f4206b401f Fix season/episode numbers zfill 2018-01-03 19:24:19 -08:00
JonnyWong16
99f8d24b3e Remove bottom padding on stats info 2018-01-03 16:35:22 -08:00
JonnyWong16
26b06e453d v2.0.8-beta 2018-01-03 16:08:21 -08:00
JonnyWong16
54ab646048 Don't line break product or player on activity cards 2018-01-03 16:02:22 -08:00
JonnyWong16
12c9aa3d6a Try caching metadata for sessions 2018-01-03 13:36:26 -08:00
JonnyWong16
1ae8544f2d Cleanup notification parameters 2018-01-03 11:36:49 -08:00
JonnyWong16
eae9e66c75 Updating missing notification parameters 2018-01-02 16:18:50 -08:00
JonnyWong16
ad041a1691 Attempt to fix HW transcoding indicator 2018-01-02 16:13:27 -08:00
JonnyWong16
1aee3b6c8f Add idna 2.6 2018-01-02 09:03:55 -08:00
JonnyWong16
04d4ffb63d v2.0.7-beta 2018-01-01 18:05:26 -08:00
JonnyWong16
80b318b45c Check for failed to retrieve releases from GitHub 2018-01-01 16:09:26 -08:00
JonnyWong16
19969a8b1f Clickable logo using pointer-events 2018-01-01 11:11:17 -08:00
JonnyWong16
b84888356f Don't decode http response content 2017-12-31 22:13:39 -08:00
JonnyWong16
c9436195f3 Fix session pause timestamp 2017-12-31 20:50:03 -08:00
JonnyWong16
98cfb50571 Fix hub related request 2017-12-31 20:32:52 -08:00
JonnyWong16
b67884ea7f Fix LAN/WAN on activity cards 2017-12-31 20:30:48 -08:00
JonnyWong16
c7081b4417 v2.0.6-beta 2017-12-31 19:48:14 -08:00
JonnyWong16
83f1519932 Beta Plex Cloud support 2017-12-31 19:44:01 -08:00
JonnyWong16
6c6493fe31 Import urllib3 directly 2017-12-31 18:56:08 -08:00
JonnyWong16
1564cdf55e Add chardet 3.0.4 2017-12-31 18:56:08 -08:00
JonnyWong16
ffcb1144b6 Add urllib3 1.22 2017-12-31 18:56:08 -08:00
JonnyWong16
4ad644ab7f Update http handler for new requests and certifi 2017-12-31 18:56:08 -08:00
JonnyWong16
f1783df8d6 Update certifi to 2017.11.05 2017-12-31 18:56:08 -08:00
JonnyWong16
b1a3dd1a46 Update requests to 2.18.4 2017-12-31 18:56:08 -08:00
JonnyWong16
52eac2b437 Import certifi from requests 2017-12-31 18:56:08 -08:00
JonnyWong16
ca20eda606 Update paused time while still paused 2017-12-31 18:37:55 -08:00
JonnyWong16
4e3b95950f Fix history table stopped time showing as "n/a" 2017-12-31 18:36:57 -08:00
JonnyWong16
9d01335395 v2.0.5-beta 2017-12-31 17:52:53 -08:00
JonnyWong16
63814584e9 Add sortcut to /status/sessions 2017-12-31 17:37:07 -08:00
JonnyWong16
bf7e432c0c Add total bandwidth to activity header 2017-12-31 17:13:38 -08:00
JonnyWong16
5a14c229a1 Fix IPv6 overflow on current activity cards 2017-12-31 17:12:49 -08:00
JonnyWong16
79581fb83e Sanitize script output in logger 2017-12-31 14:41:32 -08:00
JonnyWong16
90c587e6e1 Unique session id name to not conflict with multiple installs 2017-12-31 14:33:21 -08:00
JonnyWong16
b2b728a3cc Save cherrypy sessions to disk instead of ram 2017-12-31 14:29:57 -08:00
JonnyWong16
645ef86c75 Fix Join notifications not sending 2017-12-31 14:29:57 -08:00
JonnyWong16
450fda18f1 Merge pull request #1181 from felixbuenemann/fix-cherrypy-ssl-connection-type-deprecation
Fix OpenSSL SSL.ConnectionType deprecation warning
2017-12-31 12:37:22 -07:00
Felix Bünemann
f6162a8df8 Fix OpenSSL SSL.ConnectionType deprecation warning
This patches the vendored cherrypy lib to work around a deprecation
warning in pyOpenSSL 17.1.0 and later by checking and using the
SSL.Connection class if available and falling back to ConnectionType.
2017-12-31 14:30:15 +01:00
JonnyWong16
a8c5f48b60 Merge branch 'nightly' of https://github.com/JonnyWong16/plexpy into nightly 2017-12-30 23:22:02 -08:00
JonnyWong16
edc0b96167 Some sync data updates 2017-12-30 23:21:31 -08:00
JonnyWong16
9b4b3e0ecb Add stopped state to history table activity 2017-12-30 17:27:59 -08:00
JonnyWong16
7bd2c00636 Fix presence in get_server_resources 2017-12-30 17:27:50 -08:00
JonnyWong16
15faccfa2f Update server connection code 2017-12-30 17:27:39 -08:00
JonnyWong16
11e10e7d0e Update resources links 2017-12-30 16:13:55 -08:00
JonnyWong16
8ef48fc548 Update svg logo with shadows 2017-12-30 14:14:47 -08:00
JonnyWong16
29632b0805 Validate git releases as a list 2017-12-29 16:49:55 -08:00
JonnyWong16
e908c45cf2 v2.0.4-beta 2017-12-29 16:35:24 -08:00
JonnyWong16
c37e934f42 Check concurrent streams from the server instead of database 2017-12-29 16:29:20 -08:00
JonnyWong16
41f91956b8 Make sure current activity is loaded before refreshing 2017-12-29 16:26:50 -08:00
JonnyWong16
8b2bd5ce79 Add collections info pages 2017-12-29 15:52:08 -08:00
JonnyWong16
28e4151157 Remember tab when going back on library and user pages 2017-12-29 11:34:41 -08:00
JonnyWong16
66d45293e6 Add test Plex Web URL button 2017-12-29 10:47:31 -08:00
JonnyWong16
243eeeff67 v2.0.3-beta 2017-12-25 09:58:24 -08:00
JonnyWong16
18520e24d1 Report correct release version on beta 2017-12-25 09:48:33 -08:00
JonnyWong16
87743171b7 Fix write session history optimized_version_title column name 2017-12-25 09:07:02 -08:00
JonnyWong16
452f0747c8 Add missing stream info modal css 2017-12-25 09:02:33 -08:00
JonnyWong16
a20747044c Fix sync ID 2017-12-25 09:00:42 -08:00
JonnyWong16
e60241ca73 v2.0.2-beta 2017-12-24 13:53:49 -08:00
JonnyWong16
c69e68a4a8 Alias media info title to sort title 2017-12-24 11:29:12 -08:00
JonnyWong16
561d994328 Fix config version updgrade 2017-12-24 07:52:11 -08:00
JonnyWong16
33acf9402d Improved synced and optimized version info 2017-12-23 11:52:28 -08:00
JonnyWong16
0a42cb4135 Update stream info modal 2017-12-22 22:04:40 -08:00
JonnyWong16
19695c220b Fix some missing subtitle database columns 2017-12-22 19:55:21 -08:00
JonnyWong16
1fbc0165e6 Fix source video/audio/subtitle parameters in notifications 2017-12-22 14:22:37 -08:00
JonnyWong16
4dd05e217a Add back HTTP Proxy setting 2017-12-22 13:01:25 -08:00
JonnyWong16
b77a409414 Add sort title to metadata, sort media info tables by sort title 2017-12-22 12:40:58 -08:00
JonnyWong16
b2157df026 Default blank session value when writing session history 2017-12-22 11:47:28 -08:00
JonnyWong16
0b8d5954f9 Fix librariaes page 2017-12-22 10:30:45 -08:00
JonnyWong16
0d60c7b728 Remove unused logos 2017-12-21 15:30:24 -08:00
JonnyWong16
de58136314 Do not send recently added notification if item updated more than 24 hours ago 2017-12-21 15:22:18 -08:00
JonnyWong16
4e718056b6 Remove bif thumbnail setting 2017-12-21 11:23:27 -08:00
JonnyWong16
480913362e Fix default setup wizard settings 2017-12-21 11:23:11 -08:00
JonnyWong16
ad2f61132a Change logos to svgs 2017-12-21 10:49:14 -08:00
JonnyWong16
0e2df4ba14 Add note to enable 3rd party APIs for link lookup 2017-12-21 10:47:32 -08:00
JonnyWong16
c342273742 Retrieve session by session key 2017-12-19 22:20:24 -08:00
JonnyWong16
0cb147cd8f Cleanup safari-pinned-tab svg 2017-12-19 21:49:09 -08:00
JonnyWong16
11b2a17fb3 Fix white in logo text 2017-12-19 21:36:11 -08:00
JonnyWong16
23486ff235 Update favicons 2017-12-19 21:29:07 -08:00
JonnyWong16
a9e24bc0c5 Remove update section ids 2017-12-19 20:36:24 -08:00
JonnyWong16
3c22496ea2 Fix some platform mappings 2017-12-19 20:28:40 -08:00
JonnyWong16
b8164ca556 Validate condition logic on save 2017-12-19 17:32:37 -08:00
JonnyWong16
19565b3d0a Add message to verify server for error communicating 2017-12-19 17:27:20 -08:00
JonnyWong16
50ce17ac72 Fix missing users table cache parameter 2017-12-19 16:40:45 -08:00
JonnyWong16
e51a425389 API enabled by default 2017-12-19 11:47:59 -08:00
JonnyWong16
3df7642193 Missing save button in settings 2017-12-19 11:21:07 -08:00
JonnyWong16
38ad9c9893 v2.0.1-beta 2017-12-19 10:56:25 -08:00
JonnyWong16
fb75b9566f Temporarily disable browser notifications 2017-12-19 10:33:42 -08:00
JonnyWong16
80a6118bf9 Fix music stats background fallback 2017-12-19 09:42:11 -08:00
JonnyWong16
6b2bc0108b Fix Join apikey 2017-12-18 23:09:50 -08:00
JonnyWong16
bd07cf5a04 Missing video_height database column 2017-12-18 13:51:14 -08:00
JonnyWong16
f07ad960dc Merge branch 'v2' into nightly 2017-12-17 23:21:31 -08:00
JonnyWong16
824e975598 v2.0.0-beta 2017-12-17 23:17:44 -08:00
JonnyWong16
4f44c64e4a Switch to master/beta/nightly branches 2017-12-17 23:13:15 -08:00
JonnyWong16
a449670667 Some more first run fixes 2017-12-17 23:12:56 -08:00
JonnyWong16
7cd38581a6 Fix duplicate database column video_width 2017-12-17 22:52:38 -08:00
JonnyWong16
507ecee2e3 Update links in readme 2017-12-16 13:32:02 -08:00
JonnyWong16
95a6c62dd9 Fix clipped shadow in logos 2017-12-16 12:52:33 -08:00
JonnyWong16
b8c1fef700 Add Tautulli text logo 2017-12-16 12:52:33 -08:00
JonnyWong16
7a8301a8dc Update git repo links 2017-12-16 12:52:33 -08:00
JonnyWong16
19f029cff0 Rename PlexPy to Tautulli 2017-12-16 12:52:33 -08:00
JonnyWong16
55bdde808b Update all Tautulli image assets 2017-12-16 12:47:05 -08:00
JonnyWong16
abab2f3f6b Update setup wizard 2017-12-16 12:43:14 -08:00
JonnyWong16
c586fe1d07 Update session database with all session data 2017-12-16 09:08:17 -08:00
JonnyWong16
1b0c32f4e7 Fix logging for subtitles enabled 2017-12-16 09:07:32 -08:00
JonnyWong16
e667f4487f Log new stream info to database 2017-12-14 20:00:33 -08:00
JonnyWong16
507be2e6e3 Remove monitoring interval setting 2017-12-14 19:59:53 -08:00
JonnyWong16
5ff3c433b2 Add missing concurrent streams icon 2017-12-14 06:44:39 -08:00
JonnyWong16
7c825f72aa Add background colour to poster blur 2017-12-13 22:34:12 -08:00
JonnyWong16
36e604dc91 Add blur poster behind cover art 2017-12-13 22:22:27 -08:00
JonnyWong16
b6c5068bc4 Rename svg, add ios, change padding 2017-12-13 21:26:39 -08:00
JonnyWong16
af78f98106 svg icon css background contain 2017-12-13 20:50:26 -08:00
JonnyWong16
b209c29749 Use svg for platform and library icons 2017-12-13 20:48:04 -08:00
JonnyWong16
e28965f8b3 Fix info in terminate stream modal 2017-12-12 22:22:38 -08:00
JonnyWong16
117c228672 Update Plex logs setting help text 2017-12-11 21:30:17 -08:00
JonnyWong16
359273e26e Group library statistic cards by library type 2017-12-11 21:28:26 -08:00
JonnyWong16
b22ae58f79 Updated library cards on the homepage 2017-12-10 20:33:14 -08:00
JonnyWong16
07d8fbb7f4 Reset recently added scoller before refresh 2017-12-10 16:39:10 -08:00
JonnyWong16
9edce2d387 Move 3rd Pary APIs settings 2017-12-10 15:26:32 -08:00
JonnyWong16
1787fff8c3 Update to use Plex hub search 2017-12-09 23:59:25 -08:00
JonnyWong16
1b5e5f37d0 Add option to override Plex Web URL 2017-12-09 23:08:52 -08:00
JonnyWong16
b76143116c Better restart/shutdown refresh page polling 2017-12-09 22:32:39 -08:00
JonnyWong16
20e3eebd6a Add setting for manual server connection 2017-12-09 22:14:43 -08:00
JonnyWong16
f42f1182f2 Reimplement recently added delay to group items 2017-12-09 21:34:41 -08:00
JonnyWong16
7e7609743a Add callback to force stop stale streams 2017-12-09 02:09:14 -08:00
JonnyWong16
a00f36f83b Do not send Plex server down on websocket excpetion 2017-12-09 01:54:43 -08:00
JonnyWong16
e353d0518c Reword QR instructions 2017-12-08 23:02:58 -08:00
JonnyWong16
5efe2be7b2 Fix app parameter in api 2017-12-08 22:29:40 -08:00
JonnyWong16
53d0bef260 Add app parameter to api 2017-12-08 22:26:06 -08:00
JonnyWong16
ecd0a199f1 Add mobile device last seen 2017-12-08 22:05:44 -08:00
JonnyWong16
019787b32d Add mobile device settings 2017-12-08 20:52:55 -08:00
JonnyWong16
1ca1f9975c Product instead of Platform on activity card 2017-12-08 17:46:19 -08:00
JonnyWong16
2d76991a86 Fix watch staistics posters hover title 2017-12-08 10:11:41 -08:00
JonnyWong16
2fee437010 Double check if notificaitons was already sent 2017-12-07 22:11:05 -08:00
JonnyWong16
4e7c91617b Forgot import for 595af9e 2017-12-07 20:59:11 -08:00
JonnyWong16
86e1e99b33 Fix watch statistics poster link 2017-12-07 19:54:59 -08:00
JonnyWong16
595af9e70b Retrieve poster directly from Plex for GroupMe 2017-12-07 19:45:22 -08:00
JonnyWong16
d23c4ef319 Upload from Imgur to Telegram directly 2017-12-07 19:45:03 -08:00
JonnyWong16
1d9d16b69b Rename Plex websocket log 2017-12-02 12:28:38 -08:00
JonnyWong16
a6ee70b7ec Fix typo in Prowl key config 2017-12-02 09:36:31 -08:00
JonnyWong16
7921681fad Try returning unicode request message 2017-12-02 09:01:45 -08:00
JonnyWong16
256ddde07d Add keys and ids to Android app notification payload data 2017-12-02 08:52:06 -08:00
JonnyWong16
e606bd512f Fix missing 'or' in condition for on_stop notifications 2017-12-02 08:51:23 -08:00
JonnyWong16
ffb38ef599 Update blacklist after changing notifier configs 2017-12-01 12:31:27 -08:00
JonnyWong16
f9e7c2bdb6 Fix typo in Pushover config in 9ba6b23 2017-12-01 12:31:09 -08:00
JonnyWong16
76cc61e0c2 Change MQTT client_id to clientid 2017-12-01 12:07:29 -08:00
JonnyWong16
9ba6b230e6 Change logger blacklist to set and unify notifier blacklist keys 2017-12-01 12:00:50 -08:00
JonnyWong16
31f03e0114 Fix unicode error in notification text when using conversion or splice 2017-11-30 21:51:25 -08:00
JonnyWong16
7e7693f206 Better apikey generation 2017-11-30 20:00:44 -08:00
JonnyWong16
6cae12d467 Revert Android App notification encryption to SHA1 2017-11-30 19:47:31 -08:00
JonnyWong16
1235f73332 Fix getting source media info parts 2017-11-11 20:26:17 -08:00
JonnyWong16
75dfb82a88 Rename history table column to "Date" 2017-11-11 19:56:24 -08:00
JonnyWong16
a2eeda64df Add ability to delete synced items 2017-11-11 19:41:51 -08:00
JonnyWong16
718049b9f3 Add custom modifiers to notification text 2017-11-11 18:07:42 -08:00
JonnyWong16
fdff9d7454 Default to 'Unknown' for any missing activity values 2017-11-10 21:13:03 -08:00
JonnyWong16
976418de0f Fallback for failed media info id matching 2017-11-10 20:10:46 -08:00
JonnyWong16
e51e9493b1 Remove stats count setting 2017-11-07 20:30:28 -08:00
JonnyWong16
8535fa4e0a Don't use new library icons 2017-11-07 20:30:03 -08:00
JonnyWong16
16b05a47c0 Manually merge v2-new-icons into v2 2017-11-06 21:28:51 -08:00
JonnyWong16
ff7fee6abf Make sure activity progress cannot exceed 100% 2017-11-06 20:31:46 -08:00
JonnyWong16
7f2e740bc0 Fallback stream duration 2017-11-06 20:22:49 -08:00
JonnyWong16
3df31bb01b Lock scrolling of activity card overflow 2017-11-06 18:09:35 -08:00
JonnyWong16
c6a36cb4cf Add user to recently watched card and date to most concurrent card 2017-11-05 14:51:04 -08:00
JonnyWong16
2873d8bba3 Lock scroller on statistics cards 2017-11-05 13:28:27 -08:00
JonnyWong16
d77696be59 Flexbox activity card metadata 2017-11-05 13:28:10 -08:00
JonnyWong16
1bd2f332d9 Plex for Vizio uses Opera platform 2017-11-05 12:59:20 -08:00
JonnyWong16
e4a2616ffa Prevent password autofill in settings 2017-11-05 12:08:36 -08:00
JonnyWong16
99f93a8d50 Combine activity header into one activity function 2017-11-05 11:06:51 -08:00
JonnyWong16
e80d88c9ff Make sure there are stats before creating the watched statistic cards 2017-11-05 07:35:08 -08:00
JonnyWong16
8d2c9a7764 New watch statistics cards 2017-11-05 00:30:44 -07:00
JonnyWong16
de589f59a1 A bit of CSS cleanup for activity cards 2017-11-04 23:12:05 -07:00
JonnyWong16
627f552976 Fix some channel metadata for activity 2017-11-03 20:31:11 -07:00
JonnyWong16
67bac92849 Add channels to activity 2017-11-03 19:46:41 -07:00
JonnyWong16
e1dc299cba Add identifying playback of synced items 2017-11-02 18:33:18 -07:00
JonnyWong16
3f668ae5c6 Add pseudo progress bar update 2017-11-01 20:11:40 -07:00
JonnyWong16
0d54e9f2d6 Cache css and js based on commit hash or version number 2017-11-01 19:23:14 -07:00
JonnyWong16
ef6ef868e0 Temporary fixes for masked info for guest access 2017-11-01 19:13:54 -07:00
JonnyWong16
5d8da23c3f Add pseudo view offset counter 2017-10-31 23:28:01 -07:00
JonnyWong16
43f285951d Add background to statistic cards 2017-10-30 23:47:24 -07:00
JonnyWong16
7714ecc7dd Fix some background overflow bleeding 2017-10-30 23:46:59 -07:00
JonnyWong16
6a39201961 Ease-in-out trasition for terminate button 2017-10-30 23:09:37 -07:00
JonnyWong16
f0ca7385b9 Move admin CSS to separate file 2017-10-30 23:00:45 -07:00
JonnyWong16
567bba0c44 Sorted raw stream info json 2017-10-29 11:43:49 -07:00
JonnyWong16
7559c0c6f8 Json values are integers not strings 2017-10-29 11:43:38 -07:00
JonnyWong16
58bcd068f2 Fix HW transcoding indicator 2017-10-29 11:23:53 -07:00
JonnyWong16
7047829943 Add hidden raw stream info 2017-10-29 11:13:50 -07:00
JonnyWong16
b6a634ea6f Add media type icon 2017-10-29 10:48:01 -07:00
JonnyWong16
15a871889f Add info icon for bandwidth tooltip 2017-10-29 10:35:37 -07:00
JonnyWong16
9d2cfaa3f5 Toggle terminte session button when hovering over entire card 2017-10-29 10:25:32 -07:00
JonnyWong16
8625d3f127 Fix some incorrect codec info displayed 2017-10-29 10:23:51 -07:00
JonnyWong16
f07a7fa2cf New current activity cards 2017-10-29 02:45:18 -07:00
JonnyWong16
c6a4c4d6b3 Remove websocket require restart message in settings 2017-10-29 00:25:33 -07:00
JonnyWong16
df55f70991 Fix bif thumb for music 2017-10-14 14:38:54 -07:00
JonnyWong16
37951cd69b Manually merge v1.4.25 into v2 2017-10-02 18:14:46 -07:00
JonnyWong16
cfd3099626 v1.4.25 2017-10-02 18:08:23 -07:00
JonnyWong16
3db6c98c27 Fix tab to space 2017-10-02 18:07:16 -07:00
JonnyWong16
3c04b04b98 Make TMDb and TVmaze lookup optional 2017-10-01 12:04:29 -07:00
JonnyWong16
d207d4a508 Add missing Trakt.tv provider name 2017-10-01 11:51:09 -07:00
JonnyWong16
df4e466fdf Manually merge v1.4.24 into v2 2017-10-01 11:19:42 -07:00
JonnyWong16
5417747473 v1.4.24 2017-10-01 11:13:16 -07:00
JonnyWong16
cf6847d777 Fallback to product if player title is blank 2017-10-01 11:08:52 -07:00
JonnyWong16
464fa1f8a3 Add no forking option to startup arguments 2017-10-01 11:08:40 -07:00
JonnyWong16
665a6435ef Merge pull request #1076 from Vashypooh/master
Added support for windows service
2017-10-01 10:49:49 -07:00
JonnyWong16
2d64ba4a0e Merge pull request #1107 from Joshua1337/master
Update web 3.20.5 urls
2017-10-01 10:43:58 -07:00
JonnyWong16
a6fd7b581f Rename column header to "Total Played Duration" 2017-09-30 23:42:12 -07:00
JonnyWong16
58712a2d05 Add api and websocket to preformatted log reader 2017-09-30 23:39:00 -07:00
JonnyWong16
39da58d3bc Log failed login attempts 2017-09-30 23:34:46 -07:00
JonnyWong16
daec864f50 Manually merge v1.4.23 into v2 2017-09-30 16:47:26 -07:00
JonnyWong16
54cd860c13 Separate API and websocket logging 2017-09-30 16:42:25 -07:00
JonnyWong16
fe210646c3 Use player product name if no title 2017-09-30 16:41:29 -07:00
JonnyWong16
006c778dca v1.4.23 2017-09-30 15:28:32 -07:00
JonnyWong16
bd636b756b Update PushBullet authorization header 2017-09-30 15:03:51 -07:00
JonnyWong16
d21b74f231 Fix regression for PlexWatch and Plexivity import 2017-09-30 15:01:10 -07:00
JonnyWong16
4354f72578 Update platform name override for Playstation 4 2017-09-30 14:53:24 -07:00
JonnyWong16
f5ca522e6c Update coin addresses 2017-09-30 14:44:14 -07:00
JonnyWong16
3c1d0d3128 Reset button state after modal shown on info page 2017-09-30 11:00:24 -07:00
JonnyWong16
5d2f1d7014 Select notification agent for manual recently aded notifications
* And add to API
2017-09-30 10:46:08 -07:00
JonnyWong16
a17c3f8138 Return empty dict if tvmaze/themoviedb lookup fails 2017-09-28 19:59:54 -07:00
JonnyWong16
45f002a797 Add manual trigger for recently added notifications from the info page 2017-09-26 22:21:04 -07:00
JonnyWong16
4a16ee6865 Update web interface settings help text 2017-09-26 21:03:11 -07:00
JonnyWong16
76e9e24c41 Simpler http root check when starting webserver 2017-09-26 20:58:20 -07:00
JonnyWong16
92a3589588 Check for / in http root setting 2017-09-26 20:52:03 -07:00
JonnyWong16
1e10ddec99 Move modals to template includes on history page 2017-09-26 20:27:15 -07:00
JonnyWong16
ad827e62f6 Fix typo from cd007ee
* Also better https replace for Imgur urls
2017-09-18 19:42:28 -07:00
JonnyWong16
6dd7e8445a Add default values for session bandwidth and location 2017-09-13 18:54:03 -07:00
JonnyWong16
9364e5ab91 Add purge to user delete message 2017-09-13 18:52:46 -07:00
Joshua Dehler
8a556a50ab Fix web 3.20.5 urls 2017-09-08 20:13:45 +02:00
Joshua Dehler
532ff59dfe Fix web 3.20.5 urls 2017-09-08 20:13:07 +02:00
JonnyWong16
9a48383eb4 Use stopped time to calculate duration for current activity in history table 2017-08-25 23:00:40 -07:00
JonnyWong16
07524242c0 Replace IP with session location 2017-08-23 22:24:22 -07:00
JonnyWong16
3b0e4bf254 Only update bif if playing state 2017-08-23 22:23:33 -07:00
JonnyWong16
da3abf11a2 Fix use float when rounding bitrate/bandwidth 2017-08-23 22:10:24 -07:00
JonnyWong16
aee752e04e Add MQTT notification agent 2017-08-23 20:51:27 -07:00
JonnyWong16
b4fa6befdf Fix test script args 2017-08-23 20:46:46 -07:00
JonnyWong16
cd007ee0eb Catch exception so websocket doesn't crash when failed to process data 2017-08-23 20:33:14 -07:00
JonnyWong16
bbe309e7bd Set session state for buffer events 2017-08-23 20:29:48 -07:00
JonnyWong16
f414d7aa16 Check for localhost in QR address 2017-08-22 22:33:58 -07:00
JonnyWong16
be2989ead1 Allow manual entry of QR code server address 2017-08-22 22:03:55 -07:00
JonnyWong16
1c8e581cf1 Write stopped time to database for all events
* To prevent the "long duration" websocket issue for missing stop events
2017-08-22 20:29:21 -07:00
JonnyWong16
a81dfe83a9 Turn on logging of disabled user/library notifications 2017-08-19 23:49:32 -07:00
JonnyWong16
4b9b8d61f2 Add loader message to homepage toggles 2017-08-19 23:49:08 -07:00
JonnyWong16
4fa5fb909c Fixed height recently added row when empty 2017-08-19 23:35:42 -07:00
JonnyWong16
2d7fb82dd6 Fix API json encoding 2017-08-19 21:38:22 -07:00
JonnyWong16
48152c9ba3 Fix stream width and height info 2017-08-19 21:23:41 -07:00
JonnyWong16
a5771dccf5 Fix session start log format error 2017-08-19 21:23:16 -07:00
JonnyWong16
581b8375b9 Manually merge v1.4.22 into v2 2017-08-19 21:11:08 -07:00
JonnyWong16
ec685407bb v1.4.22 2017-08-19 20:50:28 -07:00
JonnyWong16
be9a1dcf06 Temporary fix for incorrect source media info 2017-08-19 20:48:01 -07:00
JonnyWong16
1f7e8b4d9a Fix removing old config backups 2017-08-19 20:29:49 -07:00
JonnyWong16
9058c5accb Explicitly assign websocket state 2017-08-18 10:57:02 -07:00
JonnyWong16
a0799e8197 Initialize scheduler to reconnect websocket when failed on startup 2017-08-13 09:44:15 -07:00
JonnyWong16
21309ba280 Remove speed from activity when transcode throttled 2017-08-13 09:43:45 -07:00
JonnyWong16
b66018a5c3 Increase activity refresh to 2 seconds 2017-08-13 09:10:00 -07:00
JonnyWong16
f0e14b6de5 Round bitrate/bandwidth to Mbps 2017-08-13 09:09:39 -07:00
JonnyWong16
845c3d419a Add audio quality profiles 2017-08-08 21:38:46 -07:00
JonnyWong16
00e281dfb7 Fix crashing when streaming clips 2017-08-08 21:37:57 -07:00
JonnyWong16
b3da08ce74 Merge pull request #1084 from mttlmy/dev
Added platform 'Linux' to link to image linux.png
2017-08-07 16:32:12 -07:00
mttlmy
50753db4ff Added platform 'Linux' to link to image linux.png 2017-08-07 19:27:46 -04:00
JonnyWong16
862c9cea87 Add network and bandwidth to current activity
* Move quality profile to info bar
2017-08-07 11:25:26 -07:00
JonnyWong16
427f24dffe Add inner shadow for terminate session button 2017-08-04 08:55:08 -07:00
JonnyWong16
68072d8340 Manual merge of v1.4.21 into v2 2017-08-02 21:37:59 -07:00
JonnyWong16
1ac4d43db2 Add message for no recently added items 2017-08-02 21:22:37 -07:00
JonnyWong16
e0b78adfee Add recently added media type toggles to homepage 2017-08-02 21:12:59 -07:00
JonnyWong16
0c481fc005 Fix media info tables 2017-07-26 19:17:24 -07:00
JonnyWong16
9f6ee3e761 Return blank TVMaze/TMDB info on failed database queries 2017-07-26 15:45:09 -07:00
JonnyWong16
81dca01302 Create table indices after table upgrades 2017-07-26 15:42:27 -07:00
JonnyWong16
0c62a83145 Add terminate session button to current activity 2017-07-23 13:03:16 -07:00
JonnyWong16
c780b9fd65 Remove help text for provider notification parameters 2017-07-23 02:12:30 -07:00
JonnyWong16
0e180cb242 Add provider links for Discord, Hipchat, Pushover, and Slack 2017-07-23 01:56:44 -07:00
JonnyWong16
41101921ed Add rating key to The Movie Database and TVmaze lookups 2017-07-23 01:56:44 -07:00
JonnyWong16
80ee8f9617 Add The Movie Database lookup 2017-07-23 01:56:33 -07:00
JonnyWong16
1f55b5457e Add homepage stats toggles 2017-07-22 18:13:53 -07:00
Vashypooh
b3fe6145e2 Added support for windows service
Added support for running as a windows service so it does not fork the process on reboot.
2017-07-22 16:02:42 -04:00
William Comartin
527af7063d New icons for platforms and libraries 2017-07-18 20:46:00 -04:00
William Comartin
25455e8194 Add user_id param to get_users_table 2017-07-15 22:08:59 -04:00
JonnyWong16
c27c1379d0 Update Facebook for provider link only
* Custom poster/metadata removed in Graph API v2.9
2017-07-10 22:34:50 -07:00
JonnyWong16
42a7ae36c2 Add TVmaze lookup 2017-07-10 22:33:20 -07:00
JonnyWong16
ce846d65cb Imgur uploads to use requests library 2017-07-10 22:21:12 -07:00
JonnyWong16
dc25ef857f Refactor notifier requests and better logging 2017-07-08 15:07:01 -07:00
JonnyWong16
6f0c650a72 Separate movie/episode/track watched percent 2017-07-07 19:01:04 -07:00
JonnyWong16
8348424758 Merge branch 'v2-notifications-conditions' into v2 2017-07-07 18:09:34 -07:00
JonnyWong16
9701474662 Update all notifiers to use requests library 2017-07-06 22:42:34 -07:00
JonnyWong16
e284a17034 Fix logic parsing for nested and 2017-07-06 09:20:32 -07:00
JonnyWong16
abf55df26d Add GroupMe notification agent 2017-07-05 21:51:15 -07:00
JonnyWong16
6488a7436a Send single MQTT notification 2017-07-05 21:10:39 -07:00
JonnyWong16
cceff2e8dd Add note about order of operations 2017-07-05 19:27:45 -07:00
JonnyWong16
161e6f70d0 Remove the use of eval for evaluating custom notification logic 2017-07-05 19:13:02 -07:00
JonnyWong16
d4e5a750e0 Add condition parameter type passed from JS 2017-07-05 18:47:34 -07:00
William Comartin
b1264bedd8 Merge branch 'v2-notifications-conditions' of github.com:JonnyWong16/plexpy into v2-notifications-conditions 2017-07-05 16:37:53 -04:00
William Comartin
5323ae2943 Update filterer.jquery.js newest version adds type to conditions output from update method 2017-07-05 16:37:23 -04:00
JonnyWong16
af77e51307 v1.4.21 2017-07-01 16:45:44 -07:00
JonnyWong16
b4e8689e92 Fix qrcode javascript 2017-07-01 16:45:37 -07:00
JonnyWong16
8ec30a77ff Update donation methods 2017-07-01 16:35:12 -07:00
JonnyWong16
29c7853380 v1.4.20 2017-06-24 21:41:24 -07:00
JonnyWong16
cd417aaf44 Support custom port for Mattermost (Slack) notifications 2017-06-24 21:34:53 -07:00
JonnyWong16
428a5cc0ff Udate file sizes when refreshing media info 2017-06-24 21:34:22 -07:00
JonnyWong16
d128d7c8e6 Sort 4k properly in media info table 2017-06-24 21:17:26 -07:00
JonnyWong16
8027199bd5 Merge pull request #1021 from senepa/senepa-patch-1
Fixed math used to calculate human_duration
2017-06-24 21:07:35 -07:00
JonnyWong16
099a887cc7 Add PlexTogether platform image 2017-06-24 21:06:40 -07:00
Nicholas Alipaz
e17c551555 Fix reviewed items by JonnyWong16 2017-06-20 17:03:03 -07:00
Nicholas Alipaz
f7166f37f5 Remove MQTT settings form config 2017-06-20 16:54:01 -07:00
Nicholas Alipaz
6bc12e17fd Initial mqtt notification agent 2017-06-20 15:14:05 -07:00
JonnyWong16
ea41d06023 v1.4.19 2017-05-31 19:55:42 -07:00
JonnyWong16
5147baab05 Temporary fix for current activity resolution on PMS 1.7.x 2017-05-31 19:50:44 -07:00
JonnyWong16
ae5777e612 Another temporary fix for media_part_info 2017-05-16 22:26:20 -07:00
JonnyWong16
1b5a7d78d4 Temporary fix for metadata media_info 2017-05-16 22:05:34 -07:00
JonnyWong16
7ba2b7828c Check for blank parameter and operator 2017-05-08 09:21:49 -07:00
William Comartin
1eac1002b2 Update Filterer, Fixes null Values issue 2017-05-08 11:57:54 -04:00
William Comartin
f41280f5b9 Setup Selectize for Filterer Values 2017-05-08 00:30:55 -04:00
JonnyWong16
8653b5b928 Update log error message 2017-05-07 20:26:12 -07:00
JonnyWong16
5b5ebadfea Use list of values for conditions 2017-05-07 17:40:41 -07:00
JonnyWong16
12c94ee79e Add parsing and evaluating custom notification conditions 2017-05-07 13:07:24 -07:00
JonnyWong16
d536a10d20 Fix notification parameters category names 2017-05-06 23:26:42 -07:00
JonnyWong16
2db3b093b9 Remove blank parameter option 2017-05-06 23:26:26 -07:00
William Comartin
8aa94cc32d Update Filterer, add properties from server to fill in the Filterer 2017-05-07 01:47:00 -04:00
JonnyWong16
2e83b42ba9 Add blank defaults to conditions and parameters 2017-05-06 22:43:49 -07:00
JonnyWong16
42b1a0d3de Pass parameters to notifier config modal 2017-05-06 22:04:24 -07:00
JonnyWong16
9d49a2bd11 Missing bracket in help text 2017-05-05 23:26:09 -07:00
JonnyWong16
f3349c64a9 Add settings for notification conditions filterer 2017-05-05 23:14:11 -07:00
JonnyWong16
565dea5ecf Dynamically build notification parameters 2017-05-05 22:25:06 -07:00
JonnyWong16
2ebe849b8e Allow temporary device token through api 2017-04-30 19:51:53 -07:00
o
1c50e615cf Fixing math used to calculate human_duration
There are 86400 seconds in a day
2017-04-22 19:27:31 -04:00
JonnyWong16
ed2d34e979 v1.4.18 2017-04-22 15:57:43 -07:00
JonnyWong16
c404016700 Merge pull request #1020 from senepa/dev
A correction and additional Arnold quotes
2017-04-22 15:44:26 -07:00
o
14b0353ba4 A correction and additional Arnold quotes
Correction:
True Lies (1994)
'Can you hurry up. My horse is getting tired.' to 'Make it quick because my horse is getting tired.'
http://www.imdb.com/title/tt0111503/quotes?item=qt0408883

Additions:
Last Action Hero (1993)
'Well, listen to this one: Rubber baby buggy bumpers!'
http://www.imdb.com/title/tt0107362/quotes?item=qt1196411

Kindergarten Cop (1990)
'Take your toy back to the carpet!'
http://www.imdb.com/title/tt0099938/quotes?item=qt0460013

Kindergarten Cop (1990)
'My name is John Kimble... And I love my car.'
http://www.imdb.com/title/tt0099938/quotes?item=qt0460001

Commando (1985)
'I eat Green Berets for breakfast.'
http://www.imdb.com/title/tt0088944/quotes?item=qt0402329

Jingle All the Way (1996)
'Put that cookie down. NOW!'
http://www.imdb.com/title/tt0116705/quotes?item=qt0266218
2017-04-22 18:40:21 -04:00
JonnyWong16
fbe136a350 Fix datatables footer text wrapping 2017-04-22 13:43:45 -07:00
JonnyWong16
4fcfea943e Add badges to readme 2017-04-22 13:35:22 -07:00
JonnyWong16
279d27d081 Update PayPal donation link 2017-04-22 13:32:36 -07:00
JonnyWong16
84bfe99017 Download config and database from the settings 2017-04-22 13:23:16 -07:00
JonnyWong16
7c0c7eea30 Remove global logging toggles 2017-04-22 12:44:46 -07:00
JonnyWong16
77b0f69b0c Catch notification thread exception 2017-04-22 11:14:53 -07:00
JonnyWong16
e71e588a91 Fix crash if session is missing stream_video_bitrate 2017-04-20 23:28:11 -07:00
JonnyWong16
beb8df9dda Add thumbnails to notification options 2017-04-19 22:09:39 -07:00
JonnyWong16
014cac7789 Add thumb to android notification 2017-04-19 22:04:02 -07:00
JonnyWong16
41caaa7730 Fixed width icon in notification logs table 2017-04-19 22:03:42 -07:00
JonnyWong16
997e2cdfd8 Encrypt notification with device token instead of api key 2017-04-19 20:21:10 -07:00
JonnyWong16
a939d1bfd8 Fix notify_log success column name 2017-04-19 19:59:59 -07:00
JonnyWong16
59f12c71a9 Manual merge v2 notifications encryption 2017-04-19 19:58:39 -07:00
JonnyWong16
0528ce983f Send notification ID to the android app 2017-04-19 19:52:01 -07:00
JonnyWong16
f2f28f48cb Log test notifications 2017-04-19 19:43:22 -07:00
JonnyWong16
006e7c214d Add notification success to database 2017-04-19 19:32:35 -07:00
JonnyWong16
fc37a8afa3 Switch to SHA1 and remove gcm_tag 2017-04-19 09:49:13 -07:00
JonnyWong16
c2243320ec Log API error message 2017-04-14 17:26:20 -07:00
JonnyWong16
f5969f271a Remove global notification toggles 2017-04-10 21:14:26 -07:00
JonnyWong16
c7063b5973 Improve Facebook auth polling 2017-04-02 12:20:14 -07:00
JonnyWong16
23e0379beb Fallback to parent poster for Imgur upload 2017-04-02 11:01:47 -07:00
JonnyWong16
08619244f0 Generate a unique token for each mobile device 2017-03-31 21:02:09 -07:00
JonnyWong16
5029b19d37 Add note about https for QR scan 2017-03-31 18:14:48 -07:00
JonnyWong16
4bdf520bce Check device is registered before sending notification 2017-03-31 18:14:32 -07:00
JonnyWong16
0a493b9349 Fix to make queries safe 2017-03-31 09:37:22 -07:00
JonnyWong16
a612de52f9 Forgot missing comma 2017-03-31 09:11:48 -07:00
JonnyWong16
a85d4a678d Check git remote branch before splitting 2017-03-30 19:36:38 -07:00
JonnyWong16
08fdcac240 Fix OSX notifier agent id key 2017-03-30 19:34:37 -07:00
JonnyWong16
40060255ee Add automatic Android app QR scan verification 2017-03-30 19:25:45 -07:00
JonnyWong16
d2da193978 Combine android app config notes 2017-03-30 18:14:28 -07:00
JonnyWong16
441c56854d Add android app notification priority option 2017-03-29 22:32:56 -07:00
JonnyWong16
e6023a4702 Add notification encryption warning message 2017-03-29 22:32:35 -07:00
JonnyWong16
d031d74bc6 Check for pycryptodome library on import 2017-03-29 21:24:40 -07:00
JonnyWong16
2952d1360a Update .gitignore for certs only in root directory 2017-03-29 20:03:03 -07:00
JonnyWong16
301ef85e89 Encrypt OneSignal notifications 2017-03-29 20:02:48 -07:00
JonnyWong16
ddf671abd1 Add ability to unregister mobile devices 2017-03-28 21:44:18 -07:00
JonnyWong16
f60c978d80 Fix bc5ce52 2017-03-28 10:09:55 -07:00
JonnyWong16
42a895b095 Change Pushy to OneSignal for push notifications 2017-03-28 09:38:03 -07:00
JonnyWong16
c405f04e9c Fix Pushy device token and add logging 2017-03-27 21:12:39 -07:00
JonnyWong16
bc5ce52236 Fix 50969c2 2017-03-27 21:05:46 -07:00
JonnyWong16
896922de4f Update Android app device registration 2017-03-27 20:50:00 -07:00
JonnyWong16
203a6d47b4 Fix track metadata 2017-03-27 11:34:54 -07:00
JonnyWong16
8e13e2deb2 Add device token to android app notifier config 2017-03-25 23:39:32 -07:00
JonnyWong16
d18c2ffddb Add register android app for push notifications 2017-03-25 23:13:35 -07:00
JonnyWong16
50969c24cc Temporary fix for show/season media info tables 2017-03-25 23:12:23 -07:00
JonnyWong16
f3070763fa Fix some stream info overrides 2017-03-25 13:25:45 -07:00
JonnyWong16
ca093875b4 Don't uppercase TrueHD 2017-03-25 12:28:32 -07:00
JonnyWong16
f77e061ff1 Catch notifier config error 2017-03-25 12:17:04 -07:00
JonnyWong16
0df1bd137d Fix splitting of script arguments 2017-03-25 11:58:37 -07:00
JonnyWong16
651125ef2c Merge pull request #999 from Hellowlol/patch-1
Add missing CONFIG for API get_apikey
2017-03-21 08:12:38 -07:00
Hellowlol
a5eb0e7faa Add missing CONFIG 2017-03-21 15:35:03 +01:00
JonnyWong16
3513f7fe2c Add banner to metadata 2017-03-15 09:01:39 -07:00
JonnyWong16
d845b3f7b0 Add user rating to metadata 2017-03-15 08:36:45 -07:00
JonnyWong16
9318c4742d Manual merge of v1.4.17 into v2 2017-03-04 16:02:37 -08:00
JonnyWong16
e85cdd5609 v1.4.17 2017-03-04 15:55:45 -08:00
JonnyWong16
83f80b9288 Fix month capitalization 2017-03-04 15:49:36 -08:00
JonnyWong16
76fe771d8c Update init scripts 2017-03-04 15:42:03 -08:00
JonnyWong16
c6ad09fe8f Cleanup graphs PRs 2017-03-04 15:33:45 -08:00
JonnyWong16
a3014638c8 Merge pull request #953 from ampsonic/patch-1
Update init.ubuntu.systemd
2017-03-04 15:19:00 -08:00
JonnyWong16
8b15c63b0d Merge pull request #982 from Pbaboe/StartDayofWeek
Start day of the week changeable
2017-03-04 15:02:57 -08:00
JonnyWong16
589adf4df9 Merge pull request #980 from Pbaboe/MonthlyGraphs
Change amount of months in Graphs > Play Totals > Plays by Month
2017-03-04 15:00:24 -08:00
JonnyWong16
b07d85f233 Merge pull request #975 from demonbane/dev
Fix 404s for icon files and invalid paths
2017-03-04 14:53:23 -08:00
JonnyWong16
f0e5855a8e Update bitcoin donation link 2017-03-04 14:47:30 -08:00
JonnyWong16
5997aa5cd9 Fix Plex Web 3.0 urls 2017-03-04 14:47:22 -08:00
JonnyWong16
8a2696adf7 Fix edit friendly name on user page 2017-03-04 10:05:29 -08:00
JonnyWong16
fd1bd7f215 Improve quality profile logic 2017-03-03 18:15:14 -08:00
JonnyWong16
74876ea3c9 Fix transcode decision 2017-03-03 17:44:20 -08:00
JonnyWong16
f6fc142c47 Add Rotten Tomatoes rating 2017-03-03 17:21:52 -08:00
JonnyWong16
78fd83746e Add subtitle direct stream to activity 2017-03-03 16:56:07 -08:00
JonnyWong16
2794a4b550 Add audio channel substitutions 2017-03-02 22:14:23 -08:00
JonnyWong16
7244b15821 Fix link to Plex Web 3.0 in notifications 2017-03-02 18:06:25 -08:00
JonnyWong16
45a1c119ac Rewrite imgur url to https 2017-03-02 18:02:10 -08:00
JonnyWong16
82b42f92a9 Add session throttled key for backwards compatibility
* And fix check for optimized version
2017-03-02 18:01:59 -08:00
JonnyWong16
c4fc831968 Fix refresh of burn subtitle info 2017-03-01 20:52:30 -08:00
JonnyWong16
83c1ca195f Testing more detailed activity pane 2017-02-28 22:27:07 -08:00
JonnyWong16
3166b91cb7 Always show notifier ID on notification agents table 2017-02-28 20:59:25 -08:00
JonnyWong16
914e3a3988 Check use bif setting 2017-02-28 20:58:59 -08:00
Peter Kums
cb2a38addc Start day of the week changeable
Option in general settings to change the start day of the week to Monday (instead of the default of Sunday). This is only relevant for the Graph : Play by day of week.

Feathub issue : http://feathub.com/JonnyWong16/plexpy/+15
2017-02-27 19:38:12 +01:00
JonnyWong16
9fee0d711a Fix clip links in history table 2017-02-26 22:29:36 -08:00
JonnyWong16
989ebcd3b7 Media type clip fixes 2017-02-26 16:11:18 -08:00
JonnyWong16
a46b24213b Add more source media parameters 2017-02-26 16:00:32 -08:00
Peter Kums
873f857c82 Store months for Play by Months graph
Store the selected amount of months in the Graphs > Play Totals > Plays by Months graph in the config.ini file.
2017-02-27 00:17:56 +01:00
Peter Kums
b9a22461c1 Change months in Plays by Month graph
Add an option on the Graphs > Play Totals > Plays by Month page to change the amount of months the graph shows data for.
2017-02-26 23:53:24 +01:00
JonnyWong16
c01731ebe9 Fix Plex Web 3.0 link 2017-02-26 09:52:25 -08:00
JonnyWong16
89b837393d Unicode full title 2017-02-26 09:52:04 -08:00
JonnyWong16
cea851d38e Add terminate session to API 2017-02-25 22:53:32 -08:00
JonnyWong16
992f0baf93 Add detailed stream info to notification options 2017-02-25 22:30:47 -08:00
JonnyWong16
e272a0eecc Update session info 2017-02-25 20:32:54 -08:00
JonnyWong16
0c95297659 Reorganize settings 2017-02-25 11:27:59 -08:00
JonnyWong16
628cef11fa Make sure notification threads exit on shutdown 2017-02-25 10:59:51 -08:00
JonnyWong16
2c5d131019 Check if recently added notifications disabled for library 2017-02-25 10:36:28 -08:00
Alex Malinovich
85a02771a7 Fix 404s for icon files and invalid paths 2017-02-21 01:44:12 -08:00
JonnyWong16
67e5c7de2c Change Pushbullet to use Access-Token header 2017-02-11 11:02:21 -08:00
JonnyWong16
00ff9c5736 Strip white characters from notification subject and body 2017-02-07 18:41:31 -08:00
JonnyWong16
ca472ff597 Improved IP address handling (includes IPv6) 2017-02-05 18:55:10 -08:00
JonnyWong16
d875f21647 Move all modals out of body-container 2017-02-03 17:23:20 -08:00
JonnyWong16
403ed7f63f Update media flags bundle 2017-02-03 16:28:05 -08:00
JonnyWong16
3e67177f73 Slack option to use thumbnail 2017-02-02 21:34:51 -08:00
JonnyWong16
e49517ef05 Add a space 2017-02-02 20:40:10 -08:00
JonnyWong16
f44121e2f9 Stacked user/library edit modals 2017-02-02 20:37:44 -08:00
JonnyWong16
de6215a933 Fix for stacked modals 2017-02-02 20:37:34 -08:00
JonnyWong16
876ff65694 Fix wide modal on small screens 2017-02-02 20:35:12 -08:00
JonnyWong16
1c142ef3f4 Add ability to duplicate a notifier 2017-02-02 20:34:27 -08:00
JonnyWong16
bfe5209c05 Fix wording and reordering of notifier configs 2017-02-02 20:23:38 -08:00
JonnyWong16
83ac03578d Trim notifiier text inputs before saving 2017-01-30 19:19:12 -08:00
JonnyWong16
e34472084c Add port to Slack connection when used with Mattermost 2017-01-30 19:18:29 -08:00
JonnyWong16
4dce0ec015 Verify color hex code for Discord and Slack 2017-01-30 19:16:05 -08:00
JonnyWong16
304c2429bb Don't use default subject/body with blank notification text
* Allow different notifications using the media type tags
2017-01-29 17:31:47 -08:00
JonnyWong16
957c7aeab9 Update Discord, Facebook, Hipchat, and Slack info cards
* Add option to hide plot summaries
2017-01-29 17:23:27 -08:00
ampsonic
6a0b0327c3 Update init.ubuntu.systemd
Updated the instructions to more accurately reflect required steps. Removed outdated information and added information on creating the plexpy user. 

Only the comments of the file changed not actual configuration.
2017-01-28 16:42:50 -08:00
JonnyWong16
07a1136839 Clean up PrettyMetadata 2017-01-27 23:24:19 -08:00
JonnyWong16
70f006d06d Update Discord, Slack, and Hipchat cards 2017-01-27 23:12:46 -08:00
JonnyWong16
651f4ebf5f Fix websocket on_created 2017-01-27 23:12:33 -08:00
JonnyWong16
fc7b396e45 Log recently added items to the database
* Temporarily disable recently added upgrade notifications
2017-01-27 20:50:46 -08:00
JonnyWong16
eac31d10f1 Fix some notifier text 2017-01-27 20:49:33 -08:00
JonnyWong16
270d4f510a Add https certificate chain 2017-01-15 11:49:48 -08:00
JonnyWong16
285599cf90 Fix typo 2017-01-15 11:49:27 -08:00
JonnyWong16
01ec812e1c Fix missing recently added notifications 2016-12-06 20:31:18 -08:00
JonnyWong16
9cf51d403a Add link to Discord card 2016-12-06 20:07:28 -08:00
JonnyWong16
dfac33723a Reword QR scanner help text 2016-12-06 18:08:18 -08:00
JonnyWong16
655f1c249e Add show and episode title to get_history API 2016-11-29 20:54:27 -08:00
JonnyWong16
e31e531f9c Fix websocket timeline json 2016-11-25 21:06:43 -08:00
JonnyWong16
d7cef5add7 Manual merge of v1.4.16 into v2 2016-11-25 19:16:43 -08:00
JonnyWong16
3742f33d08 v1.4.16 2016-11-25 18:47:22 -08:00
JonnyWong16
82ac33dd75 Fix websocket for new json response on PMS 1.3.0 2016-11-25 18:42:23 -08:00
JonnyWong16
03eec610fa Add separate settings tab for PlexPy Remote App 2016-11-18 22:39:44 -08:00
JonnyWong16
66191d2ff9 Put QR code in pre block 2016-11-17 23:37:33 -08:00
JonnyWong16
9e64463e70 Add QR code to link PlexPy Remote android app 2016-11-17 23:14:23 -08:00
JonnyWong16
ebf014406d Use fallback text if invalid subject or body 2016-11-14 21:33:37 -08:00
JonnyWong16
8c7c0101cd Dynamically update stream and transcoder tooltip percent 2016-11-14 21:10:48 -08:00
JonnyWong16
4d6179dfdd Fix typo 2016-11-14 20:49:01 -08:00
JonnyWong16
21f6a076cb Don't capitalize video and audio decision 2016-11-11 21:43:00 -08:00
JonnyWong16
bb938d4482 Fix Script test action 2016-11-11 13:54:35 -08:00
JonnyWong16
411e798f8e Rename script configuration tabs 2016-11-11 13:37:39 -08:00
JonnyWong16
0c5fa37d8b Select test script over configured script 2016-11-11 13:37:39 -08:00
JonnyWong16
fd4a2bdb4d Make sure agent is in v1 before upgrading agents 2016-11-11 13:37:39 -08:00
JonnyWong16
38d2345cd2 Option to send recently added notification for new versions 2016-11-11 13:37:38 -08:00
JonnyWong16
cc45ad0b63 Simplify random Arnold quote choice 2016-11-11 13:37:38 -08:00
JonnyWong16
0ab9cdf97c Only preview notification text for valid media types 2016-11-11 13:37:37 -08:00
JonnyWong16
580595e5fa Fix set temporary session stopped time 2016-11-11 13:37:37 -08:00
JonnyWong16
ca573ce73a Make sure parameters have media type for PrettyMetadata 2016-11-11 13:37:37 -08:00
JonnyWong16
c75099decc Fix script timeout 2016-11-11 13:37:36 -08:00
JonnyWong16
d874697eef Add notifier text preview 2016-11-11 13:37:11 -08:00
JonnyWong16
cb5252b8d4 Update Plex Home Theater and XBMC notification agents 2016-11-11 13:37:11 -08:00
JonnyWong16
5f28ead6e9 Make sure to get metadata media info for notification 2016-11-11 13:36:26 -08:00
JonnyWong16
bf99c0e290 Note auto line breaks in email HTML 2016-11-11 13:36:26 -08:00
JonnyWong16
5aaa014207 Option to group recently added by parent or grandparent 2016-11-11 13:36:25 -08:00
JonnyWong16
a13f84fbf6 Only split once for git remote/branch 2016-11-11 13:36:25 -08:00
JonnyWong16
1618921a57 Add notifier configs to logger blacklist 2016-11-11 13:36:25 -08:00
JonnyWong16
864063676f Default http_proxy on and remove setting 2016-11-11 13:36:25 -08:00
JonnyWong16
17649bf36a Catch websocket expection 2016-11-11 13:36:24 -08:00
JonnyWong16
8f22b118be Use default subject and body if blank 2016-11-11 13:36:24 -08:00
JonnyWong16
6f97036446 Enable TTS for Discord 2016-11-11 13:36:24 -08:00
JonnyWong16
ffcde69352 Fix Facebook authorization 2016-11-11 13:36:24 -08:00
JonnyWong16
1520062878 Remove experimental tag for Discord 2016-11-11 13:36:24 -08:00
JonnyWong16
228777963f Script logger error message for unspecified folder 2016-11-11 13:36:23 -08:00
JonnyWong16
08a9b59ca4 Remove 'on_' prefix from notifier actions 2016-11-11 13:36:23 -08:00
JonnyWong16
7da1edfcc5 Change missing image to warning 2016-11-11 13:36:23 -08:00
JonnyWong16
f63b5514f3 Stop capitalizing the action name in notifications 2016-11-11 13:36:23 -08:00
JonnyWong16
486ddb55b2 Change wording 2016-11-11 13:36:23 -08:00
JonnyWong16
6720b44f43 Don't auto close modal when saving notifier config 2016-11-11 13:36:22 -08:00
JonnyWong16
0c7db9c1ee Add attachement colour option for Slack 2016-11-11 13:36:22 -08:00
JonnyWong16
7df455309e Fix poster upload logger message 2016-11-11 13:36:22 -08:00
JonnyWong16
0a4b3f02db Remove api v1 import 2016-11-11 13:36:22 -08:00
JonnyWong16
b8fc6e6b0f A bit of performance improvement 2016-11-11 13:36:22 -08:00
JonnyWong16
39b8f49894 Center restart message 2016-11-11 13:36:22 -08:00
JonnyWong16
c3b5621dda Fix fallback body text 2016-11-11 13:36:21 -08:00
JonnyWong16
5d58d9f5d4 Fix getting user stream count for notifications 2016-11-11 13:36:21 -08:00
JonnyWong16
52a6f639b0 Cleanup activity processor 2016-11-11 13:36:21 -08:00
JonnyWong16
cfcd32a10b Update read changelog for variable headers and list levels 2016-11-11 13:36:21 -08:00
JonnyWong16
9e8d55e0f3 Update notification logs table 2016-11-11 13:36:21 -08:00
JonnyWong16
ed6a42f747 Create a new database table for poster urls 2016-11-11 13:36:20 -08:00
JonnyWong16
ffdd9c9cbf Rework notification logic to only build parameters once per action
* Instead of rebuilding for each notification agent
* Change season/episode to use season poster
* Change album/track to use album art
2016-11-11 13:36:20 -08:00
JonnyWong16
f45bd49421 Comment out Discord TTS 2016-11-11 13:36:20 -08:00
JonnyWong16
e9cfc59400 Add pretty metadata for season and album 2016-11-11 13:36:19 -08:00
JonnyWong16
b98faa0671 Update Slack agent 2016-11-11 13:36:18 -08:00
JonnyWong16
bfb6aee908 Mark Discord as experimental 2016-11-11 13:36:18 -08:00
JonnyWong16
5b6f876ddc Add Discord notification agent 2016-11-11 13:36:16 -08:00
JonnyWong16
6737f45948 Some typos 2016-11-11 13:36:15 -08:00
JonnyWong16
1b42f95643 Alphabetize notification agents 2016-11-11 13:36:15 -08:00
JonnyWong16
b3f43f956e Add delay to check for valid DLNA session 2016-11-11 13:36:15 -08:00
JonnyWong16
abe75c9744 Change git remote/branch textbox width 2016-11-11 13:36:15 -08:00
JonnyWong16
1b1e4639fd Log DLNA platform 2016-11-11 13:36:15 -08:00
JonnyWong16
6d0327f662 Don't nest metadata dict
* Return metadata dict directly
2016-11-11 13:36:14 -08:00
JonnyWong16
19e379f084 Add Git section in settings 2016-11-11 13:35:25 -08:00
JonnyWong16
2f291b167e Add grouped metadata note 2016-11-11 13:35:25 -08:00
JonnyWong16
d47daba8c1 Auto redirect if available before countdown on state change 2016-11-11 13:35:25 -08:00
JonnyWong16
27183483a9 Fix check for media info before parsing xml 2016-11-11 13:32:37 -08:00
JonnyWong16
31b6ff003a Fix Pushover notifications 2016-11-11 13:32:37 -08:00
JonnyWong16
0e58369873 Add media info metadata params for notifications 2016-11-11 13:32:37 -08:00
JonnyWong16
94ddf041aa Fix notifier table column name 2016-11-11 13:32:37 -08:00
JonnyWong16
bca9da3964 Make entire notifier stacked config click to open modal 2016-11-11 13:32:37 -08:00
JonnyWong16
1ca1b5aefa Chnage wording for branch checkout warning message 2016-11-11 13:32:36 -08:00
JonnyWong16
9eec985fb9 Move git remote/branch to extra settings 2016-11-11 13:32:36 -08:00
JonnyWong16
d1551bd8c7 Add option to switch the git remote and branch 2016-11-11 13:32:36 -08:00
JonnyWong16
91716527a4 Option to update PlexPy automatically 2016-11-11 13:32:36 -08:00
JonnyWong16
83c304290b Add PlexPy update notifications 2016-11-11 13:32:35 -08:00
JonnyWong16
5ee986593c Disable check server response when websocket connected 2016-11-11 13:31:23 -08:00
JonnyWong16
7187aff1a6 Minor notifier fixes
* Email replace \n with <br>
* Slack and Hipchat help text wording
2016-11-11 13:31:23 -08:00
JonnyWong16
44f39e7fea Actually set notifier config when sending notifications 2016-11-11 13:31:22 -08:00
JonnyWong16
f42d7b0da0 Remove old templates 2016-11-11 13:31:22 -08:00
JonnyWong16
50941055fb Automatically show config modal when adding a new notifier 2016-11-11 13:31:22 -08:00
JonnyWong16
a361296930 Make changelog and notifier config modal wider 2016-11-11 13:31:22 -08:00
JonnyWong16
61507c03a0 Add get_pms_update to the API 2016-11-11 13:31:22 -08:00
JonnyWong16
8595fb97ce Fix bell tooltip on the notifiers table 2016-11-11 13:31:21 -08:00
JonnyWong16
7a37408459 Add advanced config for number of notification threads 2016-11-11 13:31:21 -08:00
JonnyWong16
303ccce8b4 Some more cleanup 2016-11-11 13:31:21 -08:00
JonnyWong16
d8cc76c7d7 Set temporary session stop times on websocket disconnect 2016-11-11 13:31:21 -08:00
JonnyWong16
fd35295093 Remove unused settings 2016-11-11 13:31:21 -08:00
JonnyWong16
72764c614e Add logger message 2016-11-11 13:31:20 -08:00
JonnyWong16
b8106186fb Add advanced setting for remote access ping threshold 2016-11-11 13:31:20 -08:00
JonnyWong16
eb3c189ab6 Rework task scheduler for websocket only 2016-11-11 13:31:20 -08:00
JonnyWong16
16c7d27508 Default to websocket connection
* No polling failover
2016-11-11 13:31:20 -08:00
JonnyWong16
be50ecd033 Default True for no data notifications 2016-11-11 13:31:20 -08:00
JonnyWong16
4170ed55a6 Cleanup recently_added_grandparent javascript in settings 2016-11-11 13:31:19 -08:00
JonnyWong16
31c9ecaf44 Clean up timeline state 2016-11-11 13:31:19 -08:00
JonnyWong16
e1bd5ed49e Add grouped notification params 2016-11-11 13:31:19 -08:00
JonnyWong16
d97cacff14 More intelligent grouping of recently added
* Websocket only
2016-11-11 13:31:19 -08:00
JonnyWong16
8ed2f0eafa Another attempt at using websockets for recently added 2016-11-11 13:31:19 -08:00
JonnyWong16
438e525319 Add user_id to session started log message 2016-11-11 13:31:18 -08:00
JonnyWong16
2a2237f542 Check concurrent streams by API instead of database 2016-11-11 13:31:18 -08:00
JonnyWong16
06db6826ed Check media_type in params when building notification text 2016-11-11 13:31:18 -08:00
JonnyWong16
08a8b5fee0 Multithreaded notification queue 2016-11-11 13:31:18 -08:00
JonnyWong16
82f4c99025 Check on_watched condition before adding to queue 2016-11-11 13:31:18 -08:00
JonnyWong16
7b2a7aff9f Update notification handler for all notification triggers 2016-11-11 13:31:18 -08:00
JonnyWong16
1206d13978 Add notifier id to config modal 2016-11-11 13:31:17 -08:00
JonnyWong16
8bdf1af021 Add previously configured notification agents to the new system 2016-11-11 13:30:52 -08:00
JonnyWong16
f0595b8b0a Add new notification system 2016-11-11 13:30:52 -08:00
JonnyWong16
258ec197d7 Uniform logger 2016-11-11 13:28:18 -08:00
JonnyWong16
7d3711bf5a Add last_insert_id module to database 2016-11-11 13:28:18 -08:00
JonnyWong16
8925a0dc78 Remove API v1 2016-11-11 13:28:18 -08:00
JonnyWong16
38ccd26b96 Allow data to be passed for confirmAjaxCall 2016-11-11 13:28:18 -08:00
JonnyWong16
7e8fddc50c Make sure confirm modal is above other modals 2016-11-11 13:28:17 -08:00
JonnyWong16
bc1452d1d0 Remove old current activity template 2016-11-11 13:28:17 -08:00
JonnyWong16
d285107cfb Remove shared Imgur client ID 2016-11-11 13:28:17 -08:00
JonnyWong16
354700fcbb Show changelog on update 2016-11-11 13:28:17 -08:00
JonnyWong16
ef85fba2e5 v1.4.15 2016-11-11 13:08:13 -08:00
JonnyWong16
960b601384 Remove error cmd from API 2016-11-11 12:59:35 -08:00
JonnyWong16
21d9091b43 Merge pull request #898 from Hellowlol/ap_fix
fix result type, fixup responses from the ui to api
2016-11-11 12:48:18 -08:00
Hellowlol
e881c32797 Update md add exception traceback to the browser 2016-11-05 22:24:37 +01:00
JonnyWong16
57f1af05f5 Redirect to proper HTTP root on state change 2016-11-05 12:13:53 -07:00
JonnyWong16
254f41a2cc Fix line breaks in info page summaries 2016-11-05 11:50:41 -07:00
JonnyWong16
59ce3404c9 Fix Plex.tv authentication with special characters 2016-11-05 11:48:53 -07:00
Hellowlol
11c7342299 fix result type, fixup responses from the ui to api
todo unify json responses from webserve.py
2016-11-04 00:52:01 +01:00
JonnyWong16
8b0959aa69 Fix API SQL command 2016-10-28 20:35:39 -07:00
JonnyWong16
9cd8ed12b9 Add percent to stream and transcoder progress tooltip 2016-10-28 20:34:54 -07:00
JonnyWong16
78b10d7ab5 Use HTTPS for app.plex.tv 2016-10-21 22:45:17 -07:00
JonnyWong16
a322ec2b23 Allow refreshing images if not using sessions 2016-10-16 13:08:36 -07:00
JonnyWong16
1f23654735 Merge pull request #870 from XusBadia/patch-2
Incremented table width to 100%
2016-10-13 21:52:49 -07:00
Xus Badia
e1112b95c7 Changed max-width to accommodate wider displays 2016-10-14 06:11:50 +02:00
JonnyWong16
4e043109bf Temporary fix for info pages with missing metadata
* Will be fixed properly in v2
2016-10-13 20:42:11 -07:00
Xus Badia
58e670443d Incremented table width to 100%
Table width (header and body/back) incremented to 100% but adding max-width so it isn't too wide in wide-screen monitors.
2016-10-13 11:56:02 +02:00
JonnyWong16
86a9230da8 v1.4.14 2016-10-12 21:06:34 -07:00
JonnyWong16
86f84766c1 Allow disable script timeout 2016-10-12 21:00:52 -07:00
JonnyWong16
fdc7078e5c API key readonly instead of disabled 2016-10-12 20:55:32 -07:00
JonnyWong16
c649ebfcc0 Fix typo under Flush Temporary Sessions 2016-10-10 22:47:41 -07:00
JonnyWong16
6aa0d4cd0b Check for metadata before attempting to write session history 2016-10-10 22:46:48 -07:00
JonnyWong16
1a2e205c1f v1.4.13 2016-10-08 23:42:18 -07:00
JonnyWong16
5dd04cb8ab Temporarily set stopped time when connection is lost 2016-10-08 22:56:43 -07:00
JonnyWong16
62d05e5e08 Add supplementary URL option to Pushover 2016-10-08 22:45:16 -07:00
JonnyWong16
1c087ec856 Add backup days option 2016-10-08 22:29:30 -07:00
JonnyWong16
010c12da67 Use human file size in table 2016-10-03 21:36:02 -07:00
JonnyWong16
9bdac38561 Merge pull request #859 from logaritmisk/human-file-size
Human file size for media info table
2016-10-03 21:30:26 -07:00
logaritmisk
790ca9c90a Human file size for media info table. 2016-10-03 22:27:21 +02:00
JonnyWong16
58f72d2d9c Merge pull request #856 from Hellowlol/imgfix
fix for image proxy for api.
2016-10-02 12:09:33 -07:00
Hellowlol
285e6513ed fix for image proxy for api. 2016-10-02 20:38:51 +02:00
JonnyWong16
412bc8cf2d Move watched percent to General settings 2016-09-30 19:38:20 -07:00
JonnyWong16
45cd8b8a00 Cleanup kill script 2016-09-30 00:35:31 -07:00
JonnyWong16
ae2227959e Fix 0b10e68 2016-09-29 23:35:33 -07:00
JonnyWong16
b50c92f919 Rename get_log 2016-09-29 23:31:33 -07:00
JonnyWong16
93a1d9c164 Run script in a new thread with timeout
* Also fixes script output not sent to logger
2016-09-29 23:31:15 -07:00
JonnyWong16
0b10e68c60 Force refresh Plex.tv token in settings
* Removes the old PlexPy device and fetches a new token
2016-09-29 21:21:07 -07:00
JonnyWong16
73ac4076ac Disable manual changing of API key 2016-09-29 18:51:35 -07:00
JonnyWong16
5968b82a0b Add pms_image_proxy to api 2016-09-27 22:20:10 -07:00
JonnyWong16
ce1d2a0fd9 Fix success message show incorrectly when sending test notification
* Due to saving the settings before sending the notification
2016-09-27 21:48:09 -07:00
JonnyWong16
de3f813b46 Add flush temporary sessions button in settings 2016-09-27 21:47:12 -07:00
JonnyWong16
4797b1a3b7 Add new librarys to homepage automatically 2016-09-26 22:20:44 -07:00
JonnyWong16
3e996d284d Disable posters by default for all notification agents 2016-09-25 22:05:02 -07:00
JonnyWong16
420c5a0836 Fix Browser config section 2016-09-25 22:04:25 -07:00
JonnyWong16
c6b953055a Fix admin username not shown in login logs 2016-09-24 19:37:09 -07:00
JonnyWong16
1cd0c112a6 Fix PlexPy log level filter 2016-09-24 19:29:26 -07:00
JonnyWong16
492d28ea37 Update pytz library 2016-09-19 21:48:14 -07:00
JonnyWong16
4eb7e03b67 Update Readme 2016-09-19 19:08:26 -07:00
JonnyWong16
e029f329eb Merge branch 'dev' 2016-09-18 22:11:29 -07:00
JonnyWong16
47de9a752c v1.4.12 2016-09-18 22:11:12 -07:00
JonnyWong16
51c9aa2887 Update FreeBSD service script 2016-09-18 21:58:44 -07:00
JonnyWong16
82499a53d4 Merge pull request #844 from spolyack/pid-fix
Attempt to verify the PID in an existing PID file before giving up.
2016-09-18 21:33:11 -07:00
JonnyWong16
df15302f2c Merge pull request #842 from XusBadia/patch-2
Fix card width on the homepage for iPhone 6/7 Plus
2016-09-18 21:11:24 -07:00
JonnyWong16
039b51262d Update readme 2016-09-18 21:06:44 -07:00
spolyack
465add46d4 Attempt to verify the PID in an existing PID file before giving up.
If the PID doesn't map to a running process, then we can simply ignore the presence of the PID file and overwrite it with the current (new) PID later.
2016-09-18 11:36:09 -04:00
Xus Badia
bce965b402 Fix for iPhone 6/7 Plus
Changed the max-device-width from 400px to 450px so it adjusts to the iPhone 6/7 Plus screen and doesn't leave a gap on the right of the screen.
2016-09-18 07:41:58 +02:00
JonnyWong16
95ce293169 Add FAQ link to dropdown 2016-09-17 15:15:33 -07:00
JonnyWong16
5d604c2cad Make sure all endpoints have kwargs 2016-09-17 14:45:58 -07:00
JonnyWong16
ed2d3ca277 Update git user 2016-09-17 14:40:31 -07:00
JonnyWong16
0478f40d02 Square cover for music home stats 2016-09-17 14:39:58 -07:00
JonnyWong16
a4be73da3b Remove divider 2016-09-17 14:39:38 -07:00
JonnyWong16
762192518f Override MacOSX pms platform 2016-09-03 13:57:17 -07:00
JonnyWong16
fa51df192d Cleanup settings modal text 2016-09-02 13:18:06 -07:00
JonnyWong16
1a5cc02097 Update with support links 2016-09-02 13:01:12 -07:00
JonnyWong16
a07f54ca33 Merge branch 'dev' 2016-09-02 11:51:51 -07:00
JonnyWong16
6a8cbe92a9 v1.4.11 2016-09-02 11:51:26 -07:00
JonnyWong16
16d9376ec9 Add /r/Plex Discord to Readme 2016-09-02 11:48:36 -07:00
JonnyWong16
4356f5c72a Remove unnecessary argument 2016-09-02 10:54:20 -07:00
JonnyWong16
076dc94292 A bit of script notifier cleanup 2016-08-26 19:16:48 -07:00
JonnyWong16
fbc527010a Fix notifications not sending for Local user
Fixes #807
2016-08-26 18:48:09 -07:00
JonnyWong16
5b4a22276d Fix args in the correct order for datatables queries
Fixes #813
2016-08-26 18:14:26 -07:00
JonnyWong16
b55a563fce Fix PlexWatch and Plexivity import 2016-08-26 17:43:10 -07:00
JonnyWong16
2a701a6dfe Merge branch 'dev' 2016-08-15 08:40:16 -07:00
JonnyWong16
8931fb4758 v1.4.10 2016-08-15 08:39:29 -07:00
JonnyWong16
2124165319 Add missing ipaddress module 2016-08-15 08:39:18 -07:00
JonnyWong16
0d701129a0 Merge branch 'dev' 2016-08-14 19:50:24 -07:00
JonnyWong16
ebd8625e1e v1.4.9 2016-08-14 19:50:00 -07:00
JonnyWong16
b68ca67386 Add option to include current activity in the history tables 2016-08-14 19:40:47 -07:00
JonnyWong16
17a7019c60 Clean up datatable query with union table 2016-08-14 19:40:23 -07:00
JonnyWong16
54af92251c Nicer y-axis intervals for duration graphs 2016-08-06 15:52:44 -07:00
JonnyWong16
d9edeb747d Fix ambiguous user_id column name in user login table query 2016-08-04 23:34:56 -07:00
JonnyWong16
b69b722a37 Fix deprecated BaseException.message 2016-08-04 23:34:11 -07:00
JonnyWong16
669c23ea09 Add current activity to the history table
* Needs serious testing.
* Very hacky SQLite query.
2016-08-04 23:25:12 -07:00
JonnyWong16
2b3ba8e7fa Add some metadata to the sessions table 2016-08-04 23:24:29 -07:00
JonnyWong16
9a761e7d30 Add preview to README.md 2016-08-01 17:45:03 -07:00
JonnyWong16
9d00e052f0 Add ratingKey to session start log message 2016-08-01 09:28:39 -07:00
JonnyWong16
7c159e97de Add Host to IP lookup 2016-07-31 21:14:48 -07:00
JonnyWong16
ba8e4ff33c Async ISP lookup 2016-07-31 17:51:40 -07:00
JonnyWong16
9b067a437c Return bool for Twitter and Facebook notify 2016-07-31 15:25:08 -07:00
JonnyWong16
aba39d06bf Lookup IP address ISP info 2016-07-31 11:10:26 -07:00
JonnyWong16
469d22a833 Add ipwhois library + dependencies 2016-07-31 11:05:42 -07:00
JonnyWong16
43bd49ce5b Change wording "updating" to "retrieving" 2016-07-26 21:29:09 -07:00
JonnyWong16
79dc190ccc Compare distro and build for pms updates 2016-07-26 19:11:56 -07:00
JonnyWong16
495659e9cd Update server version before checking for server updates 2016-07-26 19:11:56 -07:00
JonnyWong16
2fec2c9e4c Merge pull request #796 from wopian/patch-2
Fix 'Authentication' typo in setup wizard
2016-07-26 12:59:53 -07:00
James Harris
9cba66634d Fix 'Authentication' typo in setup wizard 2016-07-26 20:48:50 +01:00
JonnyWong16
b2f63bf231 Fix progress bar max width 100% 2016-07-24 10:22:02 -07:00
JonnyWong16
9c9ef22730 Add option to disable web page preview for Telegram 2016-07-21 19:51:41 -07:00
JonnyWong16
5d84ec3be2 Send correct json header for Slack/Mattermost 2016-07-20 18:04:56 -07:00
JonnyWong16
2150961d27 Merge branch 'dev' 2016-07-16 14:58:28 -07:00
JonnyWong16
53bca5a3d3 v1.4.8 2016-07-16 14:58:03 -07:00
JonnyWong16
cd3938eb33 Set checked value for notify by concurrent IP address 2016-07-16 11:22:38 -07:00
JonnyWong16
eb0b88bfcf Cleanup scheduler 2016-07-16 10:23:30 -07:00
JonnyWong16
b9bbf8bbca Option to specify backup interval 2016-07-15 22:51:11 -07:00
JonnyWong16
65b3d0c0de Better version comparisons 2016-07-15 22:43:36 -07:00
JonnyWong16
93b8f32f68 Use library refresh interval 2016-07-15 18:54:11 -07:00
JonnyWong16
28bb164e8e Auto log IP message in settings 2016-07-15 18:54:11 -07:00
JonnyWong16
4911cc76a3 Substitute {update_version} in fallback notification 2016-07-15 09:44:06 -07:00
JonnyWong16
26ac539bc4 Merge branch 'dev' 2016-07-14 21:24:36 -07:00
JonnyWong16
75ae6b16a4 v1.4.7 2016-07-14 21:21:59 -07:00
JonnyWong16
2835b1d28f Don't notify for Telegram poster, notify for message only 2016-07-14 18:51:24 -07:00
JonnyWong16
748aad16d7 Update formatting for Slack poster notifications 2016-07-13 21:30:01 -07:00
JonnyWong16
2c2fbb8583 Host Open Sans font locally instead of querying Google Fonts 2016-07-13 21:05:44 -07:00
JonnyWong16
20edcbf7fa Only get user stream count for session notifications 2016-07-13 20:28:02 -07:00
JonnyWong16
db81dc39ba Remove Browser notifications experimental tag 2016-07-13 20:25:41 -07:00
JonnyWong16
c3b0aef1ef Parse Slack hostname
* Allow Mattermost notifications using Slack config
2016-07-13 20:25:13 -07:00
JonnyWong16
50e29efdfe Line break between subject line and message instead of colon
* For Facebook, Twitter, Telegram, Slack
2016-07-13 20:17:23 -07:00
JonnyWong16
285e41bc88 Merge pull request #779 from aboron/dev
Adds posters option for Hipchat and metadata formatting functions.
2016-07-13 20:08:36 -07:00
aboron
ea9d0fc449 Consolidate redundant subject options.
Fix emoticon handling for html cards.
Fix cut/paste CONFIG errors.
2016-07-13 22:54:56 -04:00
greg.gaskill
9cdd2eef81 Randomize Hipchat card 'id' value. 2016-07-13 12:33:39 -04:00
greg.gaskill
2f8833236a Actually use self.media_type.
Set default divider for tv shows to '-'.
2016-07-13 12:14:58 -04:00
greg.gaskill
2b680eeb6d Finished metadata class.
Finished Hipchat graphical poster notifications.
2016-07-13 10:59:32 -04:00
greg.gaskill
809f120db0 Refactored PrettyMetadata class.
Trying basic Hipchat poster without links (unfortunately not allowed to use <div>s).
2016-07-12 17:13:54 -04:00
greg.gaskill
6d9ef8bbc3 Combine repeated metadata formatting functions in one place. 2016-07-12 14:33:04 -04:00
JonnyWong16
a26d6ec6bb Make search message clearer 2016-07-09 21:15:40 -07:00
JonnyWong16
2d26ced3fc A bit of HipChat cleanup 2016-07-08 19:38:17 -07:00
JonnyWong16
d74cd4bf24 Merge pull request #773 from aboron/dev
Added Hipchat integration notifier.
2016-07-08 19:30:08 -07:00
aboron
f040d897a7 Modified message color default behavior. 2016-07-08 16:24:26 -04:00
aboron
ed2f87f57b Added all available color options into a selection list. 2016-07-08 15:45:43 -04:00
aboron
9b9e31f54c Improved configuration help text wording. 2016-07-08 11:44:14 -04:00
aboron
b3cfcf660e Changed Hipchat emoticon checkbox to user definable string, since (plex) was a custom user emoticon. 2016-07-08 11:37:49 -04:00
aboron
e5bcd1f94e Made notification subject optional per single-line standard.
Added option to include custom (plex) emoticon at the beginning of each notification.  (Feature only relevant to Hipchat.)
2016-07-08 09:36:45 -04:00
aboron
2b6fa769f7 Added Hipchat integration notifier. 2016-07-07 15:09:48 -04:00
JonnyWong16
3ccc82f343 Add notification for user streaming from a new device 2016-07-05 21:30:47 -07:00
JonnyWong16
f4273cafb6 Add missing concurrent notifications for tracks 2016-07-05 20:59:07 -07:00
JonnyWong16
59d63f61d9 Add missing concurrent notification to OSX notify 2016-07-05 20:55:11 -07:00
JonnyWong16
9d9103a83b Add missing user concurrent stream script 2016-07-05 20:48:11 -07:00
JonnyWong16
0b085b6d03 Notifications for user concurrent streams 2016-07-04 22:47:59 -07:00
JonnyWong16
f77538f179 Fix guidelines modal for separated configuration table 2016-07-02 16:05:57 -07:00
JonnyWong16
f7810f7f95 Reword GeoLite2 install confirmation message 2016-07-02 16:05:37 -07:00
JonnyWong16
4d28e4603f Respect custom GeoLite2 path on reinstalling database 2016-07-01 10:16:24 -07:00
JonnyWong16
8b787e4ae0 Add option to uninstall the GeoLite2 database 2016-07-01 09:33:13 -07:00
JonnyWong16
f5ba168172 Format geoip error messages 2016-07-01 09:30:31 -07:00
JonnyWong16
1df6dadbdd Fix typo 2016-07-01 09:12:06 -07:00
JonnyWong16
3dc29144a3 Add some more IP address info 2016-07-01 09:00:01 -07:00
JonnyWong16
951167ce17 Include ipaddress module 2016-07-01 08:34:13 -07:00
JonnyWong16
906e4055d8 Add geoip lookup to API 2016-06-30 22:27:36 -07:00
JonnyWong16
2f5526388a Move configuration table to separate file 2016-06-30 22:02:38 -07:00
JonnyWong16
82341642f4 Missing GeoLite2 database message link to settings page 2016-06-30 22:02:17 -07:00
JonnyWong16
c96b1eb09d IP address lookup using MaxMind GeoLite2 database 2016-06-30 21:19:54 -07:00
JonnyWong16
f5bfa67c69 Formatting on stream info modal 2016-06-30 21:15:56 -07:00
JonnyWong16
47797ffcd4 Join notification subject line optional 2016-06-27 20:33:12 -07:00
JonnyWong16
a73053e380 Check for valid server versions before comparing version numbers 2016-06-26 21:00:40 -07:00
JonnyWong16
bc042fead7 Fix processed/grouped table selection in database import tool 2016-06-26 10:20:07 -07:00
JonnyWong16
ed6779e937 Fix #765 2016-06-26 09:10:38 -07:00
JonnyWong16
ee7ca68f87 Don't filter PMS version in the logger 2016-06-25 18:41:49 -07:00
JonnyWong16
32693b6378 Add notification options for pmsupdate 2016-06-25 18:41:33 -07:00
JonnyWong16
984e5588c8 Use Plex downloads to check for PMS updates instead of server API
* Check for PMS updates has been disabled and must be re-enabled in the
settings
2016-06-25 18:41:18 -07:00
JonnyWong16
a42a1af867 Update stream info on current activity refresh 2016-06-21 00:01:41 -07:00
JonnyWong16
03de680915 Don't allow guests to refresh poster images 2016-06-20 23:28:45 -07:00
JonnyWong16
8c6e142314 Hide poster refresh icon in guest mode 2016-06-20 19:09:02 -07:00
JonnyWong16
b12bde4f79 Fix apostrophe in Arnold quote 2016-06-19 23:31:52 -07:00
JonnyWong16
1120aa3841 Fix direct stream count in current activity header 2016-06-18 16:36:13 -07:00
JonnyWong16
652ca73126 Make "Enable Posters in Notifications" a global toggle 2016-06-18 09:33:37 -07:00
JonnyWong16
8706e72f6a Make sure fallback to username if friendly name is blank 2016-06-14 20:49:27 -07:00
JonnyWong16
319d521773 Update Facebook instructions 2016-06-14 18:47:14 -07:00
JonnyWong16
d9474cdcc5 Merge branch 'dev' 2016-06-11 11:40:24 -07:00
JonnyWong16
e49a34177a v1.4.6 2016-06-11 11:40:03 -07:00
JonnyWong16
67d203e011 Catch exception and attempt to reconnect websocket 2016-06-11 11:26:52 -07:00
JonnyWong16
0d38b3de16 Catch json parse error for current activity 2016-06-06 00:28:01 -07:00
JonnyWong16
38116a14f3 Fix double clear search button 2016-06-05 11:23:12 -07:00
JonnyWong16
b28f0b65f0 Add download logs button for Plex logs 2016-06-05 11:18:23 -07:00
JonnyWong16
13ab4a9363 Add log level filter to PlexPy logs 2016-06-05 11:17:58 -07:00
JonnyWong16
7cb7783a34 Make sure there is a date before trying to format it 2016-06-05 11:05:17 -07:00
JonnyWong16
d1a13dad38 Merge pull request #729 from sanderploegsma/feature/plex-log-level-filter
Add log level filter for plex server and media logs
2016-06-05 09:30:57 -07:00
JonnyWong16
b4e06dea99 Add some date options for notifications 2016-06-04 22:30:41 -07:00
JonnyWong16
0f92dc0fdf Add refresh button to images 2016-06-04 12:43:45 -07:00
JonnyWong16
6a58895d37 Reflect path suggested in installation guide (FreeNAS) 2016-06-04 08:48:58 -07:00
JonnyWong16
1709a2b7df Merge pull request #741 from Hellowlol/cachefix
Allow refresh of images
2016-06-04 08:43:51 -07:00
JonnyWong16
febb3da0c1 Merge pull request #735 from nortron/fix_freebsd_daemon_template_default_path
Reflect path suggested in installation guide (FreeBSD)
2016-06-04 08:43:29 -07:00
Hellowlol
552a428985 allow refresh of images
Allow refresh of images and fix bug where a disabled cache still would
use the cache
2016-06-02 17:27:23 +02:00
Tim Van
38e04bd42a Allow global config setting for PMS log window size. 2016-05-30 15:59:01 +02:00
JonnyWong16
8f0ba5ba4f Add notification agent ids to the API docs 2016-05-29 16:04:27 -07:00
JonnyWong16
c67aedceb1 Add library statistics to API 2016-05-28 14:09:59 -07:00
JonnyWong16
b3a7fbd9b5 Add pms token to loopback url when retrieving images 2016-05-28 14:02:21 -07:00
JonnyWong16
29522428de Catch exception when retrieving current activity 2016-05-28 14:01:29 -07:00
JonnyWong16
77bd52b2ae Add user details and stats to API 2016-05-26 19:25:14 -07:00
Nick N
d8112e7628 Reflect path suggested in installation guide 2016-05-26 11:44:03 -07:00
JonnyWong16
ffa208e73f Merge branch 'dev' 2016-05-25 21:34:15 -07:00
JonnyWong16
61ead15c38 v1.4.5 2016-05-25 21:33:50 -07:00
JonnyWong16
407e2ae481 Revert pms image proxy to use 127.0.0.1 2016-05-25 21:27:43 -07:00
JonnyWong16
5fb16edf43 Make sure library details were returned when joining shared libraries 2016-05-25 18:55:20 -07:00
JonnyWong16
8eb5c475bb Make sure port is a string when when matching pms url 2016-05-25 18:54:31 -07:00
JonnyWong16
84090310f7 Extract mapped IPv4 address from Plexivity import 2016-05-25 18:53:40 -07:00
JonnyWong16
fc98e2f052 Merge branch 'dev' 2016-05-24 22:17:22 -07:00
JonnyWong16
bedcfa9520 v1.4.4 2016-05-24 22:17:09 -07:00
JonnyWong16
bb152b590b Set all datatable tooltips to body container 2016-05-24 22:13:26 -07:00
JonnyWong16
3623732cf7 Sort sessions by session_key
* Try to minimize instances jumping around under homepage current
activity.
* Still need to fix for music activity. Some clients have a different
session_key per track.
2016-05-24 22:12:57 -07:00
JonnyWong16
05ba89f164 Make sure clip image urls are escaped 2016-05-24 21:33:37 -07:00
Sander Ploegsma
cb5053476d Add log level filter for plex server and media logs 2016-05-25 00:09:04 +02:00
JonnyWong16
cee656a053 Fix ip address in Plexivity import 2016-05-23 18:02:13 -07:00
JonnyWong16
cfc7d529e1 Merge branch 'dev' 2016-05-22 16:24:23 -07:00
JonnyWong16
a93dc68e6c v1.4.3 2016-05-22 16:24:01 -07:00
JonnyWong16
2d91cfd3db Fix basic auth 2016-05-22 16:22:35 -07:00
JonnyWong16
36e81f44cb Merge branch 'dev' 2016-05-22 15:04:25 -07:00
JonnyWong16
cb0e65337f v1.4.2 2016-05-22 15:04:17 -07:00
JonnyWong16
1c627f4649 Fix unable to save settings when checking http proxy 2016-05-22 14:54:44 -07:00
JonnyWong16
16cbfed20b Option to use HTTP basic authentication 2016-05-22 14:23:55 -07:00
JonnyWong16
f6a3bc57e2 Fix typos 2016-05-22 13:24:52 -07:00
JonnyWong16
594443d1dc Match port as well when retrieving pms url 2016-05-22 13:24:45 -07:00
JonnyWong16
c3378e1653 Merge branch 'dev' 2016-05-20 20:54:36 -07:00
JonnyWong16
bc57dd650c v1.4.1 2016-05-20 20:54:06 -07:00
JonnyWong16
311a8c6fa3 Try using requests for Join notifications 2016-05-20 20:44:16 -07:00
JonnyWong16
bdb43c0e9e Add paging for recently added to the API 2016-05-20 20:16:14 -07:00
JonnyWong16
8033b47596 Add secondary sort by most recent for watch statistics 2016-05-19 22:44:28 -07:00
JonnyWong16
9d5052cc68 Add http proxy checkbox to settings 2016-05-19 21:55:11 -07:00
JonnyWong16
f4c9dc8a5f Make sure cherrypy doesn't add the local port twice with http_proxy enabled 2016-05-19 21:54:58 -07:00
JonnyWong16
a3f0a78df0 Reduce cost factor for hashing passwords
* Also reduce memory cost
2016-05-19 20:24:22 -07:00
JonnyWong16
b70363e005 Fix resolution in stream data modal 2016-05-18 20:55:49 -07:00
JonnyWong16
65eab801e8 Format Join device ids 2016-05-18 20:55:49 -07:00
JonnyWong16
9e764248d3 Merge pull request #713 from Hellowlol/fix_log_order
Fix #705
2016-05-18 20:55:06 -07:00
Hellowlol
a660a1c44b fix https://github.com/drzoidberg33/plexpy/issues/705#issuecomment-219927893
Can you test and verify
2016-05-18 20:55:20 +02:00
JonnyWong16
33458c1bdb Make sure current activity returned sessions when refreshing 2016-05-17 21:10:05 -07:00
JonnyWong16
e5530182cd Make sure we get a result when trying to group the session 2016-05-17 20:58:28 -07:00
JonnyWong16
9ecabc3faf Just make sure redirects include http_root 2016-05-16 18:18:52 -07:00
JonnyWong16
8b58f6b861 Make sure pms_identifier is cleared first when verifying server 2016-05-16 09:14:00 -07:00
JonnyWong16
9e41bf529d Don't return inside the loop after sending XBMC/Plex notifications 2016-05-16 08:28:40 -07:00
JonnyWong16
36398fe958 Persist current activity artwork blur across refresh 2016-05-15 21:54:25 -07:00
JonnyWong16
69cfbea5f3 Refresh Join device list when changing API key 2016-05-15 17:20:28 -07:00
JonnyWong16
1e1e3beca6 Check for blank username/passwords on login 2016-05-15 17:20:14 -07:00
JonnyWong16
a726154b1d Merge branch 'dev' 2016-05-15 13:23:34 -07:00
JonnyWong16
c2ccb51ef5 v1.4.0 2016-05-15 13:23:13 -07:00
JonnyWong16
a1d7062b1f Update changelog reader for second level indents 2016-05-15 13:22:06 -07:00
JonnyWong16
2e1e3f8409 Get Plex token using PlexTV 2016-05-15 12:57:03 -07:00
JonnyWong16
885604ef06 Add module name to webauth and webstart log messages 2016-05-15 11:52:01 -07:00
JonnyWong16
cb8a5504f6 Cleanup unused modules and imports
* Ran code through PyFlakes
2016-05-15 11:32:11 -07:00
JonnyWong16
325fa19e46 Some notifiers cleanup 2016-05-15 10:15:59 -07:00
JonnyWong16
06b684c899 Include oauthlib module 2016-05-15 10:15:44 -07:00
JonnyWong16
363d1b07ca Alert if leaving settings without saving changes 2016-05-15 02:11:58 -07:00
JonnyWong16
663b9a610a Need IP address modal on logs page 2016-05-15 01:26:31 -07:00
JonnyWong16
f598d5046e Add complete login table to logs 2016-05-15 01:01:29 -07:00
JonnyWong16
ae381f7762 Some missed css 2016-05-15 00:04:04 -07:00
JonnyWong16
acc18b8d68 Include posters in Twitter notifications
* Also cleanup Facebook
2016-05-15 00:03:45 -07:00
JonnyWong16
6f33d29a51 Add user login table to API 2016-05-14 23:09:43 -07:00
JonnyWong16
be82e64add Include poster in Slack notifications 2016-05-14 23:00:54 -07:00
JonnyWong16
3ee000ed7d Add Join notification agent 2016-05-14 22:21:59 -07:00
JonnyWong16
0f338edacd Forgot some css in 0cbc4b9546 2016-05-14 19:53:27 -07:00
JonnyWong16
085d937946 Only strip timestamp when caching image if it is metadata 2016-05-14 19:47:14 -07:00
JonnyWong16
0cbc4b9546 More fixes to scrolling datatables 2016-05-14 19:46:22 -07:00
JonnyWong16
9e1c4b1a88 Add side scrolling datatables 2016-05-14 10:46:26 -07:00
JonnyWong16
b47f542df7 Limit number of failed session write attempts for activity pinger
* Default is 5 attempts, configurable manually in the config file.
2016-05-13 22:48:24 -07:00
JonnyWong16
baed101ef1 Fix all confirm modal dialogues 2016-05-13 22:05:54 -07:00
JonnyWong16
c9ee6e3af9 Some datatables cleanup 2016-05-13 21:43:32 -07:00
JonnyWong16
8ed7688277 Log PlexPy logins to database 2016-05-13 21:43:21 -07:00
JonnyWong16
27716d080f Cleanup setup wizard 2016-05-13 18:38:33 -07:00
JonnyWong16
4311d12603 Import Plexivity database 2016-05-12 23:50:04 -07:00
JonnyWong16
6aa786698e Backup config file 2016-05-12 22:00:34 -07:00
JonnyWong16
b0eb98c667 Some javascript cleanup in settings 2016-05-12 20:58:33 -07:00
JonnyWong16
955b69a9bf Don't redirect when saving settings 2016-05-12 20:56:59 -07:00
JonnyWong16
5f5bfa864d Fix libraries and users confirm delete modal 2016-05-12 18:20:00 -07:00
JonnyWong16
6ec6c69dba Fix grouping on history table 2016-05-12 18:15:21 -07:00
JonnyWong16
19f3286a82 Typo in API docs 2016-05-12 01:21:28 -07:00
JonnyWong16
36a3cae9c2 Remove javascript from guest pages 2016-05-12 00:43:48 -07:00
JonnyWong16
86215c34be Raise exception type 2016-05-12 00:26:07 -07:00
JonnyWong16
4ad421d4d0 Add note bif thumbnails not cached 2016-05-12 00:25:55 -07:00
JonnyWong16
e79f6d5617 Cleanup image caching and logs
* Prettier confirm modal dialogues
* Setting to disable image caching
2016-05-12 00:04:31 -07:00
JonnyWong16
baf44a97b4 Use PMSConnect to retireve notification poster 2016-05-11 22:01:38 -07:00
JonnyWong16
c14053a199 Send PMS token in header instead of in uri 2016-05-11 22:01:11 -07:00
JonnyWong16
1e5153d69e Merge pull request #695 from Hellowlol/imgzz
Cache images and remove memory log
2016-05-11 21:50:10 -07:00
JonnyWong16
fed38bd046 Try a new stream info modal layout 2016-05-11 21:25:20 -07:00
JonnyWong16
89d298ea65 Add Imgur client id note in settings 2016-05-11 21:03:09 -07:00
JonnyWong16
cd35fa1802 Fix current activity header for tracks 2016-05-11 20:59:29 -07:00
JonnyWong16
150453bff3 Fix current activity artwork for tracks 2016-05-11 20:59:19 -07:00
JonnyWong16
49833b3c51 Update issues template to make it clearer 2016-05-10 09:48:35 -07:00
JonnyWong16
4a0f0238b0 Persist current activity details between refreshes 2016-05-10 00:36:34 -07:00
JonnyWong16
83b97111a0 Add PMS http request timeout an advanced setting in config file 2016-05-09 18:28:39 -07:00
Hellowlol
43bbf32098 fix formatting and add pretag 2016-05-09 22:41:07 +02:00
JonnyWong16
a70817f421 Fallback to shared Imgur client id for now 2016-05-08 17:53:50 -07:00
Hellowlol
9ae441b75a cache image, download log etc. 2016-05-09 01:03:37 +02:00
JonnyWong16
21fcbd85d8 Removed shared Imgur client id
* Users must enter their own Imgur client id now
2016-05-08 15:50:10 -07:00
JonnyWong16
e1b61214b7 Update all APIv2 docs 2016-05-08 11:42:53 -07:00
JonnyWong16
2d10b0748c Change regex to match a3a62b1 for server notify text 2016-05-07 16:16:08 -07:00
JonnyWong16
f4e719749a Cleanup all imports
* Should fix problems with needing to do inline imports
2016-05-07 11:26:00 -07:00
JonnyWong16
600bca7e8b Only check browser notifications if enabled 2016-05-07 11:20:46 -07:00
JonnyWong16
a3a62b1d94 Add lazy quantifier to notifications media tag regex 2016-05-07 08:43:05 -07:00
JonnyWong16
dbe783d31d Remove a step in the Facebook app setup
* Email address is required when creating a Facebook app, so no need for
the extra step
2016-05-06 18:53:47 -07:00
JonnyWong16
f0d8492b66 Mark browser notifications experimental 2016-05-06 18:42:15 -07:00
JonnyWong16
7587eb9ac2 Remove print statement 2016-05-06 18:42:04 -07:00
JonnyWong16
fe2fdafbb1 Change regex for media type tags 2016-05-06 18:41:52 -07:00
JonnyWong16
e50c77d8c6 Fix {plex_url) string formatting 2016-05-06 18:09:13 -07:00
JonnyWong16
81f9f52353 Fix double fallback image in current activity 2016-05-05 19:22:02 -07:00
JonnyWong16
6e5b02d326 Fix Email HTML 2016-05-04 23:15:10 -07:00
JonnyWong16
d09c7b13b3 Add browser notifications 2016-05-04 22:56:04 -07:00
JonnyWong16
ff532a5c6c Return success/failed message for testing notifications 2016-05-04 18:10:02 -07:00
JonnyWong16
698275633f Fix and add Plex back to notification agents 2016-05-04 17:49:10 -07:00
JonnyWong16
c5dff312e1 Allow HTML emails 2016-05-04 17:48:47 -07:00
JonnyWong16
972412e712 Use bleach to clean Telegram and Pushover HTML 2016-05-04 17:46:51 -07:00
JonnyWong16
453c46df00 Add bleach library to clean notification HTML 2016-05-04 17:45:48 -07:00
JonnyWong16
f001e19728 Add transcode decision count to activity header 2016-05-04 12:54:14 -07:00
JonnyWong16
3da8cc1e7f Allow "All Users" in graphs for guests 2016-05-04 12:10:58 -07:00
JonnyWong16
68d124ff04 Some minor UI tweaks 2016-05-04 11:13:33 -07:00
JonnyWong16
4921458782 Fix typos 2016-05-03 10:31:42 -07:00
JonnyWong16
86aa21a8bb Add {plex_url} as a notification option 2016-05-03 00:49:22 -07:00
JonnyWong16
65de742f96 Add posters and HTML support for Telegram 2016-05-03 00:39:24 -07:00
JonnyWong16
4043398e01 Update requests package to 2.10.0 2016-05-02 23:26:10 -07:00
JonnyWong16
7be651f5cf Caches pms images to disk 2016-05-02 22:08:06 -07:00
JonnyWong16
5ddd4d045e Fix recently "watched" music to "played" 2016-05-02 15:30:08 -07:00
JonnyWong16
1cc7e8725d Tone down the bold headers font 2016-05-02 09:47:59 -07:00
JonnyWong16
6fe115fd0d Hide update notification from guests 2016-05-02 08:37:13 -07:00
JonnyWong16
d58dfec5ea Remove Libraries > Edit mode button from GUI for guests 2016-05-02 08:33:12 -07:00
JonnyWong16
3e6f5ac70e Ignore case of username/email when matching the user in the database 2016-05-01 22:56:18 -07:00
JonnyWong16
a1821fabf9 Fix first time guest logins failing 2016-05-01 20:52:36 -07:00
JonnyWong16
b6461f4f9e Refresh the users list on guest login to update library permissions 2016-05-01 16:58:19 -07:00
JonnyWong16
0781018e4e Rename masked Title to Plex Media 2016-05-01 14:23:25 -07:00
JonnyWong16
2f8e768c5c Add modal popup for admin login from menu 2016-05-01 11:06:37 -07:00
JonnyWong16
1622b0fa29 Make sure info pages are protected if source=history 2016-05-01 11:06:37 -07:00
JonnyWong16
e147ce9039 Add all content rating and label filters for guest 2016-05-01 11:06:37 -07:00
JonnyWong16
2aa059a170 Add shared libraries and filters to database 2016-05-01 11:06:37 -07:00
JonnyWong16
ae60b21375 Add metadata labels to database 2016-05-01 11:06:37 -07:00
JonnyWong16
03faebe776 Make sure to check server token on login 2016-05-01 11:06:37 -07:00
JonnyWong16
f66afc4cae Change episode image fallback to art 2016-05-01 11:06:37 -07:00
JonnyWong16
b327413bfa Change friendly name to username on history tables 2016-05-01 11:06:37 -07:00
JonnyWong16
54776e2712 Show masked top 10 users on graphs 2016-05-01 11:06:37 -07:00
JonnyWong16
4b8d4488d7 Change "Allow" to "Toggle" guest access 2016-05-01 11:06:37 -07:00
JonnyWong16
a2a1b66fc3 Disable allow guest access checkbox if no admin username/password setup 2016-05-01 11:06:37 -07:00
JonnyWong16
d2bdb597f6 Sessions off if no password set 2016-05-01 11:06:37 -07:00
JonnyWong16
85a7819469 Check if sessions enabled for login/logout
* Redirect to logout on session expiry to remove the session
2016-05-01 11:06:37 -07:00
JonnyWong16
5689dfd3e3 Use image for login screen logo 2016-05-01 11:06:37 -07:00
JonnyWong16
3c76ead1ab Check to make sure session isn't None before returning 2016-05-01 11:06:37 -07:00
JonnyWong16
be7fbdf5d8 Accidentally removed modal restart button in settings 2016-05-01 11:06:37 -07:00
JonnyWong16
fc21f043ae Catch exception and return default session 2016-05-01 11:06:37 -07:00
JonnyWong16
11659df89d Missing 'year' key in track current activity 2016-05-01 11:06:37 -07:00
JonnyWong16
2bfa770f60 Hacky solution to exclude cherrypy threads from sessions 2016-05-01 11:06:37 -07:00
JonnyWong16
4679121115 Check session enabled instead of auth 2016-05-01 11:06:37 -07:00
JonnyWong16
3ecc90d21a Add request status to notifier logs 2016-05-01 11:06:37 -07:00
JonnyWong16
fd587fe108 Smoother animation for homepage recently added media toggles 2016-05-01 11:06:37 -07:00
JonnyWong16
0f851ec2a3 Filter info pages and search results for guests 2016-05-01 11:06:37 -07:00
JonnyWong16
4d057a1c5e Add user selection to history page
* Clean up buttons
2016-05-01 11:06:37 -07:00
JonnyWong16
c8b13ff5e1 Filter all graph data for guests 2016-05-01 11:06:37 -07:00
JonnyWong16
545dd08535 Flip mask_session_info bool 2016-05-01 11:06:37 -07:00
JonnyWong16
c0a5a8d775 Filter all library and user data for guests 2016-05-01 11:06:37 -07:00
JonnyWong16
d462ebe8e5 Allow logging in with email address 2016-05-01 11:06:37 -07:00
JonnyWong16
5d7ba8cf14 Mask all info on the homepage 2016-05-01 11:06:37 -07:00
JonnyWong16
af9786f149 Guest access per user disabled by default 2016-05-01 11:06:37 -07:00
JonnyWong16
6b990ee78a Pass 'admin' as default to templates 2016-05-01 11:06:37 -07:00
JonnyWong16
f87102ccc7 Check if cherrypy auth enabled before serving template 2016-05-01 11:06:37 -07:00
JonnyWong16
63398089cd Disable auth for static directories 2016-05-01 11:06:37 -07:00
JonnyWong16
89694b5069 More template filters for Libraries, Users, and Sync 2016-05-01 11:06:37 -07:00
JonnyWong16
4f8a5211f8 Filter History and Graphs in the WebUI
* Still need to prevent manually accessing endpoints with other user_ids
2016-05-01 11:06:37 -07:00
JonnyWong16
b45df26fdc Add manual "Verify Server" button to PMS settings 2016-05-01 11:06:37 -07:00
JonnyWong16
c0b0181475 Some cleanup 2016-05-01 11:06:37 -07:00
JonnyWong16
62600a450a Add global allow guest access setting and per user toggles 2016-05-01 11:06:37 -07:00
JonnyWong16
4be41336b3 Missing require auth for getLog 2016-05-01 11:06:37 -07:00
JonnyWong16
3abea4ad3c Enable guest login with Plex.tv account 2016-05-01 11:06:37 -07:00
JonnyWong16
b2304992e5 Update CherryPy to 5.1.0 2016-05-01 11:06:37 -07:00
JonnyWong16
f9825410dc Move mask logs toggle to Extra Settings 2016-05-01 11:06:37 -07:00
JonnyWong16
24205dc86e Fix settings hover nav menu for mobile 2016-05-01 11:06:37 -07:00
JonnyWong16
9fcd0da83d Save session for 30 days with "Remember Me" checked 2016-05-01 11:06:37 -07:00
JonnyWong16
e99bc73e46 Require authentication for all endpoints except API
* And more minor UI changes
2016-05-01 11:06:37 -07:00
JonnyWong16
d8ad9adabd A bunch of UI updates 2016-05-01 11:06:37 -07:00
JonnyWong16
11aa7d0140 Add option to hash password in config file 2016-05-01 11:06:37 -07:00
JonnyWong16
6f97173b00 Add http_root to settings page 2016-05-01 11:06:37 -07:00
JonnyWong16
54a7367fb6 Remove unnecessary css and js from login page 2016-05-01 11:06:37 -07:00
JonnyWong16
51a12099e4 Initial implementation of login control 2016-05-01 11:06:37 -07:00
JonnyWong16
00c0c96b1b Merge branch 'dev' 2016-05-01 11:03:01 -07:00
JonnyWong16
0aa2537d1e v1.3.16 2016-05-01 11:02:36 -07:00
JonnyWong16
14489e1db9 Revert reconnecting cf70b3e989 and bff4eaba56 2016-04-30 13:03:54 -07:00
JonnyWong16
bff4eaba56 Websocket check active sessions on reconnect cf70b3e989 2016-04-29 08:03:14 -07:00
JonnyWong16
4a5d2f8502 Fix regression PMS update notifications broken 2016-04-29 07:07:02 -07:00
JonnyWong16
72af2fa281 Fix persist Users > Edit mode on datatable page change 2016-04-27 23:47:24 -07:00
JonnyWong16
cf70b3e989 Reconnect websocket on a new thread 2016-04-27 23:11:12 -07:00
JonnyWong16
7ebd74a54a Cache posters with thread id to avoid overwriting images 2016-04-27 23:10:54 -07:00
JonnyWong16
9a650b5cd6 Merge pull request #662 from otgerp/dev
Added ability to view per-user graphs
2016-04-23 21:51:26 -07:00
Otger
ffa1331802 Added missing user filtering to a pair of graphs and renamed a few things 2016-04-24 03:21:51 +02:00
Otger
dacb4ea7d6 Merge branch 'dev' of https://github.com/drzoidberg33/plexpy into dev 2016-04-24 02:43:46 +02:00
JonnyWong16
ae5889dbac Fix viewing photos crashing PlexPy 2016-04-21 08:38:28 -07:00
drzoidberg33
7b169e9439 Create ISSUE_TEMPLATE.md 2016-04-19 21:17:55 +02:00
JonnyWong16
541d2904d3 Merge branch 'dev' 2016-04-18 21:29:13 -07:00
JonnyWong16
2080bbcbca v1.3.15 2016-04-18 21:28:45 -07:00
JonnyWong16
f4c38008a1 Fix logger typo 2016-04-16 22:46:47 -07:00
JonnyWong16
2d38b15f1b Merge pull request #672 from alotufo/dev
Optimized iOS, Android and IE10 images
2016-04-16 09:36:20 -07:00
Al Lotufo
13257b9f86 Optimize iOS images
Ran images through ImageOptim to reduce file size
2016-04-16 12:23:09 -04:00
Al Lotufo
22f106b357 Optimize IE10 images
Ran images through ImageOptim to reduce file size
2016-04-16 12:21:17 -04:00
Al Lotufo
352b5aadba Optimize Android images
Ran images through ImageOptim to reduce file size
2016-04-16 12:20:42 -04:00
JonnyWong16
f86c9ea947 Fix 127.0.0.1 showing as external IP address on tables 2016-04-13 18:03:05 -07:00
JonnyWong16
2f5f0ba1e1 Fix getting pms_url when multiple connections published
* Fixes bug grabbing the wrong pms_url when multiple local/remote
connections are published to plex.tv
* This tries to find the connection with the matching address first,
otherwise grabs the first valid local/remote connection (prior
behaviour)
2016-04-12 22:52:53 -07:00
JonnyWong16
6a72923182 Fix Slack notifications with an icon URL not sending 2016-04-12 08:55:08 -07:00
Otger
d62f7b2a5f Added ability to view per-user graphs 2016-04-09 23:54:31 +02:00
JonnyWong16
8ca6255ff3 Merge pull request #658 from xtjoeytx/patch-1
Update welcome.html
2016-04-08 16:13:33 -07:00
Joseph
d3b3afd593 Update welcome.html
fixed spelling error
2016-04-08 01:07:41 -04:00
JonnyWong16
57cb5ff6cf Fix fallback pms_url if server URL not found 2016-04-06 19:23:59 -07:00
JonnyWong16
39f3da6cde Fix regression file sizes not shown in media info table footer 2016-04-06 19:21:52 -07:00
JonnyWong16
5a236c9357 Fix wording of notification delay help text 2016-04-06 19:19:13 -07:00
JonnyWong16
4b0eab57a8 Fix regression PMS down notifications failing 2016-04-06 19:17:56 -07:00
JonnyWong16
74a232630a Add {transcode_key} and {username} notification options 2016-04-02 14:11:18 -07:00
JonnyWong16
71d023ab77 Fix logger typo in notification handler 2016-04-02 12:13:54 -07:00
JonnyWong16
786a374233 Merge branch 'dev' 2016-03-29 08:16:25 -07:00
JonnyWong16
41899872cd v1.3.14 2016-03-29 08:15:35 -07:00
JonnyWong16
076659db52 Fix regression missing notify_action for script notifications 2016-03-28 22:21:23 -07:00
JonnyWong16
8f665622d6 Fix typo for home stats cards in settings 2016-03-28 18:12:32 -07:00
JonnyWong16
5cc6e0b172 Merge branch 'dev' 2016-03-27 17:25:53 -07:00
JonnyWong16
bff22900cb v1.3.13 2016-03-27 17:25:16 -07:00
JonnyWong16
5e79c9fd62 Only filter logger if string is longer than 5 characters 2016-03-27 17:22:30 -07:00
JonnyWong16
92f55c254c Merge branch 'dev' 2016-03-27 16:51:30 -07:00
JonnyWong16
39034e38f6 v1.3.12 2016-03-27 16:43:06 -07:00
JonnyWong16
3c7b9558fe Access log file from the Help & Info page 2016-03-27 16:41:57 -07:00
JonnyWong16
c8f7f40b46 ISO date format for logs 2016-03-27 16:10:02 -07:00
JonnyWong16
2a764cf190 Add "First" and "Last" page buttons to datatables 2016-03-27 15:32:03 -07:00
JonnyWong16
ba6ef4d629 Add toggle for log blacklist and mask public IP addresses 2016-03-27 15:18:41 -07:00
JonnyWong16
67d3505733 Merge pull request #627 from JonnyWong16/dev-env
Enable PlexPy dev environment
2016-03-27 10:30:42 -07:00
JonnyWong16
252145cf58 Enable PlexPy dev environment using --dev flag 2016-03-27 10:25:46 -07:00
JonnyWong16
dbc62542ef Merge pull request #634 from evilmarty/enhancement/ifttt
Allow formatting of IFTTT event key with action name
2016-03-26 18:08:45 -07:00
Marty Zalega
005829ab72 Allow formatting of ifttt event key with action name 2016-03-27 10:46:09 +10:00
JonnyWong16
448c8b0e8a Merge pull request #632 from alshain/patch-2
Fix unicode logging with 1252 encoded locale on Windows
2016-03-26 12:09:27 -07:00
Chris
ff0e724ee5 Fix unicode logging with 1252 encoded locale on Windows
Replaces the abbreviation for months in the log output with numerals. Works around logging exceptions on Windows during March ("Mär") with Swiss-German locale on Windows, which is encoded with Windows-1252.
2016-03-26 19:59:12 +01:00
JonnyWong16
568e4a5ee8 Fix blacklist logging again ed8c7c1 2016-03-26 10:00:58 -07:00
JonnyWong16
fbf4a524c1 Catch URLError when uploading to Imgur 2016-03-25 15:39:31 -07:00
JonnyWong16
29db2e958f Hide Plex notification agent 2016-03-25 13:24:24 -07:00
JonnyWong16
cc7bcbf9d5 Change log directory to log file in "Help & Info" 2016-03-25 13:20:50 -07:00
JonnyWong16
98d4484e6c Update CONTRIBUTING.md 2016-03-25 13:20:25 -07:00
JonnyWong16
0b126278f9 Fix blacklisting of blank strings from ed8c7c1 2016-03-25 13:00:04 -07:00
JonnyWong16
cc919415bb Merge pull request #612 from codedecay/dev
Add CherryPy Environment Option
2016-03-25 12:59:28 -07:00
JonnyWong16
a3f398390c Clean up Arnie quotes 2016-03-25 09:16:24 -07:00
JonnyWong16
5ae89368f1 Merge pull request #625 from Chrisophogus/patch-1
Extra Arnie
2016-03-25 09:14:25 -07:00
JonnyWong16
c8f1cb0a0a Start PlexPy for different environment variables 2016-03-25 09:12:40 -07:00
Chrisophogus
f783b08b78 Additional changes 2016-03-23 20:52:50 +00:00
Chrisophogus
85e0c6d3cd Extra Arnie
Added some additional Arnie quotes.
2016-03-23 20:14:48 +00:00
JonnyWong16
2259a96058 Use default poster for Facebook if unable to upload poster 2016-03-21 18:53:56 -07:00
JonnyWong16
afed5841e7 Remove old notify_log table upgrades 2016-03-20 17:17:50 -07:00
JonnyWong16
52361cd505 Catch error if unable to retrieve poster for notification 2016-03-20 17:06:58 -07:00
JonnyWong16
b743cca7bc Add summary to Facebook posts 2016-03-19 23:27:26 -07:00
JonnyWong16
1d01d0bff1 Add FeatHub feature requests and guidelines modal popup 2016-03-19 22:24:09 -07:00
JonnyWong16
c45a488962 Remove experimental from Facebook and Scripts 2016-03-19 20:45:49 -07:00
JonnyWong16
6731c44541 Merge pull request #614 from Vilsol/dev
Update Arnold Quotes
2016-03-19 16:20:31 -07:00
JonnyWong16
b04ed83963 Make sure build_notify_text returns two values 2016-03-16 19:13:29 -07:00
Vilsol
c35b79e642 Update Arnold Quotes 2016-03-16 16:33:56 +00:00
JonnyWong16
ed8c7c1052 Filter out tokens/keys/passwords from logger 2016-03-15 23:49:35 -07:00
JonnyWong16
498a074222 Add user GitHub API Token to settings 2016-03-15 23:49:27 -07:00
JonnyWong16
3fe6db4d42 Fix "Check GitHub for updates" not rescheduling when toggling setting 2016-03-15 20:42:45 -07:00
Eric Solari
6e5cd82dfb Add CherryPy Environment Option 2016-03-15 22:24:08 -05:00
JonnyWong16
cbf3488de9 Merge branch 'dev' 2016-03-15 19:15:46 -07:00
JonnyWong16
c72314fb71 v1.3.11 2016-03-15 19:14:56 -07:00
JonnyWong16
c4af6feb92 Fix typo preventing history logging for websockets 2016-03-15 19:13:13 -07:00
JonnyWong16
08537c1d69 Merge branch 'dev' 2016-03-12 15:04:40 -08:00
JonnyWong16
425da82f5f v1.3.10 2016-03-12 15:04:16 -08:00
JonnyWong16
2cfbf7c39a Rename "watched" to "played" on user/library pages 2016-03-12 14:35:29 -08:00
JonnyWong16
d4eed9f8fd Merge pull request #594 from chiviak/160223_freenas_dev
Few improvements to the FreeNAS/FreeBSD init scripts
2016-03-09 22:13:24 -08:00
JonnyWong16
fe10170826 Fix checked settings to int when saving config 2016-03-09 22:11:23 -08:00
JonnyWong16
8dc3b0b250 Do not retrieve user/library details if importing plexWatch database 2016-03-09 22:10:33 -08:00
JonnyWong16
75da1220af Fix expanding media info tables from 464d2a5 2016-03-08 18:23:58 -08:00
JonnyWong16
37a2c3c631 Fix typo in notification settings 2016-03-08 18:21:01 -08:00
JonnyWong16
5c5722714d Add ability to clear the temporary sessions table from database 2016-03-07 19:40:18 -08:00
JonnyWong16
2ba529f9e3 Fix missing time import 2016-03-06 17:06:05 -08:00
JonnyWong16
fd760ff015 Fix missing notifiers import 2016-03-06 17:05:52 -08:00
Scott Serrano
daab1d917b Update FreeBSD script to match the latest FreeNAS changes 2016-03-05 21:14:53 -08:00
Scott Serrano
4c3a63a7e1 Allow for additional plexpy arguments like port 2016-03-05 21:14:48 -08:00
Scott Serrano
7cc58b84da Run plexpy directly in daemon mode instead of using the daemon program 2016-03-05 21:14:42 -08:00
Scott Serrano
2bac4ac1a7 Make the freenas init script executable 2016-03-05 21:14:35 -08:00
JonnyWong16
c5b2b86786 Enable keep_history for default user/library
* Log sessions to "Local" if retrieving user/library data fails
2016-03-05 16:21:59 -08:00
JonnyWong16
5652a2b6c2 Revert set_session_state from d73e379 2016-03-05 16:05:32 -08:00
JonnyWong16
bd19f543a2 Merge pull request #586 from JonnyWong16/websockets-watched-notify-fix
Check if notification agents enabled before sending notifications
2016-03-05 13:22:11 -08:00
JonnyWong16
cc1e888227 Check if notification agents enabled before sending notifications 2016-03-05 13:20:28 -08:00
JonnyWong16
d73e379dcf Do not remove session from db until it is successfully written
* For activity pinger only
2016-03-05 13:07:26 -08:00
JonnyWong16
0569abd00d Add customizable backup, cache, and log directory 2016-03-04 23:41:18 -08:00
JonnyWong16
7f5d9bec87 Add button to clear notification logs 2016-03-04 23:13:19 -08:00
JonnyWong16
b39e7bbb6d Do not strip newlines from notification text
* Behaviour is more predictable this way
2016-03-04 22:50:21 -08:00
JonnyWong16
70270a8e3b Hide days selection from Play Totals graph 2016-03-04 22:27:52 -08:00
JonnyWong16
efdc050a28 Filter history modal on graphs based on clicked series 2016-03-04 22:21:34 -08:00
JonnyWong16
e8a65df7f0 Add transcode_decision to media_info table 2016-03-04 22:20:15 -08:00
JonnyWong16
59628a72fb Fix typo in PlexWatch importer 2016-03-04 22:19:16 -08:00
JonnyWong16
a4d6c6c0d8 Fix datatables modal popups from 464d2a5 2016-03-04 22:18:34 -08:00
JonnyWong16
bea82c6640 Fix IPv6 address 2016-03-03 14:26:39 -08:00
drzoidberg33
1ba3bdfbda Don't check for PMS updates every 10 seconds. 2016-03-02 14:00:30 +02:00
JonnyWong16
98b4000bc0 Add ability to reset Imgur posters from info page 2016-03-01 23:29:49 -08:00
JonnyWong16
14f6824931 Use Parsley to verify pms logs folder is not a shortcut 2016-03-01 21:49:12 -08:00
JonnyWong16
795d7d0a93 Add ability to get notified of PMS updates 2016-03-01 21:04:57 -08:00
JonnyWong16
673fa2b556 Fix auto-refresh of log tabs 2016-03-01 20:31:45 -08:00
JonnyWong16
0e2504fc78 Document remaining time format options 2016-03-01 20:31:21 -08:00
JonnyWong16
2afca9f2b4 Alert if PMS logs folder is a shortcut 2016-02-28 15:39:13 -08:00
JonnyWong16
464d2a541d Give tables unique ids to save state indivdually 2016-02-27 13:39:21 -08:00
JonnyWong16
fa8c5e0982 Only use user_id in current activity link to user page 2016-02-27 01:18:40 -08:00
JonnyWong16
5e15884d8f Fix scrollers when items don't fill up the row 2016-02-27 01:00:12 -08:00
JonnyWong16
b5e9ff3b4e Add scrolling recently watched and added to user and library pages 2016-02-27 00:00:11 -08:00
JonnyWong16
fed7d4cc34 Add scrolling recently added to homepage 2016-02-26 23:53:03 -08:00
JonnyWong16
d7ab066ff8 Revert datatables save state to true 2016-02-26 21:57:22 -08:00
JonnyWong16
4100917016 Add ability to disable Facebook poster link to Plex Web 2016-02-26 21:39:41 -08:00
JonnyWong16
5d2c1ffb88 Fix bug in checking for PMS version in settings 2016-02-26 19:17:42 -08:00
JonnyWong16
ddb0f198a9 Add tooltip to current activity progress bars 2016-02-25 21:56:23 -08:00
JonnyWong16
13438e3e25 Anonymize more URLs 2016-02-25 09:57:05 -08:00
JonnyWong16
05a410b327 Catch blank view_offset or duration in history table query 2016-02-24 21:40:29 -08:00
JonnyWong16
23fa64d289 Change colour of grouped recently added note on checkbox toggle 2016-02-24 21:40:19 -08:00
JonnyWong16
1920c9b7e3 Reconnect websocket on server change 2016-02-23 19:05:20 -08:00
JonnyWong16
eedd0d9c07 Use subprocess.Popen on windows to restart PlexPy
* See python bug: https://bugs.python.org/issue19066
2016-02-23 18:29:33 -08:00
JonnyWong16
9ef389d335 Actually allow HTML tags for Pushover 2016-02-22 21:20:05 -08:00
JonnyWong16
6542997520 Merge branch 'dev' 2016-02-21 23:07:33 -08:00
JonnyWong16
a58b2e2038 v1.3.9 2016-02-21 23:06:22 -08:00
JonnyWong16
6860e348dc Fix typo in setting recently added notification state 2016-02-21 23:01:18 -08:00
JonnyWong16
5e094e7597 Merge pull request #477 from elseym/pushover-html-support
Pushover HTML Support
2016-02-21 21:35:07 -08:00
JonnyWong16
2f2cb8386b Change wording for enable posters in notification help text 2016-02-21 20:41:18 -08:00
elseym
0873beaed2 enable pushover html support by default, introduce option to deactivate 2016-01-24 18:06:36 +01:00
1240 changed files with 150422 additions and 108751 deletions

12
.gitignore vendored
View File

@@ -12,16 +12,20 @@
*.db* *.db*
*.db-journal *.db-journal
*.ini *.ini
release.lock
version.lock version.lock
logs/* logs/*
backups/*
cache/* cache/*
newsletters/*
*.mmdb
# HTTPS Cert/Key # # HTTPS Cert/Key #
################## ##################
*.crt /*.crt
*.key /*.key
*.csr /*.csr
*.pem /*.pem
# Mergetool # Mergetool
*.orgin *.orgin

2720
API.md

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,61 +1,20 @@
# Contributing to PlexPy # Contributing to Tautulli
## Issues
In case you read this because you are posting an issue, please take a minute and conside the things below. The issue tracker is not a support forum. It is primarily intended to submit bugs, improvements or feature requests. However, we are glad to help you, and make sure the problem is not caused by PlexPy, but don't expect step-by-step answers.
##### Many issues can simply be solved by:
- Making sure you update to the latest version.
- Turning your device off and on again.
- Analyzing your logs, you just might find the solution yourself!
- Using the **search** function to see if this issue has already been reported/solved.
- Checking the [Wiki](https://github.com/drzoidberg33/plexpy/wiki) for
[ [Installation] ](https://github.com/drzoidberg33/plexpy/wiki/Installation) and
[ [FAQs] ](https://github.com/drzoidberg33/plexpy/wiki/Frequently-Asked-Questions-(FAQ)).
- For basic questions try asking on [Gitter](https://gitter.im/drzoidberg33/plexpy) or the [Plex Forums](https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program) first before opening an issue.
##### If nothing has worked:
1. Open a new issue on the GitHub [issue tracker](http://github.com/drzoidberg33/plexpy/issues).
2. Provide a clear title to easily help identify your problem.
3. Use proper [markdown syntax](https://help.github.com/articles/github-flavored-markdown) to structure your post (i.e. code/log in code blocks).
4. Make sure you provide the following information:
- [ ] Version
- [ ] Branch
- [ ] Commit hash
- [ ] Operating system
- [ ] Python version
- [ ] What you did?
- [ ] What happened?
- [ ] What you expected?
- [ ] How can we reproduce your issue?
- [ ] What are your (relevant) settings?
- [ ] Include a link to your **FULL** (not just a few lines!) log file that has the error. Please use [Gist](http://gist.github.com) or [Pastebin](http://pastebin.com/).
5. Close your issue when it's solved! If you found the solution yourself please comment so that others benefit from it.
## Feature Requests
1. Search for similar existing 'issues', feature requests can be recognized by the blue `enhancement` label.
2. If a similar request exists, post a comment (+1, or add a new idea to the existing request).
3. If no similar requests exist, you can create a new one.
4. Provide a clear title to easily identify the feature request.
5. Tag your feature request with `[Feature Request]` so it can be identified easily.
## Pull Requests ## Pull Requests
If you think you can contribute code to the PlexPy repository, do not hesitate to submit a pull request. If you think you can contribute code to the Tautulli repository, do not hesitate to submit a pull request.
### Branches ### Branches
All pull requests should be based on the `dev` branch, to minimize cross merges. When you want to develop a new feature, clone the repository with `git clone origin/dev -b FEATURE_NAME`. Use meaningful commit messages. All pull requests should be based on the `nightly` branch, to minimize cross merges. When you want to develop a new feature, clone the repository with `git clone origin/nightly -b FEATURE_NAME`. Use meaningful commit messages.
### Python Code ### Python Code
#### Compatibility #### Compatibility
The code should work with Python 2.6 and 2.7. Note that PlexPy runs on different platforms, including Network Attached Storage devices such as Synology. The code should work with Python 2.7. Note that Tautulli runs on many different platforms.
Re-use existing code. Do not hesitate to add logging in your code. You can the logger module `plexpy.logger.*` for this. Web requests are invoked via `plexpy.request.*` and derived ones. Use these methods to automatically add proper and meaningful error handling. Re-use existing code. Do not hesitate to add logging in your code. You can the logger module `plexpy.logger.*` for this. Web requests are invoked via `plexpy.request.*` and derived ones. Use these methods to automatically add proper and meaningful error handling.
#### Code conventions #### Code conventions
Although PlexPy did not adapt a code convention in the past, we try to follow the [PEP8](http://legacy.python.org/dev/peps/pep-0008/) conventions for future code. A short summary to remind you (copied from http://wiki.ros.org/PyStyleGuide): Although Tautulli did not adapt a code convention in the past, we try to follow the [PEP8](http://legacy.python.org/dev/peps/pep-0008/) conventions for future code. A short summary to remind you (copied from http://wiki.ros.org/PyStyleGuide):
* 4 space indentation * 4 space indentation
* 80 characters per line * 80 characters per line
@@ -70,13 +29,10 @@ Although PlexPy did not adapt a code convention in the past, we try to follow th
#### Documentation #### Documentation
Document your code. Use docstrings See [PEP-257](https://www.python.org/dev/peps/pep-0257/) for more information. Document your code. Use docstrings See [PEP-257](https://www.python.org/dev/peps/pep-0257/) for more information.
#### Continuous Integration
PlexPy has a configuration file for [travis-ci](https://travis-ci.org/). You can add your forked repo to Travis to have it check your code against PEP8, PyLint, and PyFlakes for you. Your pull request will show a green check mark or a red cross on each tested commit, depending on if linting passes.
### HTML/Template code ### HTML/Template code
#### Compatibility #### Compatibility
HTML5 compatible browsers are targetted. There is no specific mobile version of PlexPy yet. HTML5 compatible browsers are targeted.
#### Conventions #### Conventions
* 4 space indentation * 4 space indentation

41
ISSUE_TEMPLATE.md Normal file
View File

@@ -0,0 +1,41 @@
<!---
Reporting Issues:
* To ensure that a developer has enough information to work with please include all of the information below.
Please provide as much detail as possible. Screenshots can be very useful to see the problem.
* Use proper markdown syntax to structure your post (i.e. code/log in code blocks).
See: https://help.github.com/articles/basic-writing-and-formatting-syntax/
* Include a link to your **FULL** log file that has the error(not just a few lines!).
Please use [Gist](http://gist.github.com) or [Pastebin](http://pastebin.com/).
Feature Requests:
* Feature requests are handled on FeatHub: http://feathub.com/Tautulli/Tautulli
* Do not post them on the GitHub issues tracker.
-->
**Version:**
**Branch:**
**Commit hash:**
**Operating system:**
**Python version:**
**What you did?**
**What happened?**
**What you expected?**
**How can we reproduce your issue?**
<!-- Provide a detailed step-by-step. -->
**What are your (relevant) settings?**
**Link to logs:**
<!--
Close your issue when it's solved! If you found the solution yourself please comment so that others benefit from it.
-->

228
PlexPy.py
View File

@@ -1,232 +1,28 @@
#!/usr/bin/env python #!/bin/sh
''''which python >/dev/null 2>&1 && exec python "$0" "$@" # '''
''''which python2 >/dev/null 2>&1 && exec python2 "$0" "$@" # '''
''''which python2.7 >/dev/null 2>&1 && exec python2.7 "$0" "$@" # '''
''''exec echo "Error: Python not found!" # '''
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# This file is part of PlexPy. # This file is part of Tautulli.
# #
# PlexPy is free software: you can redistribute it and/or modify # Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# PlexPy is distributed in the hope that it will be useful, # Tautulli is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>. # along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
import os from Tautulli import main
import sys
# Ensure lib added to path, before any other imports # Call main() from Tautulli.py
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'lib/'))
from plexpy import webstart, logger, web_socket
import locale
import time
import signal
import argparse
import plexpy
# Register signals, such as CTRL + C
signal.signal(signal.SIGINT, plexpy.sig_handler)
signal.signal(signal.SIGTERM, plexpy.sig_handler)
def main():
"""
PlexPy application entry point. Parses arguments, setups encoding and
initializes the application.
"""
# Fixed paths to PlexPy
if hasattr(sys, 'frozen'):
plexpy.FULL_PATH = os.path.abspath(sys.executable)
else:
plexpy.FULL_PATH = os.path.abspath(__file__)
plexpy.PROG_DIR = os.path.dirname(plexpy.FULL_PATH)
plexpy.ARGS = sys.argv[1:]
# From sickbeard
plexpy.SYS_PLATFORM = sys.platform
plexpy.SYS_ENCODING = None
try:
locale.setlocale(locale.LC_ALL, "")
plexpy.SYS_ENCODING = locale.getpreferredencoding()
except (locale.Error, IOError):
pass
# for OSes that are poorly configured I'll just force UTF-8
if not plexpy.SYS_ENCODING or plexpy.SYS_ENCODING in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
plexpy.SYS_ENCODING = 'UTF-8'
# Set up and gather command line arguments
parser = argparse.ArgumentParser(
description='A Python based monitoring and tracking tool for Plex Media Server.')
parser.add_argument(
'-v', '--verbose', action='store_true', help='Increase console logging verbosity')
parser.add_argument(
'-q', '--quiet', action='store_true', help='Turn off console logging')
parser.add_argument(
'-d', '--daemon', action='store_true', help='Run as a daemon')
parser.add_argument(
'-p', '--port', type=int, help='Force PlexPy to run on a specified port')
parser.add_argument(
'--datadir', help='Specify a directory where to store your data files')
parser.add_argument('--config', help='Specify a config file to use')
parser.add_argument('--nolaunch', action='store_true',
help='Prevent browser from launching on startup')
parser.add_argument(
'--pidfile', help='Create a pid file (only relevant when running as a daemon)')
args = parser.parse_args()
if args.verbose:
plexpy.VERBOSE = True
if args.quiet:
plexpy.QUIET = True
# Do an intial setup of the logger.
logger.initLogger(console=not plexpy.QUIET, log_dir=False,
verbose=plexpy.VERBOSE)
if args.daemon:
if sys.platform == 'win32':
sys.stderr.write(
"Daemonizing not supported under Windows, starting normally\n")
else:
plexpy.DAEMON = True
plexpy.QUIET = True
if args.pidfile:
plexpy.PIDFILE = str(args.pidfile)
# If the pidfile already exists, plexpy may still be running, so
# exit
if os.path.exists(plexpy.PIDFILE):
raise SystemExit("PID file '%s' already exists. Exiting." %
plexpy.PIDFILE)
# The pidfile is only useful in daemon mode, make sure we can write the
# file properly
if plexpy.DAEMON:
plexpy.CREATEPID = True
try:
with open(plexpy.PIDFILE, 'w') as fp:
fp.write("pid\n")
except IOError as e:
raise SystemExit("Unable to write PID file: %s", e)
else:
logger.warn("Not running in daemon mode. PID file creation " \
"disabled.")
# Determine which data directory and config file to use
if args.datadir:
plexpy.DATA_DIR = args.datadir
else:
plexpy.DATA_DIR = plexpy.PROG_DIR
if args.config:
config_file = args.config
else:
config_file = os.path.join(plexpy.DATA_DIR, 'config.ini')
# Try to create the DATA_DIR if it doesn't exist
if not os.path.exists(plexpy.DATA_DIR):
try:
os.makedirs(plexpy.DATA_DIR)
except OSError:
raise SystemExit(
'Could not create data directory: ' + plexpy.DATA_DIR + '. Exiting....')
# Make sure the DATA_DIR is writeable
if not os.access(plexpy.DATA_DIR, os.W_OK):
raise SystemExit(
'Cannot write to the data directory: ' + plexpy.DATA_DIR + '. Exiting...')
# Put the database in the DATA_DIR
plexpy.DB_FILE = os.path.join(plexpy.DATA_DIR, 'plexpy.db')
if plexpy.DAEMON:
plexpy.daemonize()
# Read config and start logging
plexpy.initialize(config_file)
# Force the http port if neccessary
if args.port:
http_port = args.port
logger.info('Using forced web server port: %i', http_port)
else:
http_port = int(plexpy.CONFIG.HTTP_PORT)
# Check if pyOpenSSL is installed. It is required for certificate generation
# and for CherryPy.
if plexpy.CONFIG.ENABLE_HTTPS:
try:
import OpenSSL
except ImportError:
logger.warn("The pyOpenSSL module is missing. Install this " \
"module to enable HTTPS. HTTPS will be disabled.")
plexpy.CONFIG.ENABLE_HTTPS = False
# Try to start the server. Will exit here is address is already in use.
web_config = {
'http_port': http_port,
'http_host': plexpy.CONFIG.HTTP_HOST,
'http_root': plexpy.CONFIG.HTTP_ROOT,
'http_proxy': plexpy.CONFIG.HTTP_PROXY,
'enable_https': plexpy.CONFIG.ENABLE_HTTPS,
'https_cert': plexpy.CONFIG.HTTPS_CERT,
'https_key': plexpy.CONFIG.HTTPS_KEY,
'http_username': plexpy.CONFIG.HTTP_USERNAME,
'http_password': plexpy.CONFIG.HTTP_PASSWORD,
}
webstart.initialize(web_config)
# Start the background threads
plexpy.start()
# Open connection for websocket
if plexpy.CONFIG.MONITORING_USE_WEBSOCKET:
try:
web_socket.start_thread()
except:
logger.warn(u"Websocket :: Unable to open connection.")
# Fallback to polling
plexpy.POLLING_FAILOVER = True
plexpy.initialize_scheduler()
# Open webbrowser
if plexpy.CONFIG.LAUNCH_BROWSER and not args.nolaunch:
plexpy.launch_browser(plexpy.CONFIG.HTTP_HOST, http_port,
plexpy.CONFIG.HTTP_ROOT)
# Wait endlessy for a signal to happen
while True:
if not plexpy.SIGNAL:
try:
time.sleep(1)
except KeyboardInterrupt:
plexpy.SIGNAL = 'shutdown'
else:
logger.info('Received signal: %s', plexpy.SIGNAL)
if plexpy.SIGNAL == 'shutdown':
plexpy.shutdown()
elif plexpy.SIGNAL == 'restart':
plexpy.shutdown(restart=True)
else:
plexpy.shutdown(restart=True, update=True)
plexpy.SIGNAL = None
# Call main()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -1,14 +1,15 @@
# PlexPy # Tautulli
[![Join the chat at https://gitter.im/drzoidberg33/plexpy](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/drzoidberg33/plexpy?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Discord](https://img.shields.io/badge/Discord-Tautulli-7289DA.svg?style=flat-square)](https://tautulli.com/discord)
[![Reddit](https://img.shields.io/badge/Reddit-Tautulli-FF5700.svg?style=flat-square)](https://www.reddit.com/r/Tautulli/)
[![Plex Forums](https://img.shields.io/badge/Plex%20Forums-Tautulli-E5A00D.svg?style=flat-square)](https://forums.plex.tv/discussion/307821/tautulli-monitor-your-plex-media-server)
A python based web application for monitoring, analytics and notifications for Plex Media Server (www.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).
* PlexPy [forum thread](https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program)
## Features ## Features
* Responsive web design viewable on desktop, tablet and mobile web browsers. * Responsive web design viewable on desktop, tablet and mobile web browsers.
* Themed to complement Plex/Web. * Themed to complement Plex/Web.
* Easy configuration setup (no separate web server required). * Easy configuration setup (no separate web server required).
@@ -24,54 +25,24 @@ This project is based on code from [Headphones](https://github.com/rembo10/headp
* Full sync list data on all users syncing items from your library. * Full sync list data on all users syncing items from your library.
* And many more!! * And many more!!
## Preview
* [Full preview gallery available on our website](https://tautulli.com)
![Tautulli Homepage](https://tautulli.com/images/screenshots/activity-compressed.jpg?v=2)
## Installation and Support ## Installation and Support
* [Installation Guides](https://github.com/drzoidberg33/plexpy/wiki/Installation) shows you how to install PlexPy. * Read the [Installation Guides](https://github.com/Tautulli/Tautulli-Wiki/wiki/Installation) for instructions to install Tautulli.
* [FAQs](https://github.com/drzoidberg33/plexpy/wiki/Frequently-Asked-Questions-(FAQ)) 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.
* Support is available on [Discord](https://tautulli.com/discord), [Reddit](https://www.reddit.com/r/Tautulli), or the [Plex Forums](https://forums.plex.tv/discussion/307821/tautulli-monitor-your-plex-media-server).
**Support** the project by implementing new features, solving support tickets and provide bug fixes. ## Issues & Feature Requests
## Issues * Please see the [Issues Repository](https://github.com/Tautulli/Tautulli-Issues).
##### Many issues can simply be solved by:
- Making sure you update to the latest version.
- Turning your device off and on again.
- Analyzing your logs, you just might find the solution yourself!
- Using the **search** function to see if this issue has already been reported/solved.
- Checking the [Wiki](https://github.com/drzoidberg33/plexpy/wiki) for
[ [Installation] ](https://github.com/drzoidberg33/plexpy/wiki/Installation) and
[ [FAQs] ](https://github.com/drzoidberg33/plexpy/wiki/Frequently-Asked-Questions-(FAQ)).
- For basic questions try asking on [Gitter](https://gitter.im/drzoidberg33/plexpy) or the [Plex Forums](https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program) first before opening an issue.
##### If nothing has worked:
1. Open a new issue on the GitHub [issue tracker](http://github.com/drzoidberg33/plexpy/issues).
2. Provide a clear title to easily help identify your problem.
3. Use proper [markdown syntax](https://help.github.com/articles/github-flavored-markdown) to structure your post (i.e. code/log in code blocks).
4. Make sure you provide the following information:
- [ ] Version
- [ ] Branch
- [ ] Commit hash
- [ ] Operating system
- [ ] Python version
- [ ] What you did?
- [ ] What happened?
- [ ] What you expected?
- [ ] How can we reproduce your issue?
- [ ] What are your (relevant) settings?
- [ ] Include a link to your **FULL** (not just a few lines!) log file that has the error. Please use [Gist](http://gist.github.com) or [Pastebin](http://pastebin.com/).
5. Close your issue when it's solved! If you found the solution yourself please comment so that others benefit from it.
## Feature Requests
1. Search for similar existing 'issues', feature requests can be recognized by the blue `enhancement` label.
2. If a similar request exists, post a comment (+1, or add a new idea to the existing request).
3. If no similar requests exist, you can create a new one.
4. Provide a clear title to easily identify the feature request.
5. Tag your feature request with `[Feature Request]` so it can be identified easily.
## License ## 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.

267
Tautulli.py Executable file
View File

@@ -0,0 +1,267 @@
#!/bin/sh
''''which python >/dev/null 2>&1 && exec python "$0" "$@" # '''
''''which python2 >/dev/null 2>&1 && exec python2 "$0" "$@" # '''
''''which python2.7 >/dev/null 2>&1 && exec python2.7 "$0" "$@" # '''
''''exec echo "Error: Python not found!" # '''
# -*- coding: utf-8 -*-
# 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/>.
import os
import sys
# Ensure lib added to path, before any other imports
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'lib/'))
import argparse
import locale
import signal
import time
import plexpy
from plexpy import config, database, logger, webstart
# Register signals, such as CTRL + C
signal.signal(signal.SIGINT, plexpy.sig_handler)
signal.signal(signal.SIGTERM, plexpy.sig_handler)
def main():
"""
Tautulli application entry point. Parses arguments, setups encoding and
initializes the application.
"""
# Fixed paths to Tautulli
if hasattr(sys, 'frozen'):
plexpy.FULL_PATH = os.path.abspath(sys.executable)
else:
plexpy.FULL_PATH = os.path.abspath(__file__)
plexpy.PROG_DIR = os.path.dirname(plexpy.FULL_PATH)
plexpy.ARGS = sys.argv[1:]
# From sickbeard
plexpy.SYS_PLATFORM = sys.platform
plexpy.SYS_ENCODING = None
try:
locale.setlocale(locale.LC_ALL, "")
plexpy.SYS_LANGUAGE, plexpy.SYS_ENCODING = locale.getdefaultlocale()
except (locale.Error, IOError):
pass
# for OSes that are poorly configured I'll just force UTF-8
if not plexpy.SYS_ENCODING or plexpy.SYS_ENCODING in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
plexpy.SYS_ENCODING = 'UTF-8'
# Set up and gather command line arguments
parser = argparse.ArgumentParser(
description='A Python based monitoring and tracking tool for Plex Media Server.')
parser.add_argument(
'-v', '--verbose', action='store_true', help='Increase console logging verbosity')
parser.add_argument(
'-q', '--quiet', action='store_true', help='Turn off console logging')
parser.add_argument(
'-d', '--daemon', action='store_true', help='Run as a daemon')
parser.add_argument(
'-p', '--port', type=int, help='Force Tautulli to run on a specified port')
parser.add_argument(
'--dev', action='store_true', help='Start Tautulli in the development environment')
parser.add_argument(
'--datadir', help='Specify a directory where to store your data files')
parser.add_argument(
'--config', help='Specify a config file to use')
parser.add_argument(
'--nolaunch', action='store_true', help='Prevent browser from launching on startup')
parser.add_argument(
'--pidfile', help='Create a pid file (only relevant when running as a daemon)')
parser.add_argument(
'--nofork', action='store_true', help='Start Tautulli as a service, do not fork when restarting')
args = parser.parse_args()
if args.verbose:
plexpy.VERBOSE = True
if args.quiet:
plexpy.QUIET = True
# Do an intial setup of the logger.
logger.initLogger(console=not plexpy.QUIET, log_dir=False,
verbose=plexpy.VERBOSE)
if args.dev:
plexpy.DEV = True
logger.debug(u"Tautulli is running in the dev environment.")
if args.daemon:
if sys.platform == 'win32':
sys.stderr.write(
"Daemonizing not supported under Windows, starting normally\n")
else:
plexpy.DAEMON = True
plexpy.QUIET = True
if args.nofork:
plexpy.NOFORK = True
logger.info("Tautulli is running as a service, it will not fork when restarted.")
if args.pidfile:
plexpy.PIDFILE = str(args.pidfile)
# If the pidfile already exists, plexpy may still be running, so
# exit
if os.path.exists(plexpy.PIDFILE):
try:
with open(plexpy.PIDFILE, 'r') as fp:
pid = int(fp.read())
os.kill(pid, 0)
except IOError as e:
raise SystemExit("Unable to read PID file: %s", e)
except OSError:
logger.warn("PID file '%s' already exists, but PID %d is " \
"not running. Ignoring PID file." %
(plexpy.PIDFILE, pid))
else:
# The pidfile exists and points to a live PID. plexpy may
# still be running, so exit.
raise SystemExit("PID file '%s' already exists. Exiting." %
plexpy.PIDFILE)
# The pidfile is only useful in daemon mode, make sure we can write the
# file properly
if plexpy.DAEMON:
plexpy.CREATEPID = True
try:
with open(plexpy.PIDFILE, 'w') as fp:
fp.write("pid\n")
except IOError as e:
raise SystemExit("Unable to write PID file: %s", e)
else:
logger.warn("Not running in daemon mode. PID file creation " \
"disabled.")
# Determine which data directory and config file to use
if args.datadir:
plexpy.DATA_DIR = args.datadir
else:
plexpy.DATA_DIR = plexpy.PROG_DIR
if args.config:
config_file = args.config
else:
config_file = os.path.join(plexpy.DATA_DIR, config.FILENAME)
# Try to create the DATA_DIR if it doesn't exist
if not os.path.exists(plexpy.DATA_DIR):
try:
os.makedirs(plexpy.DATA_DIR)
except OSError:
raise SystemExit(
'Could not create data directory: ' + plexpy.DATA_DIR + '. Exiting....')
# Make sure the DATA_DIR is writeable
if not os.access(plexpy.DATA_DIR, os.W_OK):
raise SystemExit(
'Cannot write to the data directory: ' + plexpy.DATA_DIR + '. Exiting...')
# Put the database in the DATA_DIR
plexpy.DB_FILE = os.path.join(plexpy.DATA_DIR, database.FILENAME)
# Move 'plexpy.db' to 'tautulli.db'
if os.path.isfile(os.path.join(plexpy.DATA_DIR, 'plexpy.db')) and \
not os.path.isfile(os.path.join(plexpy.DATA_DIR, plexpy.DB_FILE)):
try:
os.rename(os.path.join(plexpy.DATA_DIR, 'plexpy.db'), plexpy.DB_FILE)
except OSError as e:
raise SystemExit("Unable to rename plexpy.db to tautulli.db: %s", e)
if plexpy.DAEMON:
plexpy.daemonize()
# Read config and start logging
plexpy.initialize(config_file)
# Start the background threads
plexpy.start()
# Force the http port if neccessary
if args.port:
http_port = args.port
logger.info('Using forced web server port: %i', http_port)
else:
http_port = int(plexpy.CONFIG.HTTP_PORT)
# Check if pyOpenSSL is installed. It is required for certificate generation
# and for CherryPy.
if plexpy.CONFIG.ENABLE_HTTPS:
try:
import OpenSSL
except ImportError:
logger.warn("The pyOpenSSL module is missing. Install this " \
"module to enable HTTPS. HTTPS will be disabled.")
plexpy.CONFIG.ENABLE_HTTPS = False
# Try to start the server. Will exit here is address is already in use.
web_config = {
'http_port': http_port,
'http_host': plexpy.CONFIG.HTTP_HOST,
'http_root': plexpy.CONFIG.HTTP_ROOT,
'http_environment': plexpy.CONFIG.HTTP_ENVIRONMENT,
'http_proxy': plexpy.CONFIG.HTTP_PROXY,
'enable_https': plexpy.CONFIG.ENABLE_HTTPS,
'https_cert': plexpy.CONFIG.HTTPS_CERT,
'https_cert_chain': plexpy.CONFIG.HTTPS_CERT_CHAIN,
'https_key': plexpy.CONFIG.HTTPS_KEY,
'http_username': plexpy.CONFIG.HTTP_USERNAME,
'http_password': plexpy.CONFIG.HTTP_PASSWORD,
'http_basic_auth': plexpy.CONFIG.HTTP_BASIC_AUTH
}
webstart.initialize(web_config)
# Open webbrowser
if plexpy.CONFIG.LAUNCH_BROWSER and not args.nolaunch and not plexpy.DEV:
plexpy.launch_browser(plexpy.CONFIG.HTTP_HOST, http_port,
plexpy.CONFIG.HTTP_ROOT)
# Wait endlessy for a signal to happen
while True:
if not plexpy.SIGNAL:
try:
time.sleep(1)
except KeyboardInterrupt:
plexpy.SIGNAL = 'shutdown'
else:
logger.info('Received signal: %s', plexpy.SIGNAL)
if plexpy.SIGNAL == 'shutdown':
plexpy.shutdown()
elif plexpy.SIGNAL == 'restart':
plexpy.shutdown(restart=True)
elif plexpy.SIGNAL == 'checkout':
plexpy.shutdown(restart=True, checkout=True)
else:
plexpy.shutdown(restart=True, update=True)
plexpy.SIGNAL = None
# Call main()
if __name__ == "__main__":
main()

View File

@@ -2,11 +2,18 @@
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
<h4 class="modal-title">Import PlexWatch Database</h4> <h4 class="modal-title">Import ${app} Database</h4>
</div> </div>
<div class="modal-body" id="modal-text"> <div class="modal-body" id="modal-text">
<p class="help-block"> <p class="help-block">
Please ensure your PlexWatch database is at version 0.3.2 or higher. <%
v = ''
if app == 'PlexWatch':
v = '0.3.2'
elif app == 'Plexivity':
v = '0.9.8'
%>
<strong>Please ensure your ${app} database is at version ${v} or higher.</strong>
</p> </p>
<div class="form-group"> <div class="form-group">
<label for="db_location">Database Location</label> <label for="db_location">Database Location</label>
@@ -15,7 +22,7 @@
<input type="text" class="form-control" id="db_location" name="db_location" value="" required> <input type="text" class="form-control" id="db_location" name="db_location" value="" required>
</div> </div>
</div> </div>
<p class="help-block">Enter the path and file name for the PlexWatch database you wish to import.</p> <p class="help-block">Enter the path and file name for the ${app} database you wish to import.</p>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="table_name">Table Name</label> <label for="table_name">Table Name</label>
@@ -23,7 +30,7 @@
<div class="col-xs-4"> <div class="col-xs-4">
<select id="table_name" class="form-control" name="table_name"> <select id="table_name" class="form-control" name="table_name">
<option value="processed">processed</option> <option value="processed">processed</option>
<option value="processed">grouped</option> <option value="grouped">grouped</option>
</select> </select>
</div> </div>
</div> </div>
@@ -41,7 +48,7 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<div> <div>
<span id="status-message"></span> <span id="status-message" style="padding-right: 25px;"></span>
<input type="button" id="import_db" class="btn btn-bright" value="Import"> <input type="button" id="import_db" class="btn btn-bright" value="Import">
</div> </div>
</div> </div>
@@ -54,8 +61,13 @@
var table_name = $("#table_name").val(); var table_name = $("#table_name").val();
var import_ignore_interval = $("#import_ignore_interval").val(); var import_ignore_interval = $("#import_ignore_interval").val();
$.ajax({ $.ajax({
url: 'get_plexwatch_export_data', url: 'import_database',
data: {database_path: database_path, table_name:table_name, import_ignore_interval:import_ignore_interval}, data: {
app: "${app}",
database_path: database_path,
table_name: table_name,
import_ignore_interval: import_ignore_interval
},
cache: false, cache: false,
async: true, async: true,
success: function(data) { success: function(data) {

View File

@@ -1,151 +1,67 @@
<% <%
import plexpy import plexpy
from plexpy import version from plexpy import version
from plexpy.helpers import anon_url
from plexpy.notifiers import BROWSER_NOTIFIERS
%> %>
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>PlexPy - ${title} | ${server_name}</title> <title>Tautulli - ${title} | ${server_name}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content=""> <meta name="description" content="">
<meta name="author" content=""> <meta name="author" content="">
<link href="interfaces/default/css/bootstrap3/bootstrap.css" rel="stylesheet"> <link href="${http_root}css/bootstrap3/bootstrap.css" rel="stylesheet">
<link href="interfaces/default/css/plexpy.css" rel="stylesheet"> <link href="${http_root}css/pnotify.custom.min.css" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css"> <link href="${http_root}css/tautulli.css${cache_param}" rel="stylesheet">
<link href="interfaces/default/css/font-awesome.min.css" rel="stylesheet"> <link href="${http_root}css/opensans.min.css" rel="stylesheet">
${next.headIncludes()} ${next.headIncludes()}
<link rel="icon" type="image/x-icon" href="interfaces/default/images/favicon.ico"/> <!-- Favicons -->
<link rel="shortcut icon" href="interfaces/default/images/favicon.png"> <link rel="icon" type="image/png" sizes="32x32" href="${http_root}images/favicon/favicon-32x32.png?v=2.0.5">
<link rel="icon" type="image/png" sizes="16x16" href="${http_root}images/favicon/favicon-16x16.png?v=2.0.5">
<!-- Allow web app to be run in full-screen mode. --> <link rel="shortcut icon" href="${http_root}images/favicon/favicon.ico?v=2.0.5">
<meta name="apple-mobile-web-app-capable" content="yes">
<!-- Configure the status bar. -->
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<!-- Set the viewport. -->
<meta name="viewport" content="initial-scale=1">
<!-- Disable automatic phone number detection. -->
<meta name="format-detection" content="telephone=no">
<!-- ICONS --> <!-- ICONS -->
<!-- IE10 icon --> <!-- Android -->
<meta name="application-name" content="PlexPy" /> <link rel="manifest" href="${http_root}images/favicon/manifest.json?v=2.0.5">
<meta name="msapplication-config" content="interfaces/default/xml/IEconfig.xml"/> <meta name="theme-color" content="#282a2d">
<!-- Android >M39 icon --> <!-- Apple -->
<link rel="manifest" href="interfaces/default/json/Android-manifest.json"> <link rel="apple-touch-icon" sizes="180x180" href="${http_root}images/favicon/apple-touch-icon.png?v=2.0.5">
<!-- iPad retina icon --> <link rel="mask-icon" href="${http_root}images/favicon/safari-pinned-tab.svg?v=2.0.5" color="#282a2d">
<link href="interfaces/default/images/res/ios/icon-76@2x.png" sizes="152x152" rel="apple-touch-icon-precomposed"> <meta name="apple-mobile-web-app-title" content="Tautulli">
<!-- iPad retina icon (iOS < 7) --> <!-- Microsoft -->
<link href="interfaces/default/images/res/ios/icon-72@2x.png" sizes="144x144" rel="apple-touch-icon-precomposed"> <meta name="application-name" content="Tautulli">
<!-- iPad non-retina icon --> <meta name="msapplication-config" content="${http_root}images/favicon/browserconfig.xml?v=2.0.5">
<link href="interfaces/default/images/res/ios/icon-76.png" sizes="76x76" rel="apple-touch-icon-precomposed">
<!-- iPad non-retina icon (iOS < 7) -->
<link href="interfaces/default/images/res/ios/icon-72.png" sizes="72x72" rel="apple-touch-icon-precomposed">
<!-- iPhone 6 Plus icon -->
<link href="interfaces/default/images/res/ios/icon-60@2x.png" sizes="120x120" rel="apple-touch-icon-precomposed">
<!-- iPhone retina icon (iOS < 7) -->
<link href="interfaces/default/images/res/ios/icon@2x.png" sizes="114x114" rel="apple-touch-icon-precomposed">
<!-- iPhone non-retina icon (iOS < 7) -->
<link href="interfaces/default/images/res/ios/icon.png" sizes="57x57" rel="apple-touch-icon-precomposed">
<!-- iPhone / iPod Touch -->
<link href="interfaces/default/images/res/ios/icon-60@3x.png" sizes="180x180" rel="apple-touch-icon-precomposed">
<link href="interfaces/default/images/res/ios/icon-60.png" sizes="60x60" rel="apple-touch-icon-precomposed">
<!-- Spotlight Icon -->
<link href="interfaces/default/images/res/ios/icon-40.png" sizes="40x40" rel="apple-touch-icon-precomposed">
<link href="interfaces/default/images/res/ios/icon-40@2x.png" sizes="80x80" rel="apple-touch-icon-precomposed">
<!-- iPhone Spotlight and Settings Icon -->
<link href="interfaces/default/images/res/ios/icon-small.png" sizes="29x29" rel="apple-touch-icon-precomposed">
<link href="interfaces/default/images/res/ios/icon-small@2x.png" sizes="58x58" rel="apple-touch-icon-precomposed">
<!-- iPad Spotlight and Settings Icon -->
<link href="interfaces/default/images/res/ios/icon-50.png" sizes="50x50" rel="apple-touch-icon-precomposed">
<link href="interfaces/default/images/res/ios/icon-50@2x.png" sizes="100x100" rel="apple-touch-icon-precomposed">
<!-- STARTUP IMAGES -->
<!-- iPad retina portrait startup image -->
<link href="interfaces/default/images/res/screen/ios/Default-Portrait@2x~ipad.png"
media="(device-width: 768px) and (device-height: 1024px)
and (-webkit-device-pixel-ratio: 2)
and (orientation: portrait)"
rel="apple-touch-startup-image">
<!-- iPad retina landscape startup image -->
<link href="interfaces/default/images/res/screen/ios/Default-Landscape@2x~ipad.png"
media="(device-width: 768px) and (device-height: 1024px)
and (-webkit-device-pixel-ratio: 2)
and (orientation: landscape)"
rel="apple-touch-startup-image">
<!-- iPad non-retina portrait startup image -->
<link href="interfaces/default/images/res/screen/ios/Default-Portrait~ipad.png"
media="(device-width: 768px) and (device-height: 1024px)
and (-webkit-device-pixel-ratio: 1)
and (orientation: portrait)"
rel="apple-touch-startup-image">
<!-- iPad non-retina landscape startup image -->
<link href="interfaces/default/images/res/screen/ios/Default-Landscape~ipad.png"
media="(device-width: 768px) and (device-height: 1024px)
and (-webkit-device-pixel-ratio: 1)
and (orientation: landscape)"
rel="apple-touch-startup-image">
<!-- iPhone 6 Plus portrait startup image -->
<link href="interfaces/default/images/res/screen/ios/Default-736h.png"
media="(device-width: 414px) and (device-height: 736px)
and (-webkit-device-pixel-ratio: 3)
and (orientation: portrait)"
rel="apple-touch-startup-image">
<!-- iPhone 6 Plus landscape startup image -->
<link href="interfaces/default/images/res/screen/ios/Default-Landscape-736h.png"
media="(device-width: 414px) and (device-height: 736px)
and (-webkit-device-pixel-ratio: 3)
and (orientation: landscape)"
rel="apple-touch-startup-image">
<!-- iPhone 6 startup image -->
<link href="interfaces/default/images/res/screen/ios/Default-667h.png"
media="(device-width: 375px) and (device-height: 667px)
and (-webkit-device-pixel-ratio: 2)"
rel="apple-touch-startup-image">
<!-- iPhone 5 startup image -->
<link href="interfaces/default/images/res/screen/ios/Default-568h@2x~iphone5.jpg"
media="(device-width: 320px) and (device-height: 568px)
and (-webkit-device-pixel-ratio: 2)"
rel="apple-touch-startup-image">
<!-- iPhone < 5 retina startup image -->
<link href="interfaces/default/images/res/screen/ios/Default@2x~iphone.png"
media="(device-width: 320px) and (device-height: 480px)
and (-webkit-device-pixel-ratio: 2)"
rel="apple-touch-startup-image">
<!-- iPhone < 5 non-retina startup image -->
<link href="interfaces/default/images/res/screen/ios/Default~iphone.png"
media="(device-width: 320px) and (device-height: 480px)
and (-webkit-device-pixel-ratio: 1)"
rel="apple-touch-startup-image">
</head> </head>
<body class="content"> <body class="content">
<div class="container"> <div class="container">
<div id="ajaxMsg" class="ajaxMsg"></div> <div id="ajaxMsg" class="ajaxMsg"></div>
% if _session['user_group'] == 'admin':
% if plexpy.CONFIG.CHECK_GITHUB and not plexpy.CURRENT_VERSION: % if plexpy.CONFIG.CHECK_GITHUB and not plexpy.CURRENT_VERSION:
<div id="updatebar" style="display: none;"> <div id="updatebar" style="display: none;">
You're running an unknown version of PlexPy. <a href="update">Update</a> or You are running an unknown version of Tautulli.<br />
<a href="#" id="updateDismiss">Close</a> <a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>
</div> </div>
% elif plexpy.CONFIG.CHECK_GITHUB and plexpy.CURRENT_VERSION != plexpy.LATEST_VERSION and plexpy.COMMITS_BEHIND > 0 and plexpy.INSTALL_TYPE != 'win': % elif plexpy.CONFIG.CHECK_GITHUB and plexpy.COMMITS_BEHIND > 0 and plexpy.common.BRANCH in ('master', 'beta') and plexpy.common.RELEASE != plexpy.LATEST_RELEASE:
<div id="updatebar" style="display: none;"> <div id="updatebar" style="display: none;">
A <a 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">
href="https://github.com/${plexpy.CONFIG.GIT_USER}/plexpy/compare/${plexpy.CURRENT_VERSION}...${plexpy.LATEST_VERSION}" target="_blank"> new release (${plexpy.LATEST_RELEASE})</a> of Tautulli is available!<br />
newer version</a> is available. You're ${plexpy.COMMITS_BEHIND} commits behind. <a href="update">Update</a> or <a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>
<a href="#" id="updateDismiss">Close</a>
</div> </div>
% elif plexpy.CONFIG.CHECK_GITHUB and plexpy.COMMITS_BEHIND > 0 and plexpy.CURRENT_VERSION != plexpy.LATEST_VERSION and plexpy.INSTALL_TYPE != 'win':
<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">
newer version</a> of Tautulli is available!<br />
You are ${plexpy.COMMITS_BEHIND} commit${'s' if plexpy.COMMITS_BEHIND > 1 else ''} behind.<br />
<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>
</div>
% else:
<div id="updatebar" style="display: none;"></div>
% endif
% endif % endif
<nav class="navbar navbar-fixed-top"> <nav class="navbar navbar-fixed-top">
<div class="container-fluid"> <div class="container-fluid">
@@ -156,8 +72,8 @@ from plexpy import version
<span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
</button> </button>
<a class="navbar-brand" href="home"> <a class="navbar-brand" href="home" title="Tautulli">
<img alt="PlexPy" src="interfaces/default/images/logo-plexpy@2x.png" height="40"> <img src="${http_root}images/logo-tautulli-45.png" height="45" alt="PlexPy">
</a> </a>
</div> </div>
<div class="collapse navbar-collapse navbar-right" id="navbar-collapse-1"> <div class="collapse navbar-collapse navbar-right" id="navbar-collapse-1">
@@ -166,7 +82,7 @@ from plexpy import version
<form action="search" method="post" class="form" id="search_form"> <form action="search" method="post" class="form" id="search_form">
<div class="input-group"> <div class="input-group">
<span class="input-textbox"> <span class="input-textbox">
<input type="text" class="form-control" name="query" id="query" aria-label="Search" placeholder="Search..."/> <input type="text" class="form-control" name="query" id="query" aria-label="Search" placeholder="Search Plex library..."/>
</span> </span>
<span class="input-group-btn"> <span class="input-group-btn">
<button class="btn btn-dark btn-inactive" type="submit" id="search_button"><i class="fa fa-search"></i></button> <button class="btn btn-dark btn-inactive" type="submit" id="search_button"><i class="fa fa-search"></i></button>
@@ -175,9 +91,9 @@ from plexpy import version
</form> </form>
</li> </li>
% if title == "Home": % if title == "Home":
<li class="active"><a href="home"><i class="fa fa-lg fa-home"></i></a></li> <li class="active"><a href="home"><i class="fa fa-lg fa-home"></i></a></li>
% else: % else:
<li><a href="home"><i class="fa fa-lg fa-home"></i></a></li> <li><a href="home"><i class="fa fa-lg fa-home"></i></a></li>
% endif % endif
% if title == "Libraries" or title == "Library" or title == "Info": % if title == "Libraries" or title == "Library" or title == "Info":
<li class="active"><a href="libraries">Libraries</a></li> <li class="active"><a href="libraries">Libraries</a></li>
@@ -185,9 +101,9 @@ from plexpy import version
<li><a href="libraries">Libraries</a></li> <li><a href="libraries">Libraries</a></li>
% endif % endif
% if title == "Users" or title == "User": % if title == "Users" or title == "User":
<li class="active"><a href="users">Users</a></li> <li class="active"><a href="users">Users</a></li>
% else: % else:
<li><a href="users">Users</a></li> <li><a href="users">Users</a></li>
% endif % endif
% if title == "History": % if title == "History":
<li class="active"><a href="history">History</a></li> <li class="active"><a href="history">History</a></li>
@@ -195,25 +111,46 @@ from plexpy import version
<li><a href="history">History</a></li> <li><a href="history">History</a></li>
% endif % endif
% if title == "Graphs": % if title == "Graphs":
<li class="active"><a href="graphs">Graphs</a></li> <li class="active"><a href="graphs">Graphs</a></li>
% else: % else:
<li><a href="graphs">Graphs</a></li> <li><a href="graphs">Graphs</a></li>
% endif % endif
% if title == "Synced Items": % if title == "Synced Items":
<li class="active"><a href="sync">Synced Items</a></li> <li class="active"><a href="sync">Synced Items</a></li>
% else: % else:
<li><a href="sync">Synced Items</a></li> <li><a href="sync">Synced Items</a></li>
% endif
% if title == "Log":
<li class="active"><a href="logs">Logs</a></li>
% else:
<li><a href="logs">Logs</a></li>
% endif % endif
% if title == "Settings": % if title == "Settings":
<li class="active"><a href="settings">Settings</a></li> <li class="dropdown active">
% else: % else:
<li><a href="settings">Settings</a></li> <li class="dropdown">
% endif % endif
<% href = 'settings' if _session['user_group'] == 'admin' else '#' %>
<a href="#" class="dropdown-toggle" aria-haspopup="true" data-toggle="dropdown" data-hover="dropdown" data-href="${href}"><i class="fa fa-lg fa-cogs"></i> <span class="caret"></span></a>
<ul class="dropdown-menu" id="settings-dropdown-menu">
% if _session['user_group'] == 'admin':
<li><a href="settings"><i class="fa fa-fw fa-cogs"></i> Settings</a></li>
<li role="separator" class="divider"></li>
<li><a href="logs"><i class="fa fa-fw fa-list-alt"></i> View Logs</a></li>
<li><a href="${anon_url('https://github.com/%s/%s-Wiki/wiki/Frequently-Asked-Questions' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO))}" target="_blank"><i class="fa fa-fw fa-question-circle"></i> FAQ</a></li>
<li><a href="support"><i class="fa fa-fw fa-comment"></i> Support</a></li>
<li role="separator" class="divider"></li>
<li><a href="#" data-target="#donate-modal" data-toggle="modal"><i class="fa fa-fw fa-heart"></i> Donate</a></li>
<li role="separator" class="divider"></li>
% if plexpy.CONFIG.CHECK_GITHUB:
<li><a href="#" id="nav-update"><i class="fa fa-fw fa-arrow-circle-up"></i> Check for Updates</a></li>
% endif
<li><a href="#" id="nav-restart"><i class="fa fa-fw fa-refresh"></i> Restart</a></li>
<li><a href="#" id="nav-shutdown"><i class="fa fa-fw fa-power-off"></i> Shutdown</a></li>
% else:
<li><a href="#" data-target="#admin-login-modal" data-toggle="modal"><i class="fa fa-fw fa-lock"></i> Admin Login</a></li>
<li role="separator" class="divider"></li>
% endif
% if _session['exp']:
<li><a href="${http_root}auth/logout"><i class="fa fa-fw fa-sign-out"></i> Sign Out</a></li>
% endif
</ul>
</li>
</ul> </ul>
</div> </div>
</div> </div>
@@ -221,25 +158,231 @@ from plexpy import version
</div> </div>
${next.headerIncludes()} ${next.headerIncludes()}
<div class="body-container"> <div class="body-container">
${next.body()} ${next.body()}
</div> </div>
<script src="interfaces/default/js/jquery-2.1.4.min.js"></script> ${next.modalIncludes()}
<script src="interfaces/default/js/bootstrap3/bootstrap.min.js"></script>
<script src="interfaces/default/js/script.js"></script> % if _session['user_group'] != 'admin':
<div id="admin-login-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="admin-login-modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form id="login-form">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
<h4 class="modal-title">Admin Login</h4>
</div>
<div class="modal-body">
<div class="col-md-6" style="margin: auto;">
<div class="form-group">
<label for="username" class="control-label">
Username
</label>
<input type="text" id="username" name="username" class="form-control" autocorrect="off" autocapitalize="off">
</div>
<div class="form-group">
<label for="password" class="control-label">
Password
</label>
<input type="password" id="password" name="password" class="form-control">
</div>
<div class="form-footer">
<div class="remember-group">
<label class="control-label">
<input type="checkbox" id="remember_me" name="remember_me" title="for 30 days" value="1" checked="checked" /> Remember me
</label>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<span id="incorrect-login" style="padding-right: 25px; display: none;">Incorrect username or password.</span>
<button id="sign-in" type="submit" class="btn btn-bright login-button"><i class="fa fa-sign-in"></i>&nbsp; Sign In</button>
</div>
<input type="hidden" id="admin_login" name="admin_login" value="1" />
</form>
</div>
</div>
</div>
% else:
<div id="donate-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="crypto-donate-modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
<h4 class="modal-title">Tautulli Donation</h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-12" style="text-align: center;">
<h4>
<strong>Thank you for supporting Tautulli!</strong>
</h4>
<p>
Please select a donation method.
</p>
</div>
</div>
<ul id="donation_type" class="nav nav-pills" role="tablist" style="display: flex; justify-content: center; margin: 10px 0;">
<li class="active"><a href="#patreon-donation" role="tab" data-toggle="tab">Patreon</a></li>
<li><a href="#paypal-donation" role="tab" data-toggle="tab">PayPal</a></li>
<li><a href="#crypto-donation" role="tab" data-toggle="tab" class="crypto-donation" data-coin="bitcoin" data-name="Bitcoin" data-address="3FdfJAyNWU15Sf11U9FTgPHuP1hPz32eEN">Bitcoin</a></li>
<li><a href="#crypto-donation" role="tab" data-toggle="tab" class="crypto-donation" data-coin="bitcoincash" data-name="Bitcoin Cash" data-address="1H2atabxAQGaFAWYQEiLkXKSnK9CZZvt2n">Bitcoin Cash</a></li>
<li><a href="#crypto-donation" role="tab" data-toggle="tab" class="crypto-donation" data-coin="ethereum" data-name="Ethereum" data-address="0x77ae4c2b8de1a1ccfa93553db39971da58c873d3">Ethereum</a></li>
<li><a href="#crypto-donation" role="tab" data-toggle="tab" class="crypto-donation" data-coin="litecoin" data-name="Litecoin" data-address="LWpPmUqQYHBhMV83XSCsHzPmKLhJt6r57J">Litecoin</a></li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="patreon-donation" style="text-align: center">
<p>
Click the button below to continue to Patreon.
</p>
<a href="${anon_url('https://www.patreon.com/bePatron?u=10078609')}" target="_blank">
<img src="images/become_a_patron_button.png" alt="Become a Patron" height="40">
</a>
</div>
<div role="tabpanel" class="tab-pane" id="paypal-donation" style="text-align: center">
<p>
Click the button below to continue to PayPal.
</p>
<a href="${anon_url('https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=6XPPKTDSX9QFL&lc=US&item_name=Tautulli&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted')}" target="_blank">
<img src="images/gold-rect-paypal-34px.png" alt="PayPal">
</a>
</div>
<div role="tabpanel" class="tab-pane" id="crypto-donation">
<label>QR Code</label>
<pre id="crypto_qr_code" style="text-align: center"></pre>
<label><span id="crypto_type_label"></span> Address</label>
<pre id="crypto_address" style="text-align: center"></pre>
</div>
</div>
</div>
<div class="modal-footer">
<input type="button" class="btn btn-bright" data-dismiss="modal" value="Close">
</div>
</div>
</div>
</div>
% endif
<div id="confirm-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="confirm-modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
<h4 class="modal-title">Confirm</h4>
</div>
<div class="modal-body">
<div id="confirm-message" style="text-align: center; margin-top: 20px; margin-bottom: 20px;">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-dark" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-danger btn-ok" data-dismiss="modal" id="confirm-button">Confirm</button>
</div>
</div>
</div>
</div>
<script src="${http_root}js/jquery-2.1.4.min.js"></script>
<script src="${http_root}js/bootstrap.min.js"></script>
<script src="${http_root}js/bootstrap-hover-dropdown.min.js"></script>
<script>window.FontAwesomeConfig = {searchPseudoElements: true}</script>
<script src="${http_root}js/fontawesome-v5.0.13.min.js"></script>
<script src="${http_root}js/fontawesome-v4-shims.min.js"></script>
<script src="${http_root}js/pnotify.custom.min.js"></script>
<script src="${http_root}js/script.js${cache_param}"></script>
<script src="${http_root}js/jquery.qrcode.min.js"></script>
<script src="${http_root}js/jquery.tripleclick.min.js"></script>
% if _session['user_group'] == 'admin' and BROWSER_NOTIFIERS:
<script src="${http_root}js/ajaxNotifications.js"></script>
% endif
<script> <script>
$('#updateDismiss').click(function() { % if _session['user_group'] == 'admin':
$('#updatebar').slideUp('slow'); $('body').on('click', '#updateDismiss', function() {
$('#updatebar').fadeOut();
// Set cookie to remember dismiss decision for 1 hour. // Set cookie to remember dismiss decision for 1 hour.
setCookie('updateDismiss', 'true', 1/24); setCookie('updateDismiss', 'true', 1/24);
}); });
if (!getCookie('updateDismiss')) { if (!getCookie('updateDismiss')) {
$('#updatebar').show(); if ($('#updatebar').html().length > 0) {
$('#updatebar').show();
}
} }
</script>
<script> function checkUpdate(_callback) {
// Allow the update bar to show again if previously dismissed.
setCookie('updateDismiss', 'true', 0);
$.ajax({
url: 'update_check',
complete: function (xhr, status) {
var result = $.parseJSON(xhr.responseText);
var msg = '';
if (result.update === null) {
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);
}
if (_callback) {
_callback();
}
}
});
}
$("#nav-shutdown").click(function() {
$("#confirm-message").text("Are you sure you want to shutdown Tautulli?");
$('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-button', function () {
window.location.href = "shutdown";
});
});
$("#nav-restart").click(function() {
$("#confirm-message").text("Are you sure you want to restart Tautulli?");
$('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-button', function () {
window.location.href = "restart";
});
});
$('#nav-update').click(function () {
$(this).html('<i class="fa fa-fw fa-spin fa-refresh"></i> Checking');
checkUpdate(function () { $('#nav-update').html('<i class="fa fa-fw fa-arrow-circle-up"></i> Check for Updates'); });
});
$('#donation_type a.crypto-donation').on('shown.bs.tab', function () {
var crypto_coin = $(this).data('coin');
var crypto_name = $(this).data('name');
var crypto_address = $(this).data('address')
$('#crypto_qr_code').empty().qrcode({
text: crypto_coin + ":" + crypto_address
});
$('#crypto_type_label').html(crypto_name);
$('#crypto_address').html(crypto_address);
});
% endif
$('.dropdown-toggle').click(function (e) {
if (!(('ontouchstart' in window) || (navigator.MaxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0))) {
window.location.href = $(this).data('href');
}
});
$('#search_form').submit(function (e) { $('#search_form').submit(function (e) {
if ($('#query').hasClass('active') && $('#query').val().trim() != '') { if ($('#query').hasClass('active') && $('#query').val().trim() != '') {
$.ajax({ $.ajax({
@@ -260,10 +403,9 @@ ${next.headerIncludes()}
}).removeClass('active'); }).removeClass('active');
} }
}); });
</script>
<script>
// Work around for iOS web app links opening in Safari
$(document).ready(function () { $(document).ready(function () {
// Work around for iOS web app links opening in Safari
if (("standalone" in window.navigator) && window.navigator.standalone) { if (("standalone" in window.navigator) && window.navigator.standalone) {
// For iOS Apps // For iOS Apps
$('a').on('click', function (e) { $('a').on('click', function (e) {
@@ -274,12 +416,54 @@ ${next.headerIncludes()}
} }
}); });
} }
// Allow stacked bootstrap modals
$(document).on('show.bs.modal', '.modal', function (event) {
var zIndex = 1040 + (10 * $('.modal:visible').length);
$(this).css('z-index', zIndex);
setTimeout(function() {
$('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack');
}, 0);
});
$(document).on('hidden.bs.modal', '.modal', function () {
$('.modal:visible').length && $(document.body).addClass('modal-open');
});
}); });
% if _session['user_group'] != 'admin':
$('#admin-login-modal').on('shown.bs.modal', function () {
$('#admin-login-modal #username').focus()
})
$('#login-form').submit(function(event) {
event.preventDefault();
$('#sign-in').prop('disabled', true).html('<i class="fa fa-refresh fa-spin"></i>&nbsp; Sign In');
$.ajax({
url: '${http_root}auth/signin',
type: 'POST',
data: $(this).serialize(),
dataType: 'json',
statusCode: {
200: function() {
window.location = "${http_root}";
},
401: function() {
$('#incorrect-login').show();
$('#username').focus();
}
},
complete: function() {
$('#sign-in').prop('disabled', false).html('<i class="fa fa-sign-in"></i>&nbsp; Sign In');
}
});
});
% endif
</script> </script>
${next.javascriptIncludes()} ${next.javascriptIncludes()}
</body> </body>
</html> </html>
<%def name="modalIncludes()"></%def>
<%def name="javascriptIncludes()"></%def> <%def name="javascriptIncludes()"></%def>
<%def name="headIncludes()"></%def> <%def name="headIncludes()"></%def>
<%def name="headerIncludes()"></%def> <%def name="headerIncludes()"></%def>

View File

@@ -0,0 +1,139 @@
<%doc>
USAGE DOCUMENTATION :: PLEASE LEAVE THIS AT THE TOP OF THIS FILE
For Mako templating syntax documentation please visit: http://docs.makotemplates.org/en/latest/
Filename: configuration_table.html
Version: 0.1
DOCUMENTATION :: END
</%doc>
<%!
import os
import sys
import plexpy
from plexpy import common, logger
from plexpy.helpers import anon_url
%>
<table class="config-info-table small-muted">
<tbody>
% if plexpy.CURRENT_VERSION:
<tr>
<td>Git Branch:</td>
<td><a class="no-highlight" href="${anon_url('https://github.com/%s/%s/tree/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.CONFIG.GIT_BRANCH))}">${plexpy.CONFIG.GIT_BRANCH}</a></td>
</tr>
<tr>
<td>Git Commit Hash:</td>
<td><a class="no-highlight" href="${anon_url('https://github.com/%s/%s/commit/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.CURRENT_VERSION))}">${plexpy.CURRENT_VERSION}</a></td>
</tr>
% endif
<tr>
<td>Configuration File:</td>
<td><a class="no-highlight" href="download_config" data-toggle="tooltip" data-placement="right" title="Download Configuration">${plexpy.CONFIG_FILE}</a></td>
</tr>
<tr>
<td>Database File:</td>
<td><a class="no-highlight" href="download_database" data-toggle="tooltip" data-placement="right" title="Download Database">${plexpy.DB_FILE}</a></td>
</tr>
<tr>
<td>Log File:</td>
<td><a class="no-highlight" href="download_log" data-toggle="tooltip" data-placement="right" title="Download Log">${os.path.join(plexpy.CONFIG.LOG_DIR, logger.FILENAME)}</a></td>
</tr>
<tr>
<td>Backup Directory:</td>
<td>${plexpy.CONFIG.BACKUP_DIR}</td>
</tr>
<tr>
<td>Cache Directory:</td>
<td>${plexpy.CONFIG.CACHE_DIR}</td>
</tr>
<tr>
<td>Newsletter Directory:</td>
<td>${plexpy.CONFIG.NEWSLETTER_DIR}</td>
</tr>
<tr>
<td>GeoLite2 Database:</td>
% if plexpy.CONFIG.GEOIP_DB:
<td>${plexpy.CONFIG.GEOIP_DB} | <a class="no-highlight" href="#" id="reinstall_geoip_db">Reinstall / Update</a> | <a class="no-highlight" href="#" id="uninstall_geoip_db">Uninstall</a></td>
% else:
<td><a class="no-highlight" href="#" id="install_geoip_db">Click here to install the GeoLite2 database.</a></td>
% endif
</tr>
% if plexpy.ARGS:
<tr>
<td>Arguments:</td>
<td>${plexpy.ARGS}</td>
</tr>
% endif
<tr>
<td>Platform:</td>
<td>${common.PLATFORM} ${common.PLATFORM_RELEASE} (${common.PLATFORM_VERSION + (' - {}'.format(common.PLATFORM_LINUX_DISTRO) if common.PLATFORM_LINUX_DISTRO else '')})</td>
</tr>
<tr>
<td>Python Version:</td>
<td>${sys.version}</td>
</tr>
<tr>
<td class="top-line">Resources:</td>
<td class="top-line">
<a class="no-highlight" href="${anon_url('https://tautulli.com')}" target="_blank">Tautulli Website</a> |
<a class="no-highlight" href="${anon_url('https://github.com/%s/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO))}" target="_blank">GitHub Source</a> |
<a class="no-highlight guidelines-modal-link" href="${anon_url('https://github.com/%s/%s-Issues' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO))}" data-id="issue">GitHub Issues</a> |
<a class="no-highlight" href="${anon_url('https://github.com/%s/%s-Wiki' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO))}" target="_blank">GitHub Wiki</a> |
<a class="no-highlight guidelines-modal-link" href="${anon_url('http://feathub.com/%s/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO))}" data-id="feature request">FeatHub Feature Requests</a>
</td>
</tr>
<tr>
<td>Support:</td>
<td>
<a class="no-highlight support-modal-link" href="${anon_url('https://tautulli.com/discord')}" target="_blank">Tautulli Discord Server</a> |
<a class="no-highlight support-modal-link" href="${anon_url('https://www.reddit.com/r/Tautulli')}" target="_blank">Tautulli Subreddit</a> |
<a class="no-highlight support-modal-link" href="${anon_url('https://forums.plex.tv/discussion/307821/tautulli-monitor-your-plex-media-server')}" target="_blank">Plex Forums</a>
</td>
</tr>
</tbody>
</table>
<script>
$(document).ready(function () {
$("#install_geoip_db, #reinstall_geoip_db").click(function () {
var msg = 'Are you sure you want to install the GeoLite2 database?<br /><br />' +
'The database is used to lookup IP address geolocation info.<br />' +
'The database will be downloaded from <a href="${anon_url("https://dev.maxmind.com/geoip/geoip2/geolite2/")}" target="_blank">MaxMind</a>, <br />' +
'and requires <strong>100MB</strong> of free space to install in your Tautulli directory.<br />'
var url = 'install_geoip_db';
confirmAjaxCall(url, msg, null, 'Installing GeoLite2 database.', getConfigurationTable);
});
$("#uninstall_geoip_db").click(function () {
var msg = 'Are you sure you want to uninstall the GeoLite2 database?<br /><br />' +
'You will not be able to lookup IP address geolocation info.';
var url = 'uninstall_geoip_db';
confirmAjaxCall(url, msg, null, 'Uninstalling GeoLite2 database.', getConfigurationTable);
});
$('.guidelines-modal-link').on('click', function (e) {
e.preventDefault();
$('#guidelines-type').text($(this).data('id'))
$('#guidelines-modal').modal();
$('#guidelines-continue').attr('href', $(this).attr('href')).on('click', function () {
$('#guidelines-modal').modal('hide');
});
});
$('.support-modal-link').on('click', function (e) {
e.preventDefault();
$('#support-modal').modal();
$('#support-continue').attr('href', $(this).attr('href')).on('click', function () {
$('#support-modal').modal('hide');
});
});
$('body').tooltip({
selector: '[data-toggle="tooltip"]',
container: 'body'
});
});
</script>

View File

@@ -0,0 +1,904 @@
/*************** SCROLLBAR BASE CSS ***************/
.scroll-wrapper {
overflow: hidden !important;
padding: 0 !important;
position: relative;
}
.scroll-wrapper > .scroll-content {
border: none !important;
box-sizing: content-box !important;
height: auto;
left: 0;
margin: 0;
max-height: none;
max-width: none !important;
overflow: scroll !important;
padding: 0;
position: relative !important;
top: 0;
width: auto !important;
}
.scroll-wrapper > .scroll-content::-webkit-scrollbar {
height: 0;
width: 0;
}
.scroll-wrapper.scroll--rtl {
direction: rtl;
}
.scroll-element {
box-sizing: content-box;
display: none;
}
.scroll-element div {
box-sizing: content-box;
}
.scroll-element .scroll-bar,
.scroll-element .scroll-arrow {
cursor: default;
}
.scroll-element.scroll-x.scroll-scrollx_visible, .scroll-element.scroll-y.scroll-scrolly_visible {
display: block;
}
.scroll-textarea {
border: 1px solid #cccccc;
border-top-color: #999999;
}
.scroll-textarea > .scroll-content {
overflow: hidden !important;
}
.scroll-textarea > .scroll-content > textarea {
border: none !important;
box-sizing: border-box;
height: 100% !important;
margin: 0;
max-height: none !important;
max-width: none !important;
overflow: scroll !important;
outline: none;
padding: 2px;
position: relative !important;
top: 0;
width: 100% !important;
}
.scroll-textarea > .scroll-content > textarea::-webkit-scrollbar {
height: 0;
width: 0;
}
/*************** SIMPLE INNER SCROLLBAR ***************/
.scrollbar-inner > .scroll-element,
.scrollbar-inner > .scroll-element div {
border: none;
margin: 0;
padding: 0;
position: absolute;
z-index: 10;
}
.scrollbar-inner > .scroll-element div {
display: block;
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.scrollbar-inner > .scroll-element.scroll-x {
bottom: 2px;
height: 8px;
left: 0;
width: 100%;
}
.scrollbar-inner > .scroll-element.scroll-y {
height: 100%;
right: 2px;
top: 0;
width: 8px;
}
.scrollbar-inner > .scroll-element .scroll-element_outer {
overflow: hidden;
}
.scrollbar-inner > .scroll-element .scroll-element_outer,
.scrollbar-inner > .scroll-element .scroll-element_track,
.scrollbar-inner > .scroll-element .scroll-bar {
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
.scrollbar-inner > .scroll-element .scroll-element_track,
.scrollbar-inner > .scroll-element .scroll-bar {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)";
filter: alpha(opacity=40);
opacity: 0.4;
}
.scrollbar-inner > .scroll-element .scroll-element_track {
background-color: #e0e0e0;
}
.scrollbar-inner > .scroll-element .scroll-bar {
background-color: #c2c2c2;
}
.scrollbar-inner > .scroll-element:hover .scroll-bar {
background-color: #919191;
}
.scrollbar-inner > .scroll-element.scroll-draggable .scroll-bar {
background-color: #919191;
}
/* update scrollbar offset if both scrolls are visible */
.scrollbar-inner > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_track {
left: -12px;
}
.scrollbar-inner > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_track {
top: -12px;
}
.scrollbar-inner > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_size {
left: -12px;
}
.scrollbar-inner > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_size {
top: -12px;
}
/*************** SIMPLE OUTER SCROLLBAR ***************/
.scrollbar-outer > .scroll-element,
.scrollbar-outer > .scroll-element div {
border: none;
margin: 0;
padding: 0;
position: absolute;
z-index: 10;
}
.scrollbar-outer > .scroll-element {
background-color: #ffffff;
}
.scrollbar-outer > .scroll-element div {
display: block;
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.scrollbar-outer > .scroll-element.scroll-x {
bottom: 0;
height: 12px;
left: 0;
width: 100%;
}
.scrollbar-outer > .scroll-element.scroll-y {
height: 100%;
right: 0;
top: 0;
width: 12px;
}
.scrollbar-outer > .scroll-element.scroll-x .scroll-element_outer {
height: 8px;
top: 2px;
}
.scrollbar-outer > .scroll-element.scroll-y .scroll-element_outer {
left: 2px;
width: 8px;
}
.scrollbar-outer > .scroll-element .scroll-element_outer {
overflow: hidden;
}
.scrollbar-outer > .scroll-element .scroll-element_track {
background-color: #eeeeee;
}
.scrollbar-outer > .scroll-element .scroll-element_outer,
.scrollbar-outer > .scroll-element .scroll-element_track,
.scrollbar-outer > .scroll-element .scroll-bar {
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
.scrollbar-outer > .scroll-element .scroll-bar {
background-color: #d9d9d9;
}
.scrollbar-outer > .scroll-element .scroll-bar:hover {
background-color: #c2c2c2;
}
.scrollbar-outer > .scroll-element.scroll-draggable .scroll-bar {
background-color: #919191;
}
/* scrollbar height/width & offset from container borders */
.scrollbar-outer > .scroll-content.scroll-scrolly_visible {
left: -12px;
margin-left: 12px;
}
.scrollbar-outer > .scroll-content.scroll-scrollx_visible {
top: -12px;
margin-top: 12px;
}
.scrollbar-outer > .scroll-element.scroll-x .scroll-bar {
min-width: 10px;
}
.scrollbar-outer > .scroll-element.scroll-y .scroll-bar {
min-height: 10px;
}
/* update scrollbar offset if both scrolls are visible */
.scrollbar-outer > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_track {
left: -14px;
}
.scrollbar-outer > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_track {
top: -14px;
}
.scrollbar-outer > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_size {
left: -14px;
}
.scrollbar-outer > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_size {
top: -14px;
}
/*************** SCROLLBAR MAC OS X ***************/
.scrollbar-macosx > .scroll-element,
.scrollbar-macosx > .scroll-element div {
background: none;
border: none;
margin: 0;
padding: 0;
position: absolute;
z-index: 10;
}
.scrollbar-macosx > .scroll-element div {
display: block;
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.scrollbar-macosx > .scroll-element .scroll-element_track {
display: none;
}
.scrollbar-macosx > .scroll-element .scroll-bar {
background-color: #6C6E71;
display: block;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
filter: alpha(opacity=0);
opacity: 0;
-webkit-border-radius: 7px;
-moz-border-radius: 7px;
border-radius: 7px;
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
-o-transition: opacity 0.2s linear;
-ms-transition: opacity 0.2s linear;
transition: opacity 0.2s linear;
}
.scrollbar-macosx:hover > .scroll-element .scroll-bar,
.scrollbar-macosx > .scroll-element.scroll-draggable .scroll-bar {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=70)";
filter: alpha(opacity=70);
opacity: 0.7;
}
.scrollbar-macosx > .scroll-element.scroll-x {
bottom: 0px;
height: 0px;
left: 0;
min-width: 100%;
overflow: visible;
width: 100%;
}
.scrollbar-macosx > .scroll-element.scroll-y {
height: 100%;
min-height: 100%;
right: 0px;
top: 0;
width: 0px;
}
/* scrollbar height/width & offset from container borders */
.scrollbar-macosx > .scroll-element.scroll-x .scroll-bar {
height: 7px;
min-width: 10px;
top: -9px;
}
.scrollbar-macosx > .scroll-element.scroll-y .scroll-bar {
left: -9px;
min-height: 10px;
width: 7px;
}
.scrollbar-macosx > .scroll-element.scroll-x .scroll-element_outer {
left: 2px;
}
.scrollbar-macosx > .scroll-element.scroll-x .scroll-element_size {
left: -4px;
}
.scrollbar-macosx > .scroll-element.scroll-y .scroll-element_outer {
top: 2px;
}
.scrollbar-macosx > .scroll-element.scroll-y .scroll-element_size {
top: -4px;
}
/* update scrollbar offset if both scrolls are visible */
.scrollbar-macosx > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_size {
left: -11px;
}
.scrollbar-macosx > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_size {
top: -11px;
}
/*************** SCROLLBAR LIGHT ***************/
.scrollbar-light > .scroll-element,
.scrollbar-light > .scroll-element div {
border: none;
margin: 0;
overflow: hidden;
padding: 0;
position: absolute;
z-index: 10;
}
.scrollbar-light > .scroll-element {
background-color: #ffffff;
}
.scrollbar-light > .scroll-element div {
display: block;
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.scrollbar-light > .scroll-element .scroll-element_outer {
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
}
.scrollbar-light > .scroll-element .scroll-element_size {
background: #dbdbdb;
background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2RiZGJkYiIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNlOGU4ZTgiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+");
background: -moz-linear-gradient(left, #dbdbdb 0%, #e8e8e8 100%);
background: -webkit-gradient(linear, left top, right top, color-stop(0%, #dbdbdb), color-stop(100%, #e8e8e8));
background: -webkit-linear-gradient(left, #dbdbdb 0%, #e8e8e8 100%);
background: -o-linear-gradient(left, #dbdbdb 0%, #e8e8e8 100%);
background: -ms-linear-gradient(left, #dbdbdb 0%, #e8e8e8 100%);
background: linear-gradient(to right, #dbdbdb 0%, #e8e8e8 100%);
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
}
.scrollbar-light > .scroll-element.scroll-x {
bottom: 0;
height: 17px;
left: 0;
min-width: 100%;
width: 100%;
}
.scrollbar-light > .scroll-element.scroll-y {
height: 100%;
min-height: 100%;
right: 0;
top: 0;
width: 17px;
}
.scrollbar-light > .scroll-element .scroll-bar {
background: #fefefe;
background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZlZmVmZSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmNWY1ZjUiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+");
background: -moz-linear-gradient(left, #fefefe 0%, #f5f5f5 100%);
background: -webkit-gradient(linear, left top, right top, color-stop(0%, #fefefe), color-stop(100%, #f5f5f5));
background: -webkit-linear-gradient(left, #fefefe 0%, #f5f5f5 100%);
background: -o-linear-gradient(left, #fefefe 0%, #f5f5f5 100%);
background: -ms-linear-gradient(left, #fefefe 0%, #f5f5f5 100%);
background: linear-gradient(to right, #fefefe 0%, #f5f5f5 100%);
border: 1px solid #dbdbdb;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
}
/* scrollbar height/width & offset from container borders */
.scrollbar-light > .scroll-content.scroll-scrolly_visible {
left: -17px;
margin-left: 17px;
}
.scrollbar-light > .scroll-content.scroll-scrollx_visible {
top: -17px;
margin-top: 17px;
}
.scrollbar-light > .scroll-element.scroll-x .scroll-bar {
height: 10px;
min-width: 10px;
top: 0px;
}
.scrollbar-light > .scroll-element.scroll-y .scroll-bar {
left: 0px;
min-height: 10px;
width: 10px;
}
.scrollbar-light > .scroll-element.scroll-x .scroll-element_outer {
height: 12px;
left: 2px;
top: 2px;
}
.scrollbar-light > .scroll-element.scroll-x .scroll-element_size {
left: -4px;
}
.scrollbar-light > .scroll-element.scroll-y .scroll-element_outer {
left: 2px;
top: 2px;
width: 12px;
}
.scrollbar-light > .scroll-element.scroll-y .scroll-element_size {
top: -4px;
}
/* update scrollbar offset if both scrolls are visible */
.scrollbar-light > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_size {
left: -19px;
}
.scrollbar-light > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_size {
top: -19px;
}
.scrollbar-light > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_track {
left: -19px;
}
.scrollbar-light > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_track {
top: -19px;
}
/*************** SCROLLBAR RAIL ***************/
.scrollbar-rail > .scroll-element,
.scrollbar-rail > .scroll-element div {
border: none;
margin: 0;
overflow: hidden;
padding: 0;
position: absolute;
z-index: 10;
}
.scrollbar-rail > .scroll-element {
background-color: #ffffff;
}
.scrollbar-rail > .scroll-element div {
display: block;
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.scrollbar-rail > .scroll-element .scroll-element_size {
background-color: #999;
background-color: rgba(0, 0, 0, 0.3);
}
.scrollbar-rail > .scroll-element .scroll-element_outer:hover .scroll-element_size {
background-color: #666;
background-color: rgba(0, 0, 0, 0.5);
}
.scrollbar-rail > .scroll-element.scroll-x {
bottom: 0;
height: 12px;
left: 0;
min-width: 100%;
padding: 3px 0 2px;
width: 100%;
}
.scrollbar-rail > .scroll-element.scroll-y {
height: 100%;
min-height: 100%;
padding: 0 2px 0 3px;
right: 0;
top: 0;
width: 12px;
}
.scrollbar-rail > .scroll-element .scroll-bar {
background-color: #d0b9a0;
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.5);
}
.scrollbar-rail > .scroll-element .scroll-element_outer:hover .scroll-bar {
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.6);
}
/* scrollbar height/width & offset from container borders */
.scrollbar-rail > .scroll-content.scroll-scrolly_visible {
left: -17px;
margin-left: 17px;
}
.scrollbar-rail > .scroll-content.scroll-scrollx_visible {
margin-top: 17px;
top: -17px;
}
.scrollbar-rail > .scroll-element.scroll-x .scroll-bar {
height: 10px;
min-width: 10px;
top: 1px;
}
.scrollbar-rail > .scroll-element.scroll-y .scroll-bar {
left: 1px;
min-height: 10px;
width: 10px;
}
.scrollbar-rail > .scroll-element.scroll-x .scroll-element_outer {
height: 15px;
left: 5px;
}
.scrollbar-rail > .scroll-element.scroll-x .scroll-element_size {
height: 2px;
left: -10px;
top: 5px;
}
.scrollbar-rail > .scroll-element.scroll-y .scroll-element_outer {
top: 5px;
width: 15px;
}
.scrollbar-rail > .scroll-element.scroll-y .scroll-element_size {
left: 5px;
top: -10px;
width: 2px;
}
/* update scrollbar offset if both scrolls are visible */
.scrollbar-rail > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_size {
left: -25px;
}
.scrollbar-rail > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_size {
top: -25px;
}
.scrollbar-rail > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_track {
left: -25px;
}
.scrollbar-rail > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_track {
top: -25px;
}
/*************** SCROLLBAR DYNAMIC ***************/
.scrollbar-dynamic > .scroll-element,
.scrollbar-dynamic > .scroll-element div {
background: none;
border: none;
margin: 0;
padding: 0;
position: absolute;
z-index: 10;
}
.scrollbar-dynamic > .scroll-element div {
display: block;
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.scrollbar-dynamic > .scroll-element.scroll-x {
bottom: 2px;
height: 7px;
left: 0;
min-width: 100%;
width: 100%;
}
.scrollbar-dynamic > .scroll-element.scroll-y {
height: 100%;
min-height: 100%;
right: 2px;
top: 0;
width: 7px;
}
.scrollbar-dynamic > .scroll-element .scroll-element_outer {
opacity: 0.3;
-webkit-border-radius: 12px;
-moz-border-radius: 12px;
border-radius: 12px;
}
.scrollbar-dynamic > .scroll-element .scroll-element_size {
background-color: #cccccc;
opacity: 0;
-webkit-border-radius: 12px;
-moz-border-radius: 12px;
border-radius: 12px;
-webkit-transition: opacity 0.2s;
-moz-transition: opacity 0.2s;
-o-transition: opacity 0.2s;
-ms-transition: opacity 0.2s;
transition: opacity 0.2s;
}
.scrollbar-dynamic > .scroll-element .scroll-bar {
background-color: #6c6e71;
-webkit-border-radius: 7px;
-moz-border-radius: 7px;
border-radius: 7px;
}
/* scrollbar height/width & offset from container borders */
.scrollbar-dynamic > .scroll-element.scroll-x .scroll-bar {
bottom: 0;
height: 7px;
min-width: 24px;
top: auto;
}
.scrollbar-dynamic > .scroll-element.scroll-y .scroll-bar {
left: auto;
min-height: 24px;
right: 0;
width: 7px;
}
.scrollbar-dynamic > .scroll-element.scroll-x .scroll-element_outer {
bottom: 0;
top: auto;
left: 2px;
-webkit-transition: height 0.2s;
-moz-transition: height 0.2s;
-o-transition: height 0.2s;
-ms-transition: height 0.2s;
transition: height 0.2s;
}
.scrollbar-dynamic > .scroll-element.scroll-y .scroll-element_outer {
left: auto;
right: 0;
top: 2px;
-webkit-transition: width 0.2s;
-moz-transition: width 0.2s;
-o-transition: width 0.2s;
-ms-transition: width 0.2s;
transition: width 0.2s;
}
.scrollbar-dynamic > .scroll-element.scroll-x .scroll-element_size {
left: -4px;
}
.scrollbar-dynamic > .scroll-element.scroll-y .scroll-element_size {
top: -4px;
}
/* update scrollbar offset if both scrolls are visible */
.scrollbar-dynamic > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_size {
left: -11px;
}
.scrollbar-dynamic > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_size {
top: -11px;
}
/* hover & drag */
.scrollbar-dynamic > .scroll-element:hover .scroll-element_outer,
.scrollbar-dynamic > .scroll-element.scroll-draggable .scroll-element_outer {
overflow: hidden;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=70)";
filter: alpha(opacity=70);
opacity: 0.7;
}
.scrollbar-dynamic > .scroll-element:hover .scroll-element_outer .scroll-element_size,
.scrollbar-dynamic > .scroll-element.scroll-draggable .scroll-element_outer .scroll-element_size {
opacity: 1;
}
.scrollbar-dynamic > .scroll-element:hover .scroll-element_outer .scroll-bar,
.scrollbar-dynamic > .scroll-element.scroll-draggable .scroll-element_outer .scroll-bar {
height: 100%;
width: 100%;
-webkit-border-radius: 12px;
-moz-border-radius: 12px;
border-radius: 12px;
}
.scrollbar-dynamic > .scroll-element.scroll-x:hover .scroll-element_outer,
.scrollbar-dynamic > .scroll-element.scroll-x.scroll-draggable .scroll-element_outer {
height: 20px;
min-height: 7px;
}
.scrollbar-dynamic > .scroll-element.scroll-y:hover .scroll-element_outer,
.scrollbar-dynamic > .scroll-element.scroll-y.scroll-draggable .scroll-element_outer {
min-width: 7px;
width: 20px;
}
/*************** SCROLLBAR GOOGLE CHROME ***************/
.scrollbar-chrome > .scroll-element,
.scrollbar-chrome > .scroll-element div {
border: none;
margin: 0;
overflow: hidden;
padding: 0;
position: absolute;
z-index: 10;
}
.scrollbar-chrome > .scroll-element {
background-color: #ffffff;
}
.scrollbar-chrome > .scroll-element div {
display: block;
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.scrollbar-chrome > .scroll-element .scroll-element_track {
background: #f1f1f1;
border: 1px solid #dbdbdb;
}
.scrollbar-chrome > .scroll-element.scroll-x {
bottom: 0;
height: 16px;
left: 0;
min-width: 100%;
width: 100%;
}
.scrollbar-chrome > .scroll-element.scroll-y {
height: 100%;
min-height: 100%;
right: 0;
top: 0;
width: 16px;
}
.scrollbar-chrome > .scroll-element .scroll-bar {
background-color: #d9d9d9;
border: 1px solid #bdbdbd;
cursor: default;
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
}
.scrollbar-chrome > .scroll-element .scroll-bar:hover {
background-color: #c2c2c2;
border-color: #a9a9a9;
}
.scrollbar-chrome > .scroll-element.scroll-draggable .scroll-bar {
background-color: #919191;
border-color: #7e7e7e;
}
/* scrollbar height/width & offset from container borders */
.scrollbar-chrome > .scroll-content.scroll-scrolly_visible {
left: -16px;
margin-left: 16px;
}
.scrollbar-chrome > .scroll-content.scroll-scrollx_visible {
top: -16px;
margin-top: 16px;
}
.scrollbar-chrome > .scroll-element.scroll-x .scroll-bar {
height: 8px;
min-width: 10px;
top: 3px;
}
.scrollbar-chrome > .scroll-element.scroll-y .scroll-bar {
left: 3px;
min-height: 10px;
width: 8px;
}
.scrollbar-chrome > .scroll-element.scroll-x .scroll-element_outer {
border-left: 1px solid #dbdbdb;
}
.scrollbar-chrome > .scroll-element.scroll-x .scroll-element_track {
height: 14px;
left: -3px;
}
.scrollbar-chrome > .scroll-element.scroll-x .scroll-element_size {
height: 14px;
left: -4px;
}
.scrollbar-chrome > .scroll-element.scroll-y .scroll-element_outer {
border-top: 1px solid #dbdbdb;
}
.scrollbar-chrome > .scroll-element.scroll-y .scroll-element_track {
top: -3px;
width: 14px;
}
.scrollbar-chrome > .scroll-element.scroll-y .scroll-element_size {
top: -4px;
width: 14px;
}
/* update scrollbar offset if both scrolls are visible */
.scrollbar-chrome > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_size {
left: -19px;
}
.scrollbar-chrome > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_size {
top: -19px;
}
.scrollbar-chrome > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_track {
left: -19px;
}
.scrollbar-chrome > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_track {
top: -19px;
}

View File

@@ -0,0 +1 @@
@font-face{font-family:'Open Sans';font-weight:400;font-style:normal;src:url(../fonts/Open-Sans-regular/Open-Sans-regular.eot);src:url(../fonts/Open-Sans-regular/Open-Sans-regular.eot?#iefix) format('embedded-opentype'),local('Open Sans'),local('Open-Sans-regular'),url(../fonts/Open-Sans-regular/Open-Sans-regular.woff2) format('woff2'),url(../fonts/Open-Sans-regular/Open-Sans-regular.woff) format('woff'),url(../fonts/Open-Sans-regular/Open-Sans-regular.ttf) format('truetype'),url(../fonts/Open-Sans-regular/Open-Sans-regular.svg#OpenSans) format('svg')}@font-face{font-family:'Open Sans';font-weight:600;font-style:normal;src:url(../fonts/Open-Sans-600/Open-Sans-600.eot);src:url(../fonts/Open-Sans-600/Open-Sans-600.eot?#iefix) format('embedded-opentype'),local('Open Sans Semibold'),local('Open-Sans-600'),url(../fonts/Open-Sans-600/Open-Sans-600.woff2) format('woff2'),url(../fonts/Open-Sans-600/Open-Sans-600.woff) format('woff'),url(../fonts/Open-Sans-600/Open-Sans-600.ttf) format('truetype'),url(../fonts/Open-Sans-600/Open-Sans-600.svg#OpenSans) format('svg')}

View File

@@ -0,0 +1 @@
.ui-pnotify{top:36px;right:36px;position:absolute;height:auto;z-index:2}body>.ui-pnotify{position:fixed;z-index:100040}.ui-pnotify-modal-overlay{background-color:rgba(0,0,0,.4);top:0;left:0;position:absolute;height:100%;width:100%;z-index:1}body>.ui-pnotify-modal-overlay{position:fixed;z-index:100039}.ui-pnotify.ui-pnotify-in{display:block!important}.ui-pnotify.ui-pnotify-move{transition:left .5s ease,top .5s ease,right .5s ease,bottom .5s ease}.ui-pnotify.ui-pnotify-fade-slow{transition:opacity .6s linear;opacity:0}.ui-pnotify.ui-pnotify-fade-slow.ui-pnotify.ui-pnotify-move{transition:opacity .6s linear,left .5s ease,top .5s ease,right .5s ease,bottom .5s ease}.ui-pnotify.ui-pnotify-fade-normal{transition:opacity .4s linear;opacity:0}.ui-pnotify.ui-pnotify-fade-normal.ui-pnotify.ui-pnotify-move{transition:opacity .4s linear,left .5s ease,top .5s ease,right .5s ease,bottom .5s ease}.ui-pnotify.ui-pnotify-fade-fast{transition:opacity .2s linear;opacity:0}.ui-pnotify.ui-pnotify-fade-fast.ui-pnotify.ui-pnotify-move{transition:opacity .2s linear,left .5s ease,top .5s ease,right .5s ease,bottom .5s ease}.ui-pnotify.ui-pnotify-fade-in{opacity:1}.ui-pnotify .ui-pnotify-shadow{-webkit-box-shadow:0 6px 28px 0 rgba(0,0,0,.1);-moz-box-shadow:0 6px 28px 0 rgba(0,0,0,.1);box-shadow:0 6px 28px 0 rgba(0,0,0,.1)}.ui-pnotify-container{background-position:0 0;padding:.8em;height:100%;margin:0}.ui-pnotify-container:after{content:" ";visibility:hidden;display:block;height:0;clear:both}.ui-pnotify-container.ui-pnotify-sharp{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.ui-pnotify-title{display:block;margin-bottom:.4em;margin-top:0}.ui-pnotify-text{display:block}.ui-pnotify-icon,.ui-pnotify-icon span{display:block;float:left;margin-right:.2em}.ui-pnotify.stack-bottomleft,.ui-pnotify.stack-topleft{left:25px;right:auto}.ui-pnotify.stack-bottomleft,.ui-pnotify.stack-bottomright{bottom:25px;top:auto}.ui-pnotify.stack-modal{left:50%;right:auto;margin-left:-150px}.ui-pnotify-closer,.ui-pnotify-sticker{float:right;margin-left:.2em}.ui-pnotify-container{position:relative;left:0}@media (max-width:480px){.ui-pnotify-mobile-able.ui-pnotify{position:fixed;top:0;right:0;left:0;width:auto!important;font-size:1.2em;-webkit-font-smoothing:antialiased;-moz-font-smoothing:antialiased;-ms-font-smoothing:antialiased;font-smoothing:antialiased}.ui-pnotify-mobile-able.ui-pnotify .ui-pnotify-shadow{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;border-bottom-width:5px}.ui-pnotify-mobile-able .ui-pnotify-container{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.ui-pnotify-mobile-able.ui-pnotify.stack-bottomleft,.ui-pnotify-mobile-able.ui-pnotify.stack-topleft{left:0;right:0}.ui-pnotify-mobile-able.ui-pnotify.stack-bottomleft,.ui-pnotify-mobile-able.ui-pnotify.stack-bottomright{left:0;right:0;bottom:0;top:auto}.ui-pnotify-mobile-able.ui-pnotify.stack-bottomleft .ui-pnotify-shadow,.ui-pnotify-mobile-able.ui-pnotify.stack-bottomright .ui-pnotify-shadow{border-top-width:5px;border-bottom-width:1px}}

File diff suppressed because one or more lines are too long

View File

@@ -34,7 +34,7 @@ table.display {
margin: 0 auto; margin: 0 auto;
clear: both; clear: both;
width: 100%; width: 100%;
font-size: 14px; font-size: 12px;
line-height: 25px; line-height: 25px;
/* Note Firefox 3.5 and before have a bug with border-collapse /* Note Firefox 3.5 and before have a bug with border-collapse
* ( https://bugzilla.mozilla.org/show%5Fbug.cgi?id=155955 ) * ( https://bugzilla.mozilla.org/show%5Fbug.cgi?id=155955 )
@@ -332,4 +332,88 @@ div.box {
} }
td.no-wrap, th.no-wrap { td.no-wrap, th.no-wrap {
white-space:nowrap; white-space:nowrap;
} }
/*
* Custom styles
*/
table.display,
table.display tr.shown + tr table[id^='history_child'],
table.display tr.shown + tr table[id^='media_info_child'],
table.display tr.shown + tr table[id^='media_info_child'] tr.shown + tr table[id^='media_info_child'] {
table-layout: auto;
}
table.display tr.shown + tr div.slider {
display: none;
}
table.display tr.shown + tr > td {
padding-top: 0;
padding-bottom: 0;
padding-left: 0;
}
table.display tr.shown + tr:hover {
background-color: rgba(255,255,255,0);
}
table.display tr.shown + tr:hover a,
table.display tr.shown + tr td:hover a,
table.display tr.shown + tr td:hover a .fa,
table.display tr.shown + tr .pagination > .active > a,
table.display tr.shown + tr .pagination > .active > a:hover {
color: #fff;
}
table.display tr.shown + tr table[id^='history_child'] td:hover a,
table.display tr.shown + tr table[id^='history_child'] td:hover a .fa,
table.display tr.shown + tr table[id^='media_info_child'] > tr > td:hover a,
table.display tr.shown + tr table[id^='media_info_child'] tr.shown + tr table[id^='media_info_child'] td:hover a {
color: #cc7b19;
}
table.display tr.shown + tr .pagination > .disabled > a,
table.display tr.shown + tr .pagination > .disabled > a:hover {
color: #444444;
}
table.display tr.shown + tr .pagination > li > a:hover {
color: #e9a049;
}
table.display tr.odd td,
table.display tr.even td {
padding: 5px 10px !important;
}
table[id^='history_child'] {
margin-top: 0;
opacity: .6;
}
table[id^='media_info_child'] {
margin-top: 0;
}
div[id^='history_child'] thead th,
div[id^='media_info_child'] thead th {
line-height: 0;
height: 0 !important;
overflow: hidden;
}
div[id^='history_child'] div.row,
div[id^='media_info_child'] div.row {
margin: 0;
}
div[id^='history_child'] div.col-sm-12,
div[id^='media_info_child'] div.col-sm-12 {
padding: 0;
}
div[id^='history_child'] div.dataTables_scrollBody,
div[id^='media_info_child'] div.dataTables_scrollBody {
overflow: hidden !important;
}
div[id^='media_info_child'] div[id^='media_info_child'] div.dataTables_scrollHead thead th {
line-height: 25px;
height: 35px !important;
overflow: hidden;
}
.current-activity-row {
background-color: rgba(255,255,255,.1) !important;
}
.current-activity-row:hover {
background-color: rgba(255,255,255,0.125) !important;
}

View File

@@ -1,305 +0,0 @@
<%doc>
USAGE DOCUMENTATION :: PLEASE LEAVE THIS AT THE TOP OF THIS FILE
For Mako templating syntax documentation please visit: http://docs.makotemplates.org/en/latest/
Filename: current_activity.html
Version: 0.1
Variable names: data [list]
data :: Usable parameters
data['stream_count'] Returns the current number of active streams
data['sessions'] Returns an array containing session data
data[sessions] :: Usable parameters
== Global keys ==
session_key Returns a unique session id for the active stream
rating_key Returns the unique identifier for the media item.
media_index Returns the index of the media item.
parent_media_index Returns the index of the media item's parent.
media_type Returns the type of session. Either 'track', 'episode' or 'movie'.
thumb Returns the location of the item's thumbnail. Use with pms_image_proxy.
bif_thumb Returns the location of the item's bif thumbnail. Use with pms_image_proxy.
art Returns the location of the item's artwork
progress_percent Returns the current progress of the item. 0 to 100.
user Returns the name of the user owning the session.
user_id Returns the Plex user id if available.
machine_id Returns the machine id of the players being used.
friendly_name Returns the friendlly name of the user owning the session.
user_thumb Returns the profile picture of the user owning the session.
state Returns the state of the current session. Either 'playing', 'paused' or 'buffering'.
title Returns the name of the episode, movie or music track.
year Returns the year of the episode, movie, or clip.
ip_address Returns the ip address of the stream.
player Returns the name of the platform used to play the stream.
platform Returns the type of platform used to play the stream.
throttled Returns true if the transcode session is throttled.
transcode_progress Returns the current transcode progress of the item. 0 to 100.
transcode_speed Returns the current transcode speed of the item.
audio_decision Returns the audio transcode decision. Either 'transcode', 'copy' or 'direct play'.
audio_codec Returns the name of the audio codec.
audio_channels Returns the number of audio channels.
grandparent_title Returns the title of the item's grandparent.
parent_title Returns the title of the item's parent.
video_decision Returns the video transcode decision. Either 'transcode', 'copy' or 'direct play'.
video_codec Returns the name of the video codec.
height Returns the value of the video height.
width Returns the value of the video width.
container Returns the value of the media container.
bitrate Returns the value of the media bitrate.
video_resolution Returns the value of the video resolution.
video_framerate Returns the value of the video framerate.
video_aspect_ratio Returns the value of the video aspect ratio.
transcode_audio_channels Returns the amount of audio channels if there is a transcode session.
transcode_audio_codec Returns the name of the audio codec if there is a transcode session.
transcode_video_codec Returns the name of the video codec if there is a transcode session.
transcode_width Returns the video width if there is a transcode session.
transcode_height Returns the video height if there is a transcode session.
transcode_container Returns the value of media container if there is a transcode session.
transcode_protocol Returns the value of media protocol if there is a transcode session.
indexes Returns true if the media has media indexes and are enabled
DOCUMENTATION :: END
</%doc>
% if data is not None:
% if data['stream_count'] != '0':
% for a in data['sessions']:
<div class="dashboard-instance" id="instance-${a['session_key']}">
% if a['media_type'] == 'movie' or a['media_type'] == 'episode' or a['media_type'] == 'track':
<a href="info?rating_key=${a['rating_key']}">
% endif
<div class="dashboard-activity-poster">
% if (a['media_type'] == 'movie' and not a['indexes']) or (a['indexes'] and not a['view_offset']):
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['art']}&width=500&height=280);"></div>
% elif (a['media_type'] == 'episode' and not a['indexes']) or (a['indexes'] and not a['view_offset']):
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['art']}&width=500&height=280);"></div>
% elif a['indexes']:
<div class="dashboard-activity-poster-face bif" style="background-image: url(pms_image_proxy?img=${a['bif_thumb']}&width=500&height=280); display: none;"></div>
% else:
% if a['media_type'] == 'track':
<div class="dashboard-activity-cover-face-bg" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=300&height=300);"></div>
<div class="dashboard-activity-cover-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=300&height=300);"></div>
% elif a['media_type'] == 'clip':
% if a['art'][:4] == 'http':
<div class="dashboard-activity-poster-face" style="background-image: url(${a['art']});"></div>
% elif a['thumb'][:4] == 'http':
<div class="dashboard-activity-poster-face" style="background-image: url(${a['thumb']});"></div>
% else:
% if a['art']:
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['art']}&width=500&height=280);"></div>
% else:
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=500&height=280);"></div>
% endif
% endif
% elif a['media_type'] == 'photo':
<div class="dashboard-activity-poster-face bif" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=500&height=500);"></div>
% else:
<div class="dashboard-activity-cover-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=300&height=300&fallback=cover);"></div>
% endif
% endif
<div class="dashboard-activity-button-info">
<button type="button" class="btn btn-activity-info btn-lg" data-target="#stream-${a['session_key']}">
<i class="fa fa-info-circle"></i>
</button>
</div>
<div id="stream-${a['session_key']}" class="dashboard-activity-info-details-overlay">
<div class="dashboard-activity-info-details-content">
<div id="platform-${a['session_key']}" title="${a['platform']}">
<script>
$("#platform-${a['session_key']}").html("<div class='dashboard-activity-info-platform-box' style='background-image: url(" + getPlatformImagePath('${a['platform']}') + ");'>");
</script>
</div>
<div class="dashboard-activity-info-platform">
<strong>${a['player']}</strong><br />
% if a['state'] == 'playing':
State &nbsp;<strong>Playing</strong>
% elif a['state'] == 'paused':
State &nbsp;<strong>Paused</strong>
% elif a['state'] == 'buffering':
State &nbsp;<strong>Buffering</strong>
% endif
</div>
% if a['media_type'] == 'track':
% if a['audio_decision'] == 'direct play':
Stream &nbsp;<strong>Direct Play</strong>
% elif a['audio_decision'] == 'copy':
Stream &nbsp;<strong>Direct Stream</strong>
% else:
Stream &nbsp;<strong>Transcoding
(Speed: ${a['transcode_speed']})
% if a['throttled'] == '1':
(Throttled)
% endif
</strong>
% endif
<br />
% if a['audio_decision'] == 'direct play':
Audio &nbsp;<strong>Direct Play (${a['audio_codec']}) (${a['audio_channels']}ch)</strong>
% elif a['audio_decision'] == 'copy':
Audio &nbsp;<strong>Direct Stream (${a['transcode_audio_codec']}) (${a['transcode_audio_channels']}ch)</strong>
% elif a['audio_decision'] == 'transcode':
Audio &nbsp;<strong>Transcode (${a['transcode_audio_codec']}) (${a['transcode_audio_channels']}ch)</strong>
% endif
% elif a['media_type'] == 'episode' or a['media_type'] == 'movie' or a['media_type'] == 'clip':
% if a['video_decision'] == 'direct play' and a['audio_decision'] == 'direct play':
Stream &nbsp;<strong>Direct Play</strong>
% elif a['video_decision'] == 'copy' and a['audio_decision'] == 'copy':
Stream &nbsp;<strong>Direct Stream</strong>
% else:
Stream &nbsp;<strong>Transcoding
(Speed: ${a['transcode_speed']})
% if a['throttled'] == '1':
(Throttled)
% endif
</strong>
% endif
<br />
% if a['video_decision'] == 'direct play':
Video &nbsp;<strong>Direct Play (${a['video_codec']}) (${a['width']}x${a['height']})</strong>
% elif a['video_decision'] == 'copy':
Video &nbsp;<strong>Direct Stream (${a['transcode_video_codec']}) (${a['width']}x${a['height']})</strong>
% elif a['video_decision'] == 'transcode':
Video &nbsp;<strong>Transcode (${a['transcode_video_codec']}) (${a['transcode_width']}x${a['transcode_height']})</strong>
% endif
<br />
% if a['audio_decision'] == 'direct play':
Audio &nbsp;<strong>Direct Play (${a['audio_codec']}) (${a['audio_channels']}ch)</strong>
% elif a['audio_decision'] == 'copy':
Audio &nbsp;<strong>Direct Stream (${a['transcode_audio_codec']}) (${a['transcode_audio_channels']}ch)</strong>
% elif a['audio_decision'] == 'transcode':
Audio &nbsp;<strong>Transcode (${a['transcode_audio_codec']}) (${a['transcode_audio_channels']}ch)</strong>
% endif
% elif a['media_type'] == 'photo':
% if a['video_decision'] == 'direct play':
Stream &nbsp;<strong>Direct Play</strong>
% elif a['video_decision'] == 'copy':
Stream &nbsp;<strong>Direct Stream</strong>
% else:
Stream &nbsp;<strong>
Transcoding
(Speed: ${a['transcode_speed']})
% if a['throttled'] == '1':
(Throttled)
% endif
</strong>
% endif
% endif
<br>
</div>
</div>
% if a['media_type'] != 'photo':
<div class="dashboard-activity-poster-info-bar">
<div class="dashboard-activity-poster-info-ip-address">
% if a['ip_address']:
<span>IP: ${a['ip_address']}</span>
% else:
<span>IP: N/A</span>
% endif
<br />
ETA:
<span id="stream-eta-${a['session_key']}">
<script>
$("#stream-eta-${a['session_key']}").html(moment().add(parseInt(${a['duration']}) - parseInt(${a['view_offset']}), 'milliseconds').format(time_format));
</script>
</span>
</div>
<div class="dashboard-activity-poster-info-time">
<span class="progress_time">${a['view_offset']}</span>/<span class="progress_time">${a['duration']}</span>
</div>
</div>
% endif
</div>
% if a['media_type'] == 'movie' or a['media_type'] == 'episode' or a['media_type'] == 'track':
</a>
% endif
<div class="dashboard-activity-progress">
<div class="dashboard-activity-progress-bar">
<div class="bufferbar" style="width: ${a['transcode_progress']}%">${a['transcode_progress']}%</div>
<div class="bar" style="width: ${a['progress_percent']}%">${a['progress_percent']}%</div>
</div>
</div>
<div class="dashboard-activity-metadata-wrapper">
<a href="user?user_id=${a['user_id']}">
<div class="dashboard-activity-metadata-user-thumb" style="background-image: url(${a['user_thumb']});"></div>
</a>
<div class="dashboard-activity-metadata-title">
% if a['state'] == 'playing':
<i class="fa fa-play"></i>&nbsp;
% elif a['state'] == 'paused':
<i class="fa fa-pause"></i>&nbsp;
% elif a['state'] == 'buffering':
<i class="fa fa-spinner"></i>&nbsp;
% endif
% if a['media_type'] == 'episode':
<a href="info?rating_key=${a['rating_key']}" title="${a['grandparent_title']} - ${a['title']}">${a['grandparent_title']} - ${a['title']}</a>
% elif a['media_type'] == 'movie':
<a href="info?rating_key=${a['rating_key']}" title="${a['title']}">${a['title']}</a>
% elif a['media_type'] == 'clip':
<span title="${a['title']}">${a['title']}</span>
% elif a['media_type'] == 'track':
<a href="info?rating_key=${a['rating_key']}" title="${a['grandparent_title']} - ${a['title']}">${a['grandparent_title']} - ${a['title']}</a>
% elif a['media_type'] == 'photo':
<span title="${a['parent_title']}">${a['parent_title']}</span>
% else:
<span title="${a['title']}">${a['title']}</span>
% endif
</div>
<div class="dashboard-activity-metadata-subtitle">
% if a['media_type'] == 'episode':
<span title="S${a['parent_media_index']} &middot; E${a['media_index']}">S${a['parent_media_index']} &middot; E${a['media_index']}</span>
% elif a['media_type'] == 'movie':
<span title="${a['year']}">${a['year']}</span>
% elif a['media_type'] == 'track':
<a href="info?rating_key=${a['parent_rating_key']}" title="${a['parent_title']}">${a['parent_title']}</a>
% elif a['media_type'] == 'photo':
<span title="${a['title']}">${a['title']}</span>
% else:
<span title="${a['year']}">${a['year']}</span>
% endif
</div>
<div class="dashboard-activity-metadata-user">
% if a['user_id']:
<a href="user?user_id=${a['user_id']}" title="${a['friendly_name']}">${a['friendly_name']}</a>
% else:
<a href="user?user=${a['user']}" title="${a['friendly_name']}">${a['friendly_name']}</a>
% endif
</div>
</div>
</div>
% endfor
<script>
// When using bif indexes make the image transition a little smoother.
$('.bif').each(function() {
$(this).hide().fadeIn(1000);
});
// Convert timestamps to readable times
$('.progress_time').each(function(index) {
$(this).html(millisecondsToMinutes($(this).text(), false));
});
// Show/Hide activity info
$('.btn-activity-info').on('click', function(e) {
e.preventDefault();
$($(this).attr('data-target')).toggle();
});
// Add hover class to dashboard-instance
$('.dashboard-activity-poster').hover(function() {
$(this).closest('.dashboard-instance').addClass('hover');
}, function() {
$(this).closest('.dashboard-instance').removeClass('hover');
});
</script>
% else:
<div class="text-muted">Nothing is currently being watched.</div><br>
% endif
% else:
<div class="text-muted">There was an error communicating with your Plex Server. Please check your <a
href="settings">settings</a>.
</div><br>
% endif

View File

@@ -15,12 +15,23 @@ DOCUMENTATION :: END
</%doc> </%doc>
% if data != None: % if data != None:
% if data == '0': <%
s = '('
if data['direct_play']:
s += str(data['direct_play']) + ' direct play' + ('s' if data['direct_play'] > 1 else '') + ', '
if data['direct_stream']:
s += str(data['direct_stream']) + ' direct stream' + ('s' if data['direct_stream'] > 1 else '') + ', '
if data['transcode']:
s += str(data['transcode']) + ' transcode' + ('s' if data['transcode'] > 1 else '') + ', '
s = s.rstrip(', ')
s += ')'
%>
% if data['stream_count'] == '0':
<h3>Activity</h3> <h3>Activity</h3>
% elif data == '1': % elif data['stream_count'] == '1':
<h3>Activity <small>${data} stream</small></h3> <h3>Activity &nbsp;&nbsp;<small>${data['stream_count']} stream ${s}</small></h3>
% else: % else:
<h3>Activity <small>${data} streams</small></h3> <h3>Activity &nbsp;&nbsp;<small>${data['stream_count']} streams ${s}</small></h3>
% endif % endif
% else: % else:
<h3>Activity</h3> <h3>Activity</h3>

View File

@@ -0,0 +1,476 @@
<%doc>
USAGE DOCUMENTATION :: PLEASE LEAVE THIS AT THE TOP OF THIS FILE
For Mako templating syntax documentation please visit: http://docs.makotemplates.org/en/latest/
Filename: current_activity_instance.html
Version: 0.1
Variable names: data {dict}
data :: Usable parameters
== Global keys ==
session_key Returns a unique session id for the active stream
rating_key Returns the unique identifier for the media item.
media_index Returns the index of the media item.
parent_media_index Returns the index of the media item's parent.
media_type Returns the type of session. Either 'track', 'episode' or 'movie'.
thumb Returns the location of the item's thumbnail. Use with pms_image_proxy.
bif_thumb Returns the location of the item's bif thumbnail. Use with pms_image_proxy.
art Returns the location of the item's artwork
progress_percent Returns the current progress of the item. 0 to 100.
user Returns the name of the user owning the session.
user_id Returns the Plex user id if available.
machine_id Returns the machine id of the players being used.
friendly_name Returns the friendlly name of the user owning the session.
user_thumb Returns the profile picture of the user owning the session.
state Returns the state of the current session. Either 'playing', 'paused' or 'buffering'.
title Returns the name of the episode, movie or music track.
year Returns the year of the episode, movie, or clip.
ip_address Returns the ip address of the stream.
player Returns the name of the platform used to play the stream.
platform Returns the type of platform used to play the stream.
transcode_throttled Returns true if the transcode session is throttled.
transcode_progress Returns the current transcode progress of the item. 0 to 100.
transcode_speed Returns the current transcode speed of the item.
audio_decision Returns the audio transcode decision. Either 'transcode', 'copy' or 'direct play'.
audio_codec Returns the name of the audio codec.
audio_channels Returns the number of audio channels.
grandparent_title Returns the title of the item's grandparent.
parent_title Returns the title of the item's parent.
video_decision Returns the video transcode decision. Either 'transcode', 'copy' or 'direct play'.
video_codec Returns the name of the video codec.
height Returns the value of the video height.
width Returns the value of the video width.
container Returns the value of the media container.
bitrate Returns the value of the media bitrate.
video_resolution Returns the value of the video resolution.
video_framerate Returns the value of the video framerate.
video_aspect_ratio Returns the value of the video aspect ratio.
transcode_audio_channels Returns the amount of audio channels if there is a transcode session.
transcode_audio_codec Returns the name of the audio codec if there is a transcode session.
transcode_video_codec Returns the name of the video codec if there is a transcode session.
transcode_width Returns the video width if there is a transcode session.
transcode_height Returns the video height if there is a transcode session.
transcode_container Returns the value of media container if there is a transcode session.
transcode_protocol Returns the value of media protocol if there is a transcode session.
indexes Returns true if the media has media indexes and are enabled
DOCUMENTATION :: END
</%doc>
% if session is not None:
<%
from collections import defaultdict
from urllib import quote
from plexpy import helpers
from plexpy.common import VIDEO_RESOLUTION_OVERRIDES, AUDIO_CODEC_OVERRIDES, EXTRA_TYPES
import plexpy
%>
<%
data = defaultdict(lambda: 'Unknown', **session)
sk = data['session_key']
href = 'info?rating_key={}'.format(data['rating_key']) if data['rating_key'] else '#'
parent_href = 'info?rating_key={}'.format(data['parent_rating_key']) if data['parent_rating_key'] else '#'
grandparent_href = 'info?rating_key={}'.format(data['grandparent_rating_key']) if data['grandparent_rating_key'] else '#'
user_href = 'user?user_id={}'.format(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']}"
data-rating_key="${data['rating_key']}" data-parent_rating_key="${data['parent_rating_key']}" data-grandparent_rating_key="${data['grandparent_rating_key']}">
<div class="dashboard-activity-container">
<%
if 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'
else:
if (data['art'] and data['art'].startswith('http')) or (data['thumb'] and data['thumb'].startswith('http')):
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 class="dashboard-activity-poster-container hidden-xs">
% 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>
% endif
% if data['channel_stream'] == 0:
% 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(pms_image_proxy?img=${data['thumb']}&width=300&height=450&fallback=poster&refresh=true);"></div>
</a>
% elif data['media_type'] == 'episode':
<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>
</a>
% elif data['media_type'] == 'track':
<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>
</a>
% elif data['media_type'] in ('photo', 'clip'):
% 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>
% 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>
% endif
% else:
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(images/art.png);"></div>
% endif
% else:
% if data['channel_icon'].startswith('http'):
<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(${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
</div>
<div class="dashboard-activity-info-icon">
<%
if not _session['user_group'] == 'admin' or not data['session_id']:
no_terminate = '-no-terminate'
else:
no_terminate = ''
%>
<div id="platform-${sk}" class="dashboard-activity-info-platform${no_terminate} svg-icon platform-${data['platform_name']}" title="${data['platform']}"></div>
% if _session['user_group'] == 'admin' and plexpy.CONFIG.PMS_PLEXPASS and data['session_id']:
<div class="dashboard-activity-terminate-session" id="terminate-button-${sk}" data-key="${sk}" data-id="${data['session_id']}" data-toggle="tooltip" title="Terminate Stream">
<i class="fa fa-times" style="padding-top: 8px;"></i>
</div>
% endif
</div>
<div class="dashboard-activity-info-container">
<div class="dashboard-activity-info-scroller scrollbar-macosx">
<div class="dashboard-activity-info scoller-content">
<ul class="list-unstyled dashboard-activity-info-list">
<li class="dashboard-activity-info-item">
<div class="sub-heading">Product</div>
<div class="sub-value platform-right">${data['product']}</div>
</li>
<li class="dashboard-activity-info-item">
<div class="sub-heading">Player</div>
<div class="sub-value platform-right">${data['player']}</div>
</li>
<li class="dashboard-activity-info-item">
<div class="sub-heading">Quality</div>
<div class="sub-value platform-right" id="stream_quality-${sk}">
% if data['media_type'] != 'photo' and data['quality_profile'] != 'Unknown':
<%
br = helpers.cast_to_int(data['stream_bitrate']) or ''
if br:
if br > 1000:
br = '(' + str(round(br / 1000.0, 1)) + ' Mbps)'
else:
br = '(' + str(br) + ' kbps)'
%>
${data['quality_profile']} ${br}
% else:
${data['quality_profile']}
% endif
</div>
</li>
% if data['optimized_version'] == 1:
<li class="dashboard-activity-info-item">
<div class="sub-heading">Optimized</div>
<div class="sub-value" id="optimized_version-${sk}">
${data['optimized_version_profile']} (${data['optimized_version_title']})
</div>
</li>
% endif
% if data['synced_version'] == 1:
<li class="dashboard-activity-info-item">
<div class="sub-heading">Synced</div>
<div class="sub-value" id="synced_version-${sk}">
${data['synced_version_profile']}
</div>
</li>
% endif
</ul>
<ul class="list-unstyled dashboard-activity-info-list">
<li class="dashboard-activity-info-item">
% if _session['user_group'] == 'admin':
<div class="sub-heading"><span class="raw-stream-info-modal" data-toggle="modal" data-target="#raw-stream-info-modal" data-key="${sk}">Stream</span></div>
% else:
<div class="sub-heading">Stream</div>
% endif
<div class="sub-value" id="transcode_decision-${sk}">
% if data['transcode_decision'] == 'transcode':
Transcode
% if data['transcode_throttled'] == 1:
(Throttled)
% else:
(Speed: ${data['transcode_speed']})
% endif
% elif data['transcode_decision'] == 'copy':
Direct Stream
% else:
Direct Play
% endif
</div>
</li>
<li class="dashboard-activity-info-item">
<div class="sub-heading">Container</div>
<div class="sub-value" id="transcode_container-${sk}">
% if data['stream_container_decision'] == 'transcode':
Transcode (${data['container'].upper()} <i class="fa fa-long-arrow-right"></i> ${data['stream_container'].upper()})
% else:
Direct Play (${data['container'].upper()})
% endif
</div>
</li>
% if data['media_type'] in ('movie', 'episode', 'clip', 'photo'):
<li class="dashboard-activity-info-item">
<div class="sub-heading">Video</div>
<div class="sub-value" id="video_decision-${sk}">
% if data['media_type'] in ('movie', 'episode', 'clip'):
% if data['stream_video_decision'] == 'transcode':
<%
hw_d = ' (HW)' if data['transcode_hw_decoding'] else ''
hw_e = ' (HW)' if data['transcode_hw_encoding'] else ''
%>
Transcode (${data['video_codec'].upper()}${hw_d} ${VIDEO_RESOLUTION_OVERRIDES.get(data['video_resolution'], data['video_resolution'])} <i class="fa fa-long-arrow-right"></i> ${data['stream_video_codec'].upper()}${hw_e} ${VIDEO_RESOLUTION_OVERRIDES.get(data['stream_video_resolution'], data['stream_video_resolution'])})
% elif data['stream_video_decision'] == 'copy':
Direct Stream (${data['stream_video_codec'].upper()} ${VIDEO_RESOLUTION_OVERRIDES.get(data['stream_video_resolution'], data['stream_video_resolution'])})
% else:
Direct Play (${data['video_codec'].upper()} ${VIDEO_RESOLUTION_OVERRIDES.get(data['video_resolution'], data['video_resolution'])})
% endif
% elif data['media_type'] == 'photo':
Direct Play (${data['width']}x${data['height']})
% endif
</div>
</li>
% endif
% if data['media_type'] in ('movie', 'episode', 'clip', 'track'):
<li class="dashboard-activity-info-item">
<div class="sub-heading">Audio</div>
<div class="sub-value" id="audio_decision-${sk}">
% if data['stream_audio_decision'] == 'transcode':
Transcode (${AUDIO_CODEC_OVERRIDES.get(data['audio_codec'], data['audio_codec'].upper())} ${data['audio_channel_layout'].split('(')[0].capitalize()} <i class="fa fa-long-arrow-right"></i> ${AUDIO_CODEC_OVERRIDES.get(data['stream_audio_codec'], data['stream_audio_codec'].upper())} ${data['stream_audio_channel_layout'].split('(')[0].capitalize()})
% elif data['stream_audio_decision'] == 'copy':
Direct Stream (${AUDIO_CODEC_OVERRIDES.get(data['stream_audio_codec'], data['stream_audio_codec'].upper())} ${data['stream_audio_channel_layout'].split('(')[0].capitalize()})
% else:
Direct Play (${AUDIO_CODEC_OVERRIDES.get(data['audio_codec'], data['audio_codec'].upper())} ${data['audio_channel_layout'].split('(')[0].capitalize()})
% endif
</div>
</li>
% endif
% if data['media_type'] in ('movie', 'episode', 'clip'):
<li class="dashboard-activity-info-item">
<div class="sub-heading">Subtitle</div>
<div class="sub-value" id="subtitle_decision-${sk}">
% if data['subtitles'] == 1:
% if data['stream_subtitle_decision'] == 'transcode':
Transcode (${data['subtitle_codec'].upper()} <i class="fa fa-long-arrow-right"></i> ${data['stream_subtitle_codec'].upper()})
% elif data['stream_subtitle_decision'] == 'copy':
Direct Stream (${data['subtitle_codec'].upper()})
% elif data['stream_subtitle_decision'] == 'burn':
Burn (${data['subtitle_codec'].upper()})
% else:
Direct Play (${data['stream_subtitle_codec'].upper() if data['synced_version'] else data['subtitle_codec'].upper()})
% endif
% else:
None
% endif
</div>
</li>
% endif
</ul>
<ul class="list-unstyled dashboard-activity-info-list">
<li class="dashboard-activity-info-item">
<div class="sub-heading">Location</div>
<div class="sub-value time-right">
<span id="location-${sk}">${data['location'].upper()}</span>:
% if data['ip_address'] != 'N/A':
<span class="ip-container"><span class="ip-address">${data['ip_address']}</span></span>
% if data['relay']:
<span data-toggle="tooltip" title="Plex Relay"><i class="fa fa-exclamation-circle"></i></span>
% else:
<a href="#" class="external_ip-modal" data-toggle="modal" data-target="#ip-info-modal" data-ip="${data['ip_address']}">
<span id="external_ip-${sk}" class="external-ip-tooltip" data-toggle="tooltip" title="Lookup External IP" style="display: none;"><i class="fa fa-map-marker"></i></span>
</a>
<script>
isPrivateIP("${data['ip_address']}").then(function () {
$("#external_ip-${sk}").hide();
}, function () {
$("#external_ip-${sk}").show();
});
</script>
% endif
% else:
N/A
% endif
</div>
</li>
<li class="dashboard-activity-info-item">
<div class="sub-heading">Bandwidth</div>
<div class="sub-value time-right">
% if data['media_type'] != 'photo' and data['bandwidth'] != 'Unknown':
<%
bw = helpers.cast_to_int(data['bandwidth'])
if bw > 1000:
bw = str(round(bw / 1000.0, 1)) + ' Mbps'
else:
bw = str(bw) + ' kbps'
%>
<span id="stream-bandwidth-${sk}">${bw}</span>
<span id="streaming-brain-${sk}" data-toggle="tooltip" title="Streaming Brain Estimate (Required Bandwidth)"><i class="fa fa-info-circle"></i></span>
% elif data['synced_version'] == 1 or data['channel_stream'] == 1:
<span id="stream-bandwidth-${sk}">None</span>
% else:
<span id="stream-bandwidth-${sk}">Unknown</span>
% endif
</div>
</li>
</ul>
</div>
</div>
% if data['media_type'] != 'photo':
<div class="dashboard-activity-info-time">
% if data['live'] == 1:
<br />Live
% elif data['view_offset']:
ETA:
<span id="stream-eta-${sk}">
<script>
$("#stream-eta-${sk}").html(moment().add(parseInt("${data['stream_duration']}") - parseInt("${data['view_offset']}"), 'milliseconds').format(time_format));
</script>
</span><br /><span class="progress_time_offset" id="stream-view-offset-${sk}" data-last_view_offset="${data['view_offset']}" data-view_offset="${data['view_offset']}" data-stream_duration="${data['stream_duration']}" data-state="${data['state']}">
<script>
$("#stream-view-offset-${sk}").html(millisecondsToMinutes(parseInt("${data['view_offset']}"), false));
</script>
</span> / <span class="progress_time_total" id="stream-duration-${sk}">
<script>
$("#stream-duration-${sk}").html(millisecondsToMinutes(parseInt("${data['stream_duration']}"), false));
</script>
</span>
% else:
ETA: Unknown<br />0:00 / <span class="progress_time_total" id="stream-duration-${sk}">
<script>
$("#stream-duration-${sk}").html(millisecondsToMinutes(parseInt("${data['stream_duration']}"), false));
</script>
</span>
% endif
</div>
% endif
</div>
</div>
<div class="dashboard-activity-progress">
<div class="dashboard-activity-progress-bar">
% if data['live'] == 1:
<div id="progress-bar-${sk}" class="progress-bar" style="width: 100%" data-toggle="tooltip" title="Stream Progress Live">Live</div>
% 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="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>
% endif
</div>
</div>
</div>
<div class="dashboard-activity-metadata-wrapper">
<a href="${user_href}" title="${data['friendly_name']}">
<div class="dashboard-activity-metadata-user-thumb" style="background-image: url(${data['user_thumb']});"></div>
</a>
<div class="dashboard-activity-metadata-title-container">
<div id="play-state-${sk}" class="dashboard-activity-metadata-play_state-icon" title="${data['state'].capitalize()}">
% if data['state'] == 'playing':
<i class="fa fa-fw fa-play"></i>&nbsp;
% elif data['state'] == 'paused':
<i class="fa fa-fw fa-pause"></i>&nbsp;
% elif data['state'] == 'buffering':
<i class="fa fa-fw fa-spinner"></i>&nbsp;
% endif
</div>
<div class="dashboard-activity-metadata-title">
% if data['channel_stream'] == 0:
% if data['media_type'] == 'movie':
<a href="${href}" title="${data['title']}">${data['title']}</a>
% elif data['media_type'] == 'episode':
<a href="${grandparent_href}" title="${data['grandparent_title']}">${data['grandparent_title']}</a>
- <a href="${href}" title="${data['title']}">${data['title']}</a>
% elif data['media_type'] == 'track':
<a id="metadata-title-${sk}" href="${href}" title="${data['title']}">${data['title']}</a>
- <a id="metadata-grandparent_title-${sk}" href="${grandparent_href}" title="${data['original_title'] or data['grandparent_title']}">${data['original_title'] or data['grandparent_title']}</a>
% elif data['media_type'] == 'photo':
<span title="${data['parent_title']}">${data['parent_title']}</span>
% elif data['media_type'] == 'clip':
<span title="${data['title']}">${data['title']}</span>
% else:
<span title="${data['title']}">${data['title']}</span>
% endif
% elif data['media_type'] == 'episode' and data['grandparent_title']:
<span title="${data['grandparent_title']}">${data['grandparent_title']}</span>
- <span title="${data['title']}">${data['title']}</span>
% else:
<span title="${data['title']}">${data['title']}</span>
% endif
</div>
</div>
<div class="dashboard-activity-metadata-subtitle-container">
% if data['live'] == 1:
<div id="media-type-${sk}" class="dashboard-activity-metadata-media_type-icon" title="Plex Live TV">
<i class="fa fa-fw fa-television"></i>&nbsp;
</div>
% elif data['channel_stream'] == 0:
<div id="media-type-${sk}" class="dashboard-activity-metadata-media_type-icon" title="${data['media_type'].capitalize()}">
% if data['media_type'] == 'movie':
<i class="fa fa-fw fa-film"></i>&nbsp;
% elif data['media_type'] == 'episode':
<i class="fa fa-fw fa-television"></i>&nbsp;
% elif data['media_type'] == 'track':
<i class="fa fa-fw fa-music"></i>&nbsp;
% elif data['media_type'] == 'photo':
<i class="fa fa-fw fa-picture-o"></i>&nbsp;
% elif data['media_type'] == 'clip':
<i class="fa fa-fw fa-video-camera"></i>&nbsp;
% endif
</div>
% else:
<div id="media-type-${sk}" class="dashboard-activity-metadata-media_type-icon" title="Channel">
<i class="fa fa-fw fa-cloud"></i>&nbsp;
</div>
% endif
<div class="dashboard-activity-metadata-subtitle">
% if data['live'] == 1:
<span title="Plex Live TV" class="sub-heading">Plex Live TV</span>
% elif data['channel_stream'] == 0:
% if data['media_type'] == 'movie':
<span title="${data['year']}" class="sub-heading">${data['year']}</span>
% elif data['media_type'] == 'episode':
<a href="${parent_href}" title="Season ${data['parent_media_index']}" class="sub-heading">S${data['parent_media_index']}</a>
&middot; <a href="${href}" title="Episode ${data['media_index']}" class="sub-heading">E${data['media_index']}</a>
% elif data['media_type'] == 'track':
<a id="metadata-parent_title-${sk}" href="${parent_href}" title="${data['parent_title']}" class="sub-heading">${data['parent_title']}</a>
% elif data['media_type'] == 'photo':
<span title="${data['title']}" class="sub-heading">${data['title']}</span>
% else:
% if data['extra_type']:
<% extra_type = EXTRA_TYPES.get(data['extra_type'], data['sub_type'].capitalize()) %>
<span title="${data['year']} (${extra_type})" class="sub-heading">${data['year']} (${extra_type})</span>
% else:
<span title="${data['year']}" class="sub-heading">${data['year']}</span>
% endif
% endif
% elif data['channel_title']:
<span title="${data['channel_title']}" class="sub-heading">${data['channel_title']}</span>
% if data['media_type'] == 'episode' and data['parent_media_index'] and data['media_index']:
(<span title="Season ${data['parent_media_index']}" class="sub-heading">S${data['parent_media_index']}</span>
&middot; <span title="Episode ${data['media_index']}" class="sub-heading">E${data['media_index']}</span>)
% elif data['media_type'] == 'episode' and data['originally_available_at']:
(<span title="${data['originally_available_at']}" class="sub-heading">${data['originally_available_at']}</span>)
% endif
% else:
<span title="Channel" class="sub-heading">Channel</span>
% if data['media_type'] == 'episode' and data['parent_media_index'] and data['media_index']:
(<span title="Season ${data['parent_media_index']}" class="sub-heading">S${data['parent_media_index']}</span>
&middot; <span title="Episode ${data['media_index']}" class="sub-heading">E${data['media_index']}</span>)
% elif data['media_type'] == 'episode' and data['originally_available_at']:
(<span title="${data['originally_available_at']}" class="sub-heading">${data['originally_available_at']}</span>)
% endif
% endif
</div>
<div class="dashboard-activity-metadata-user">
<a href="${user_href}" title="${data['friendly_name']}">${data['friendly_name']}</a>
</div>
</div>
</div>
</div>
% endif

View File

@@ -45,13 +45,7 @@ DOCUMENTATION :: END
<input type="text" class="form-control" id="custom_thumb_url" name="custom_thumb_url" value="${data['library_thumb']}"> <input type="text" class="form-control" id="custom_thumb_url" name="custom_thumb_url" value="${data['library_thumb']}">
</div> </div>
</div> </div>
<p class="help-block">Change the library's picture in PlexPy. To reset to default, leave this field empty and save.</p> <p class="help-block">Change the library's picture in Tautulli. To reset to default, leave this field empty and save.</p>
</div>
<div class="checkbox">
<label>
<input type="checkbox" id="do_notify" name="do_notify" value="1" ${helpers.checked(data['do_notify'])}> Enable notifications
</label>
<p class="help-block">Uncheck this if you do not want to receive notifications for this library's activity.</p>
</div> </div>
<div class="checkbox"> <div class="checkbox">
<label> <label>
@@ -59,12 +53,6 @@ DOCUMENTATION :: END
</label> </label>
<p class="help-block">Uncheck this if you do not want to keep any history on this library's activity.</p> <p class="help-block">Uncheck this if you do not want to keep any history on this library's activity.</p>
</div> </div>
<div class="checkbox">
<label>
<input type="checkbox" id="do_notify_created" name="do_notify_created" value="1" ${helpers.checked(data['do_notify_created'])}> Enable recently added notifications
</label>
<p class="help-block">Uncheck this if you do not want to receive recently added notifications for this library.</p>
</div>
% if data['section_id']: % if data['section_id']:
<div class="form-group"> <div class="form-group">
<button class="btn btn-danger" id="delete-all-history">Purge</button> <button class="btn btn-danger" id="delete-all-history">Purge</button>
@@ -81,37 +69,11 @@ DOCUMENTATION :: END
</div> </div>
</div> </div>
</div> </div>
<div id="confirm-modal-purge" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="confirm-modal-purge">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
<h4 class="modal-title" id="myModalLabel">Confirm Purge</h4>
</div>
<div class="modal-body" style="text-align: center;">
<p>Are you REALLY sure you want to purge all history for this library?</p>
<p>This is permanent and cannot be undone!</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-dark" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-danger btn-ok" data-dismiss="modal" id="confirm-purge">Purge</button>
</div>
</div>
</div>
</div>
<script> <script>
// Save library options // Save library options
$("#save_library").on('click', function () { $("#save_library").on('click', function () {
var custom_thumb = $("#custom_thumb_url").val(); var custom_thumb = $("#custom_thumb_url").val();
var do_notify = 0;
var do_notify_created = 0;
var keep_history = 0; var keep_history = 0;
if ($("#do_notify").is(":checked")) {
do_notify = 1;
}
if ($("#do_notify_created").is(":checked")) {
do_notify_created = 1;
}
if ($("#keep_history").is(":checked")) { if ($("#keep_history").is(":checked")) {
keep_history = 1; keep_history = 1;
} }
@@ -121,8 +83,6 @@ DOCUMENTATION :: END
data: { data: {
section_id: '${data["section_id"]}', section_id: '${data["section_id"]}',
custom_thumb: custom_thumb, custom_thumb: custom_thumb,
do_notify: do_notify,
do_notify_created: do_notify_created,
keep_history: keep_history keep_history: keep_history
}, },
cache: false, cache: false,
@@ -133,47 +93,19 @@ DOCUMENTATION :: END
}); });
}); });
$("#delete-all-history").on('click', function() { $('#delete-all-history').click(function () {
$('#confirm-modal-purge').modal(); var msg = 'Are you REALLY sure you want to purge all history for the <strong>${data["section_name"]}</strong> library?<br>' +
$('#confirm-modal-purge').one('click', '#confirm-purge', function () { 'This is permanent and cannot be undone!';
$.ajax({ var url = 'delete_all_library_history';
url: 'delete_all_library_history', confirmAjaxCall(url, msg, { section_id: '${data["section_id"]}' }, null, function () { location.reload(); });
data: { section_id: '${data["section_id"]}' },
cache: false,
async: true,
success: function(data) {
location.reload();
}
});
});
}); });
$(document).ready(function() { $(document).ready(function() {
// Move #confirm-modal to parent container // Move #confirm-modal to parent container
if (!($('#edit-library-modal').next().is('#confirm-modal-purge'))) { if (!($('#edit-library-modal').next().is('#confirm-modal-purge'))) {
$('#confirm-modal-purge').appendTo($('#edit-library-modal').parent()); $('#confirm-modal-purge').appendTo($('#edit-library-modal').parent());
} }
$('#edit-library-modal > #confirm-modal-purge').remove(); $('#edit-library-modal > #confirm-modal-purge').remove();
$('#edit-library-modal').css('z-index', '1050');
$('.modal-backdrop').not('.modal-backdrop-stack').css('z-index', '1049');
$('.modal-backdrop').not('.modal-backdrop-stack').addClass('modal-backdrop-stack');
$('#confirm-modal-purge').on('show.bs.modal', function () {
// Fix position to match parent modal
var currentPadding = parseInt($('body').css('padding-right'));
$(this).children('.modal-dialog').css('left', -currentPadding/2);
$('#edit-library-modal').css('overflow-y', 'hidden');
});
$('#confirm-modal-purge').on('shown.bs.modal', function () {
$(this).css('z-index', '1060');
$('.modal-backdrop').not('.modal-backdrop-stack').css('z-index', '1059');
$('.modal-backdrop').not('.modal-backdrop-stack').addClass('modal-backdrop-stack');
});
$('#confirm-modal-purge').on('hidden.bs.modal', function () {
$('body').addClass('modal-open');
$('#edit-library-modal').css('overflow-y', 'auto');
});
}); });
</script> </script>
% endif % endif

View File

@@ -20,6 +20,7 @@ is_allow_sync Returns bool value for whether the user has sync rights.
is_restricted Returns bool value for whether the user account is restricted. is_restricted Returns bool value for whether the user account is restricted.
do_notify Returns bool value for whether to send notifications for the user. do_notify Returns bool value for whether to send notifications for the user.
keep_history Returns bool value for whether to keep history for the user. keep_history Returns bool value for whether to keep history for the user.
allow_guest Returns bool value for whether to allow guest access for the user.
DOCUMENTATION :: END DOCUMENTATION :: END
</%doc> </%doc>
@@ -44,7 +45,7 @@ DOCUMENTATION :: END
<input type="text" class="form-control" id="friendly_name" name="friendly_name" value="${data['friendly_name']}" size="30"> <input type="text" class="form-control" id="friendly_name" name="friendly_name" value="${data['friendly_name']}" size="30">
</div> </div>
</div> </div>
<p class="help-block">Replace all occurances of the username with this name.</p> <p class="help-block">Replace all occurrences of the username with this name.</p>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="profile_url">Profile Picture URL</label> <label for="profile_url">Profile Picture URL</label>
@@ -53,13 +54,7 @@ DOCUMENTATION :: END
<input type="text" class="form-control" id="custom_avatar_url" name="custom_avatar_url" value="${data['user_thumb']}"> <input type="text" class="form-control" id="custom_avatar_url" name="custom_avatar_url" value="${data['user_thumb']}">
</div> </div>
</div> </div>
<p class="help-block">Change the users profile picture in PlexPy. To reset to default, leave this field empty and save.</p> <p class="help-block">Change the users profile picture in Tautulli. To reset to default, leave this field empty and save.</p>
</div>
<div class="checkbox">
<label>
<input type="checkbox" id="do_notify" name="do_notify" value="1" ${helpers.checked(data['do_notify'])}> Enable notifications
</label>
<p class="help-block">Uncheck this if you do not want to receive notifications for this user's activity.</p>
</div> </div>
<div class="checkbox"> <div class="checkbox">
<label> <label>
@@ -67,6 +62,12 @@ DOCUMENTATION :: END
</label> </label>
<p class="help-block">Uncheck this if you do not want to keep any history on this user's activity.</p> <p class="help-block">Uncheck this if you do not want to keep any history on this user's activity.</p>
</div> </div>
<div class="checkbox">
<label>
<input type="checkbox" id="allow_guest" name="allow_guest" value="1" ${helpers.checked(data['allow_guest'])}> Allow Guest Access
</label>
<p class="help-block">Uncheck this if you do not want to allow this user to login to Tautulli.</p>
</div>
% if data['user_id']: % if data['user_id']:
<div class="form-group"> <div class="form-group">
<button class="btn btn-danger" id="delete-all-history">Purge</button> <button class="btn btn-danger" id="delete-all-history">Purge</button>
@@ -83,37 +84,19 @@ DOCUMENTATION :: END
</div> </div>
</div> </div>
</div> </div>
<div id="confirm-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="confirm-modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
<h4 class="modal-title" id="myModalLabel">Confirm Purge</h4>
</div>
<div class="modal-body" style="text-align: center;">
<p>Are you REALLY sure you want to purge all history for this user?</p>
<p>This is permanent and cannot be undone!</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-dark" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-danger btn-ok" data-dismiss="modal" id="confirm-purge">Purge</button>
</div>
</div>
</div>
</div>
<script> <script>
// Set user options // Set user options
$("#save_user").on('click', function () { $("#save_user").on('click', function () {
var friendly_name = $("#friendly_name").val(); var friendly_name = $("input#friendly_name").val();
var custom_thumb = $("#custom_avatar_url").val(); var custom_thumb = $("#custom_avatar_url").val();
var do_notify = 0;
var keep_history = 0; var keep_history = 0;
if ($("#do_notify").is(":checked")) { var allow_guest = 0;
do_notify = 1;
}
if ($("#keep_history").is(":checked")) { if ($("#keep_history").is(":checked")) {
keep_history = 1; keep_history = 1;
} }
if ($("#allow_guest").is(":checked")) {
allow_guest = 1;
}
$.ajax({ $.ajax({
url: 'edit_user', url: 'edit_user',
@@ -121,8 +104,8 @@ DOCUMENTATION :: END
user_id: '${data["user_id"]}', user_id: '${data["user_id"]}',
friendly_name: friendly_name, friendly_name: friendly_name,
custom_thumb: custom_thumb, custom_thumb: custom_thumb,
do_notify: do_notify, keep_history: keep_history,
keep_history: keep_history allow_guest: allow_guest
}, },
cache: false, cache: false,
async: true, async: true,
@@ -132,47 +115,19 @@ DOCUMENTATION :: END
}); });
}); });
$("#delete-all-history").on('click', function() { $('#delete-all-history').click(function () {
$('#confirm-modal').modal(); var msg = 'Are you REALLY sure you want to purge all history for the <strong>${data["username"]}</strong> user?<br>' +
$('#confirm-modal').one('click', '#confirm-purge', function () { 'This is permanent and cannot be undone!';
$.ajax({ var url = 'delete_all_user_history';
url: 'delete_all_user_history', confirmAjaxCall(url, msg, { user_id: '${data["user_id"]}' }, null, function () { location.reload(); });
data: { user_id: '${data["user_id"]}' },
cache: false,
async: true,
success: function(data) {
location.reload();
}
});
});
}); });
$(document).ready(function() { $(document).ready(function() {
// Move #confirm-modal to parent container // Move #confirm-modal-purge to parent container
if(!($('#edit-user-modal').next().is('#confirm-modal'))) { if (!($('#edit-user-modal').next().is('#confirm-modal-purge'))) {
$('#confirm-modal').appendTo($('#edit-user-modal').parent()); $('#confirm-modal-purge').appendTo($('#edit-user-modal').parent());
} }
$('#edit-user-modal > #confirm-modal').remove(); $('#edit-user-modal > #confirm-modal-purge').remove();
$('#edit-user-modal').css('z-index', '1050');
$('.modal-backdrop').not('.modal-backdrop-stack').css('z-index', '1049');
$('.modal-backdrop').not('.modal-backdrop-stack').addClass('modal-backdrop-stack');
$('#confirm-modal').on('show.bs.modal', function () {
// Fix position to match parent modal
var currentPadding = parseInt($('body').css('padding-right'));
$(this).children('.modal-dialog').css('left', -currentPadding/2);
$('#edit-user-modal').css('overflow-y', 'hidden');
});
$('#confirm-modal').on('shown.bs.modal', function () {
$(this).css('z-index', '1060');
$('.modal-backdrop').not('.modal-backdrop-stack').css('z-index', '1059');
$('.modal-backdrop').not('.modal-backdrop-stack').addClass('modal-backdrop-stack');
});
$('#confirm-modal').on('hidden.bs.modal', function() {
$('body').addClass('modal-open');
$('#edit-user-modal').css('overflow-y', 'auto');
});
}); });
</script> </script>
% endif % endif

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 104 KiB

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 105 KiB

View File

@@ -1,8 +1,8 @@
<%inherit file="base.html"/> <%inherit file="base.html"/>
<%def name="headIncludes()"> <%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css"> <link rel="stylesheet" href="${http_root}css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css"> <link rel="stylesheet" href="${http_root}css/tautulli-dataTables.css">
</%def> </%def>
<%def name="body()"> <%def name="body()">
@@ -11,8 +11,16 @@
<div class="header-bar"> <div class="header-bar">
<span><i class="fa fa-bar-chart"></i> Graphs</span> <span><i class="fa fa-bar-chart"></i> Graphs</span>
</div> </div>
<div class="button-bar hidden-xs"> <div class="button-bar">
<div class="btn-group" data-toggle="buttons" id="yaxis-selection"> <div class="btn-group" id="user-selection">
<label>
<select name="graph-user" id="graph-user" class="btn" style="color: inherit;">
<option value="">All Users</option>
<option disabled>&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;</option>
</select>
</label>
</div>
<div class="btn-group" style="margin-right: 2px;" data-toggle="buttons" id="yaxis-selection">
% if config['graph_type'] == 'duration': % if config['graph_type'] == 'duration':
<label class="btn btn-dark"> <label class="btn btn-dark">
<input type="radio" name="yaxis-options" id="yaxis-count" value="plays" autocomplete="off"> Play Count <input type="radio" name="yaxis-options" id="yaxis-count" value="plays" autocomplete="off"> Play Count
@@ -29,11 +37,16 @@
</label> </label>
% endif % endif
</div> </div>
<div class="btn-group" id="days-selection"> <div class="input-group pull-right" style="width: 1px;" id="days-selection">
<label> <span class="input-group-addon btn-dark inactive">Last</span>
<input type="number" name="graph-days" id="graph-days" value="${config['graph_days']}" min="1" /> days <input type="number" class="form-control number-input" name="graph-days" id="graph-days" value="${config['graph_days']}" min="1" data-default="7" data-toggle="tooltip" title="Min: 1 day" />
</label> <span class="input-group-addon btn-dark inactive">days</span>
</div> </div>
<div class="input-group pull-right" style="width: 1px;" id="months-selection">
<span class="input-group-addon btn-dark inactive">Last</span>
<input type="number" class="form-control number-input" name="graph-months" id="graph-months" value="${config['graph_months']}" min="1" data-default="12" data-toggle="tooltip" title="Min: 1 month" />
<span class="input-group-addon btn-dark inactive">months</span>
</div>
</div> </div>
</div> </div>
<div class='table-card-back'> <div class='table-card-back'>
@@ -155,7 +168,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<h4><i class="fa fa-expand"></i> <span class="yaxis-text">Play count</span> by source resolution <small>Last <span class="days">30</span> days</small></h4> <h4><i class="fa fa-expand-arrows-alt"></i> <span class="yaxis-text">Play count</span> by source resolution <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block"> <p class="help-block">
The combined total of tv and movies by their original resolution (pre-transcoding). The combined total of tv and movies by their original resolution (pre-transcoding).
</p> </p>
@@ -168,7 +181,7 @@
</div> </div>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<h4><i class="fa fa-expand"></i> <span class="yaxis-text">Play count</span> by stream resolution <small>Last <span class="days">30</span> days</small></h4> <h4><i class="fa fa-expand-arrows-alt"></i> <span class="yaxis-text">Play count</span> by stream resolution <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block"> <p class="help-block">
The combined total of tv and movies by their streamed resolution (post-transcoding). The combined total of tv and movies by their streamed resolution (post-transcoding).
</p> </p>
@@ -218,7 +231,7 @@
% endif % endif
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<h4><i class="fa fa-calendar"></i> Plays by Month <small>Last 12 months</small></h4> <h4><i class="fa fa-calendar"></i> Plays by month <small>Last <span class="months">12</span> months</small></h4>
<p class="help-block"> <p class="help-block">
The combined total of tv, movies, and music by month. The combined total of tv, movies, and music by month.
</p> </p>
@@ -232,24 +245,31 @@
</div> </div>
</div> </div>
</div> </div>
<div class="modal fade" id="history-modal" tabindex="-1" role="dialog" aria-labelledby="history-modal">
</div>
</div> </div>
</div> </div>
</div> </div>
</%def> </%def>
<%def name="modalIncludes()">
<div class="modal fade" id="history-modal" tabindex="-1" role="dialog" aria-labelledby="history-modal">
</div>
<div class="modal fade" id="info-modal" tabindex="-1" role="dialog" aria-labelledby="info-modal">
</div>
</%def>
<%def name="javascriptIncludes()"> <%def name="javascriptIncludes()">
<script src="interfaces/default/js/moment-with-locale.js"></script> <script src="${http_root}js/moment-with-locale.js"></script>
<script src="interfaces/default/js/moment-duration-format.js"></script> <script src="${http_root}js/moment-duration-format.js"></script>
<script src="interfaces/default/js/highcharts/js/highcharts.js"></script> <script src="${http_root}js/highcharts/js/highcharts.js"></script>
<script src="interfaces/default/js/jquery.dataTables.min.js"></script> <script src="${http_root}js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script> <script src="${http_root}js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script> <script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
<script> <script>
var selected_user_id = null
// Modal popup dialog // Modal popup dialog
function selectHandler(selectedDate) { function selectHandler(selectedDate, selectedSeries) {
try try
{ {
@@ -259,67 +279,116 @@
var y = dateValue.getFullYear(); var y = dateValue.getFullYear();
var dateString = '' + y + '-' + (m<=9 ? '0' + m : m) + '-' + (d <= 9 ? '0' + d : d); var dateString = '' + y + '-' + (m<=9 ? '0' + m : m) + '-' + (d <= 9 ? '0' + d : d);
var media_type = null;
var transcode_decision = null;
switch(selectedSeries) {
case "TV": media_type = 'episode'; break;
case "Movies": media_type = 'movie'; break;
case "Music": media_type = 'track'; break;
case "Direct Play": transcode_decision = 'direct play'; break;
case "Direct Stream": transcode_decision = 'copy'; break;
case "Transcode": transcode_decision = 'transcode'; break;
}
$.ajax({ $.ajax({
"url": "history_table_modal", url: "history_table_modal",
type: 'post', cache: false,
data: { 'start_date': dateString }, async: true,
data: {
user_id: selected_user_id,
start_date: dateString,
media_type: media_type,
transcode_decision: transcode_decision
},
complete: function(xhr, status) { complete: function(xhr, status) {
$('#history-modal').modal('show');
$("#history-modal").html(xhr.responseText); $("#history-modal").html(xhr.responseText);
$('#history-modal').modal();
} }
}); });
} }
catch(err) catch(err)
{ {
console.log("Failed to retrieve data"); console.log("Failed to retrieve history modal data.");
} }
} }
</script> </script>
<script src="interfaces/default/js/graphs/plays_by_day.js"></script> <script src="${http_root}js/graphs/plays_by_day.js"></script>
<script src="interfaces/default/js/graphs/plays_by_dayofweek.js"></script> <script src="${http_root}js/graphs/plays_by_dayofweek.js"></script>
<script src="interfaces/default/js/graphs/plays_by_hourofday.js"></script> <script src="${http_root}js/graphs/plays_by_hourofday.js"></script>
<script src="interfaces/default/js/graphs/plays_by_platform.js"></script> <script src="${http_root}js/graphs/plays_by_platform.js"></script>
<script src="interfaces/default/js/graphs/plays_by_user.js"></script> <script src="${http_root}js/graphs/plays_by_user.js"></script>
<script src="interfaces/default/js/graphs/plays_by_stream_type.js"></script> <script src="${http_root}js/graphs/plays_by_stream_type.js"></script>
<script src="interfaces/default/js/graphs/plays_by_source_resolution.js"></script> <script src="${http_root}js/graphs/plays_by_source_resolution.js"></script>
<script src="interfaces/default/js/graphs/plays_by_stream_resolution.js"></script> <script src="${http_root}js/graphs/plays_by_stream_resolution.js"></script>
<script src="interfaces/default/js/graphs/plays_by_platform_by_stream_type.js"></script> <script src="${http_root}js/graphs/plays_by_platform_by_stream_type.js"></script>
<script src="interfaces/default/js/graphs/plays_by_user_by_stream_type.js"></script> <script src="${http_root}js/graphs/plays_by_user_by_stream_type.js"></script>
<script src="interfaces/default/js/graphs/plays_by_month.js"></script> <script src="${http_root}js/graphs/plays_by_month.js"></script>
<script> <script>
$(document).ready(function () { $(document).ready(function () {
// Initial values for graph from config // Initial values for graph from config
var yaxis = "${config['graph_type']}"; var yaxis = "${config['graph_type']}";
var current_range = ${config['graph_days']}; var current_day_range = ${config['graph_days']};
var current_month_range = ${config['graph_months']};
var current_tab = "${'#' + config['graph_tab']}"; var current_tab = "${'#' + config['graph_tab']}";
$('.days').html(current_range); $('.days').html(current_day_range);
$('.months').html(current_month_range);
// Load user ids and names (for the selector)
$.ajax({
url: 'get_user_names',
type: 'get',
dataType: "json",
success: function (data) {
var select = $('#graph-user');
data.sort(function(a, b) {
return a.friendly_name.localeCompare(b.friendly_name);
});
data.forEach(function(item) {
select.append('<option value="' + item.user_id + '">' +
item.friendly_name + '</option>');
});
}
});
var music_visible = (${config['music_logging_enable']} == 1 ? true : false); var music_visible = (${config['music_logging_enable']} == 1 ? true : false);
function dataSecondsToHours(data) {
$.each(data.series, function (i, series) {
series.data = $.map(series.data, function (value) {
return value / 60 / 60;
});
});
}
function loadGraphsTab1(time_range, yaxis) { function loadGraphsTab1(time_range, yaxis) {
$('#days-selection').show();
$('#months-selection').hide();
setGraphFormat(yaxis); setGraphFormat(yaxis);
$.ajax({ $.ajax({
url: "get_plays_by_date", url: "get_plays_by_date",
type: 'get', type: 'get',
data: { time_range: time_range, y_axis: yaxis }, data: { time_range: time_range, y_axis: yaxis, user_id: selected_user_id },
dataType: "json", dataType: "json",
success: function(data) { success: function(data) {
var dateArray = []; var dateArray = [];
for (var i = 0; i < data.categories.length; i++) { $.each(data.categories, function (i, day) {
dateArray.push(moment(data.categories[i], 'YYYY-MM-DD').valueOf()); dateArray.push(moment(day, 'YYYY-MM-DD').valueOf());
// Highlight the weekend // Highlight the weekend
if ((moment(data.categories[i], 'YYYY-MM-DD').format('ddd') == 'Sat') || if ((moment(day, 'YYYY-MM-DD').format('ddd') == 'Sat') ||
(moment(data.categories[i], 'YYYY-MM-DD').format('ddd') == 'Sun')) { (moment(day, 'YYYY-MM-DD').format('ddd') == 'Sun')) {
hc_plays_by_day_options.xAxis.plotBands.push({ hc_plays_by_day_options.xAxis.plotBands.push({
from: i-0.5, from: i-0.5,
to: i+0.5, to: i+0.5,
color: 'rgba(80,80,80,0.3)' color: 'rgba(80,80,80,0.3)'
}); });
} }
} });
if (yaxis === 'duration') { dataSecondsToHours(data); }
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 = data.series; hc_plays_by_day_options.series = data.series;
@@ -331,9 +400,10 @@
$.ajax({ $.ajax({
url: "get_plays_by_dayofweek", url: "get_plays_by_dayofweek",
type: 'get', type: 'get',
data: { time_range: time_range, y_axis: yaxis }, data: { time_range: time_range, y_axis: yaxis, user_id: selected_user_id },
dataType: "json", dataType: "json",
success: function(data) { success: function(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 = data.series; hc_plays_by_dayofweek_options.series = data.series;
hc_plays_by_dayofweek_options.series[2].visible = music_visible; hc_plays_by_dayofweek_options.series[2].visible = music_visible;
@@ -344,9 +414,10 @@
$.ajax({ $.ajax({
url: "get_plays_by_hourofday", url: "get_plays_by_hourofday",
type: 'get', type: 'get',
data: { time_range: time_range, y_axis: yaxis }, data: { time_range: time_range, y_axis: yaxis, user_id: selected_user_id },
dataType: "json", dataType: "json",
success: function(data) { success: function(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 = data.series; hc_plays_by_hourofday_options.series = data.series;
hc_plays_by_hourofday_options.series[2].visible = music_visible; hc_plays_by_hourofday_options.series[2].visible = music_visible;
@@ -357,9 +428,10 @@
$.ajax({ $.ajax({
url: "get_plays_by_top_10_platforms", url: "get_plays_by_top_10_platforms",
type: 'get', type: 'get',
data: { time_range: time_range, y_axis: yaxis }, data: { time_range: time_range, y_axis: yaxis, user_id: selected_user_id },
dataType: "json", dataType: "json",
success: function(data) { success: function(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 = data.series; hc_plays_by_platform_options.series = data.series;
hc_plays_by_platform_options.series[2].visible = music_visible; hc_plays_by_platform_options.series[2].visible = music_visible;
@@ -370,9 +442,10 @@
$.ajax({ $.ajax({
url: "get_plays_by_top_10_users", url: "get_plays_by_top_10_users",
type: 'get', type: 'get',
data: { time_range: time_range, y_axis: yaxis }, data: { time_range: time_range, y_axis: yaxis, user_id: selected_user_id },
dataType: "json", dataType: "json",
success: function(data) { success: function(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 = data.series; hc_plays_by_user_options.series = data.series;
hc_plays_by_user_options.series[2].visible = music_visible; hc_plays_by_user_options.series[2].visible = music_visible;
@@ -382,27 +455,31 @@
} }
function loadGraphsTab2(time_range, yaxis) { function loadGraphsTab2(time_range, yaxis) {
$('#days-selection').show();
$('#months-selection').hide();
setGraphFormat(yaxis); setGraphFormat(yaxis);
$.ajax({ $.ajax({
url: "get_plays_by_stream_type", url: "get_plays_by_stream_type",
type: 'get', type: 'get',
data: { time_range: time_range, y_axis: yaxis }, data: { time_range: time_range, y_axis: yaxis, user_id: selected_user_id },
dataType: "json", dataType: "json",
success: function(data) { success: function(data) {
var dateArray = []; var dateArray = [];
for (var i = 0; i < data.categories.length; i++) { $.each(data.categories, function (i, day) {
dateArray.push(moment(data.categories[i], 'YYYY-MM-DD').valueOf()); dateArray.push(moment(day, 'YYYY-MM-DD').valueOf());
// Highlight the weekend // Highlight the weekend
if ((moment(data.categories[i], 'YYYY-MM-DD').format('ddd') == 'Sat') || if ((moment(day, 'YYYY-MM-DD').format('ddd') == 'Sat') ||
(moment(data.categories[i], 'YYYY-MM-DD').format('ddd') == 'Sun')) { (moment(day, 'YYYY-MM-DD').format('ddd') == 'Sun')) {
hc_plays_by_stream_type_options.xAxis.plotBands.push({ hc_plays_by_day_options.xAxis.plotBands.push({
from: i-0.5, from: i-0.5,
to: i+0.5, to: i+0.5,
color: 'rgba(80,80,80,0.3)' color: 'rgba(80,80,80,0.3)'
}); });
} }
} });
if (yaxis === 'duration') { dataSecondsToHours(data); }
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 = data.series; hc_plays_by_stream_type_options.series = data.series;
@@ -413,9 +490,10 @@
$.ajax({ $.ajax({
url: "get_plays_by_source_resolution", url: "get_plays_by_source_resolution",
type: 'get', type: 'get',
data: { time_range: time_range, y_axis: yaxis }, data: { time_range: time_range, y_axis: yaxis, user_id: selected_user_id },
dataType: "json", dataType: "json",
success: function(data) { success: function(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 = data.series; hc_plays_by_source_resolution_options.series = 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);
@@ -425,9 +503,10 @@
$.ajax({ $.ajax({
url: "get_plays_by_stream_resolution", url: "get_plays_by_stream_resolution",
type: 'get', type: 'get',
data: { time_range: time_range, y_axis: yaxis }, data: { time_range: time_range, y_axis: yaxis, user_id: selected_user_id },
dataType: "json", dataType: "json",
success: function(data) { success: function(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 = data.series; hc_plays_by_stream_resolution_options.series = 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);
@@ -437,9 +516,10 @@
$.ajax({ $.ajax({
url: "get_stream_type_by_top_10_platforms", url: "get_stream_type_by_top_10_platforms",
type: 'get', type: 'get',
data: { time_range: time_range, y_axis: yaxis }, data: { time_range: time_range, y_axis: yaxis, user_id: selected_user_id },
dataType: "json", dataType: "json",
success: function(data) { success: function(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 = data.series; hc_plays_by_platform_by_stream_type_options.series = 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);
@@ -449,9 +529,10 @@
$.ajax({ $.ajax({
url: "get_stream_type_by_top_10_users", url: "get_stream_type_by_top_10_users",
type: 'get', type: 'get',
data: { time_range: time_range, y_axis: yaxis }, data: { time_range: time_range, y_axis: yaxis, user_id: selected_user_id },
dataType: "json", dataType: "json",
success: function(data) { success: function(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 = data.series; hc_plays_by_user_by_stream_type_options.series = 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);
@@ -459,15 +540,19 @@
}); });
} }
function loadGraphsTab3(yaxis) { function loadGraphsTab3(time_range, yaxis) {
$('#days-selection').hide();
$('#months-selection').show();
setGraphFormat(yaxis); setGraphFormat(yaxis);
$.ajax({ $.ajax({
url: "get_plays_per_month", url: "get_plays_per_month",
type: 'get', type: 'get',
data: { y_axis: yaxis }, data: { time_range: time_range, y_axis: yaxis, user_id: selected_user_id },
dataType: "json", dataType: "json",
success: function(data) { success: function(data) {
if (yaxis === 'duration') { dataSecondsToHours(data); }
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 = data.series; hc_plays_by_month_options.series = data.series;
@@ -478,130 +563,125 @@
} }
// Set initial state // Set initial state
if (current_tab == '#tabs-1') { loadGraphsTab1(current_range, yaxis); } if (current_tab == '#tabs-1') { loadGraphsTab1(current_day_range, yaxis); }
if (current_tab == '#tabs-2') { loadGraphsTab2(current_range, yaxis); } if (current_tab == '#tabs-2') { loadGraphsTab2(current_day_range, yaxis); }
if (current_tab == '#tabs-3') { loadGraphsTab3(yaxis); } if (current_tab == '#tabs-3') { loadGraphsTab3(current_month_range, yaxis); }
// Tab1 opened // Tab1 opened
$('#graph-tabs a[href="#tabs-1"]').on('shown.bs.tab', function (e) { $('#graph-tabs a[href="#tabs-1"]').on('shown.bs.tab', function (e) {
e.preventDefault(); e.preventDefault();
current_tab = $(this).attr('href'); current_tab = $(this).attr('href');
loadGraphsTab1(current_range, yaxis); loadGraphsTab1(current_day_range, yaxis);
$.ajax({ $.post('set_graph_config', { graph_tab: current_tab.replace('#','') });
url: 'set_graph_config',
data: { graph_tab: current_tab.replace('#','') },
async: true
});
}) })
// Tab2 opened // Tab2 opened
$('#graph-tabs a[href="#tabs-2"]').on('shown.bs.tab', function (e) { $('#graph-tabs a[href="#tabs-2"]').on('shown.bs.tab', function (e) {
e.preventDefault(); e.preventDefault();
current_tab = $(this).attr('href'); current_tab = $(this).attr('href');
loadGraphsTab2(current_range, yaxis); loadGraphsTab2(current_day_range, yaxis);
$.ajax({ $.post('set_graph_config', { graph_tab: current_tab.replace('#','') });
url: 'set_graph_config',
data: { graph_tab: current_tab.replace('#','') },
async: true
});
}) })
// Tab3 opened // Tab3 opened
$('#graph-tabs a[href="#tabs-3"]').on('shown.bs.tab', function (e) { $('#graph-tabs a[href="#tabs-3"]').on('shown.bs.tab', function (e) {
e.preventDefault(); e.preventDefault();
current_tab = $(this).attr('href'); current_tab = $(this).attr('href');
loadGraphsTab3(yaxis); loadGraphsTab3(current_month_range, yaxis);
$.ajax({ $.post('set_graph_config', { graph_tab: current_tab.replace('#','') });
url: 'set_graph_config',
data: { graph_tab: current_tab.replace('#','') },
async: true
});
}) })
// Date range changed // Date range changed
$('#graph-days').tooltip({ container: 'body', placement: 'top', html: true });
$('#graph-days').on('change', function() { $('#graph-days').on('change', function() {
current_range = $(this).val(); forceMinMax($(this));
if (current_range < 1) { current_day_range = $(this).val();
$(this).val(7); if (current_tab == '#tabs-1') { loadGraphsTab1(current_day_range, yaxis); }
current_range = 7; if (current_tab == '#tabs-2') { loadGraphsTab2(current_day_range, yaxis); }
} $('.days').html(current_day_range);
if (current_tab == '#tabs-1') { loadGraphsTab1(current_range, yaxis); } $.post('set_graph_config', { graph_days: current_day_range });
if (current_tab == '#tabs-2') { loadGraphsTab2(current_range, yaxis); } });
$('.days').html(current_range);
$.ajax({ // Month range changed
url: 'set_graph_config', $('#graph-months').tooltip({ container: 'body', placement: 'top', html: true });
data: { graph_days: current_range}, $('#graph-months').on('change', function() {
async: true forceMinMax($(this));
}); current_month_range = $(this).val();
if (current_tab == '#tabs-3') { loadGraphsTab3(current_month_range, yaxis); }
$('.months').html(current_month_range);
$.post('set_graph_config', { graph_months: current_month_range });
}); });
// User changed
$('#graph-user').on('change', function() {
selected_user_id = $(this).val() || null;
if (current_tab == '#tabs-1') { loadGraphsTab1(current_day_range, yaxis); }
if (current_tab == '#tabs-2') { loadGraphsTab2(current_day_range, yaxis); }
if (current_tab == '#tabs-3') { loadGraphsTab3(current_month_range, yaxis); }
});
// Y-axis changed // Y-axis changed
$('#yaxis-selection').on('change', function() { $('#yaxis-selection').on('change', function() {
yaxis = $('input[name=yaxis-options]:checked', '#yaxis-selection').val(); yaxis = $('input[name=yaxis-options]:checked', '#yaxis-selection').val();
if (current_tab == '#tabs-1') { loadGraphsTab1(current_range, yaxis); } if (current_tab == '#tabs-1') { loadGraphsTab1(current_day_range, yaxis); }
if (current_tab == '#tabs-2') { loadGraphsTab2(current_range, yaxis); } if (current_tab == '#tabs-2') { loadGraphsTab2(current_day_range, yaxis); }
if (current_tab == '#tabs-3') { loadGraphsTab3(yaxis); } if (current_tab == '#tabs-3') { loadGraphsTab3(current_month_range, yaxis); }
$.ajax({ $.post('set_graph_config', { graph_type: yaxis });
url: 'set_graph_config',
data: { graph_type: yaxis},
async: true
});
}); });
function setGraphFormat(type) { function setGraphFormat(type) {
if (type === 'plays') { if (type === 'plays') {
yaxis_format = function() { return this.value; }; yaxis_format = function() { return this.value; };
tooltip_format = function() { tooltip_format = function() {
if (moment(this.x, 'X').isValid() && (this.x > 946684800)) { if (moment(this.x, 'X').isValid() && (this.x > 946684800)) {
var s = '<b>'+ moment(this.x).format("ddd MMM D") +'</b>'; var s = '<b>'+ moment(this.x).format('ddd MMM D') +'</b>';
} else { } else {
var s = '<b>'+ this.x +'</b>'; var s = '<b>'+ this.x +'</b>';
} }
if (this.points.length > 1) { if (this.points.length > 1) {
var total = 0; var total = 0;
$.each(this.points, function(i, point) { $.each(this.points, function(i, point) {
s += '<br/>'+point.series.name+': '+point.y; s += '<br/>'+point.series.name+': '+point.y;
total += point.y; total += point.y;
}); });
s += '<br><b>Total: '+total+'</b>'; s += '<br><b>Total: '+total+'</b>';
} else { } else {
$.each(this.points, function(i, point) { $.each(this.points, function(i, point) {
s += '<br/>'+point.series.name+': '+point.y; s += '<br/>'+point.series.name+': '+point.y;
}); });
} }
return s; return s;
} }
stack_labels_format = function() { stack_labels_format = function() {
return this.total; return this.total;
} }
$('.yaxis-text').html('Play count'); $('.yaxis-text').html('Play count');
} else { } else {
yaxis_format = function() { return moment.duration(this.value, 'seconds').format("m [mins]"); }; yaxis_format = function() { return moment.duration(this.value, 'hours').format('H [h] m [m]'); };
tooltip_format = function() { tooltip_format = function() {
if (moment(this.x, 'X').isValid() && (this.x > 946684800)) { if (moment(this.x, 'X').isValid() && (this.x > 946684800)) {
var s = '<b>'+ moment(this.x).format("ddd MMM D") +'</b>'; var s = '<b>'+ moment(this.x).format('ddd MMM D') +'</b>';
} else { } else {
var s = '<b>'+ this.x +'</b>'; var s = '<b>'+ this.x +'</b>';
} }
if (this.points.length > 1) { if (this.points.length > 1) {
var total = 0; var total = 0;
$.each(this.points, function(i, point) { $.each(this.points, function(i, point) {
s += '<br/>'+point.series.name+': '+moment.duration(point.y, 'seconds').format('D [days] H [hrs] m [mins]'); s += '<br/>'+point.series.name+': '+moment.duration(point.y, 'hours').format('D [days] H [hrs] m [mins]');
total += point.y; total += point.y;
}); });
s += '<br/><b>Total: '+moment.duration(total, 'seconds').format('D [days] H [hrs] m [mins]')+'</b>'; s += '<br/><b>Total: '+moment.duration(total, 'hours').format('D [days] H [hrs] m [mins]')+'</b>';
} else { } else {
$.each(this.points, function(i, point) { $.each(this.points, function(i, point) {
s += '<br/>'+point.series.name+': '+moment.duration(point.y, 'seconds').format('D [days] H [hrs] m [mins]'); s += '<br/>'+point.series.name+': '+moment.duration(point.y, 'hours').format('D [days] H [hrs] m [mins]');
}); });
} }
return s; return s;
} }
stack_labels_format = function() { stack_labels_format = function() {
var s = moment.duration(this.total, 'seconds').format("H [hrs] m [mins]"); var s = moment.duration(this.total, 'hours').format('H [h] m [m]');
return s; return s;
} }
$('.yaxis-text').html('Play duration'); $('.yaxis-text').html('Play duration');
} }

View File

@@ -1,32 +1,62 @@
<%inherit file="base.html"/> <%inherit file="base.html"/>
<%def name="headIncludes()"> <%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css"> <link rel="stylesheet" href="${http_root}css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.colVis.css"> <link rel="stylesheet" href="${http_root}css/dataTables.colVis.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css"> <link rel="stylesheet" href="${http_root}css/tautulli-dataTables.css">
</%def> </%def>
<%def name="body()"> <%def name="body()">
<div class='container-fluid'> <div class='container-fluid'>
<div class='table-card-header'> <div class='table-card-header'>
<div class="header-bar"> <div class="header-bar">
<span><i class="fa fa-history"></i> History</span> <span><i class="fa fa-history"></i> History</span>
</div> </div>
<div class="button-bar"> <div class="button-bar">
<div class="colvis-button-bar hidden-xs"></div> % if _session['user_group'] == 'admin':
<button class="btn btn-danger btn-edit" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode">
<i class="fa fa-trash-o"></i> Delete mode
</button>
<div class="alert alert-danger alert-edit" role="alert" id="row-edit-mode-alert"><i class="fa fa-exclamation-triangle"></i>&nbspSelect rows to delete. Data is deleted upon exiting delete mode.</div> <div class="alert alert-danger alert-edit" role="alert" id="row-edit-mode-alert"><i class="fa fa-exclamation-triangle"></i>&nbspSelect rows to delete. Data is deleted upon exiting delete mode.</div>
<div class="btn-group">
<button class="btn btn-danger btn-edit" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode">
<i class="fa fa-trash-o"></i> Delete mode
</button>&nbsp
</div>
% endif
% if _session['user_group'] == 'admin':
<div class="btn-group" id="user-selection">
<label>
<select name="history-user" id="history-user" class="btn" style="color: inherit;">
<option value="">All Users</option>
<option disabled>&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;</option>
</select>
</label>
</div>
% endif
<div class="btn-group" data-toggle="buttons" id="media_type-selection">
<label class="btn btn-dark active">
<input type="radio" name="media_type-filter" id="history-all" value="" autocomplete="off"> All
</label>
<label class="btn btn-dark">
<input type="radio" name="media_type-filter" id="history-movies" value="movie" autocomplete="off"> Movies
</label>
<label class="btn btn-dark">
<input type="radio" name="media_type-filter" id="history-tv_shows" value="episode" autocomplete="off"> TV Shows
</label>
<label class="btn btn-dark">
<input type="radio" name="media_type-filter" id="history-music" value="track" autocomplete="off"> Music
</label>
</div>
<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>
</div>
<div class="btn-group colvis-button-bar"></div>
</div> </div>
</div> </div>
<div class='table-card-back'> <div class="table-card-back">
<table class="display" id="history_table" width="100%"> <table class="display history_table" id="history_table" width="100%">
<thead> <thead>
<tr> <tr>
<th align="left" id="delete_row">Delete</th> <th align="left" id="delete_row">Delete</th>
<th align="left" id="time">Time</th> <th align="left" id="date">Date</th>
<th align="left" id="friendly_name">User</th> <th align="left" id="friendly_name">User</th>
<th align="left" id="ip_address">IP Address</th> <th align="left" id="ip_address">IP Address</th>
<th align="left" id="platform">Platform</th> <th align="left" id="platform">Platform</th>
@@ -42,26 +72,29 @@
<tbody> <tbody>
</tbody> </tbody>
</table> </table>
<div class="modal fade" id="info-modal" tabindex="-1" role="dialog" aria-labelledby="info-modal"> </div>
</div> </div>
<div class="modal fade" id="ip-info-modal" tabindex="-1" role="dialog" aria-labelledby="ip-info-modal"> </%def>
</div>
<div class="modal fade" id="confirm-modal" tabindex="-1" role="dialog" aria-labelledby="confirm-modal"> <%def name="modalIncludes()">
<div class="modal-dialog"> <div class="modal fade" id="info-modal" tabindex="-1" role="dialog" aria-labelledby="info-modal">
<div class="modal-content"> </div>
<div class="modal-header"> <div class="modal fade" id="ip-info-modal" tabindex="-1" role="dialog" aria-labelledby="ip-info-modal">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button> </div>
<h4 class="modal-title" id="myModalLabel">Confirm Delete</h4> <div class="modal fade" id="confirm-modal-delete" tabindex="-1" role="dialog" aria-labelledby="confirm-modal-delete">
</div> <div class="modal-dialog">
<div class="modal-body" style="text-align: center;"> <div class="modal-content">
<p>Are you REALLY sure you want to delete <strong><span id="deleteCount"></span></strong> history item(s)?</p> <div class="modal-header">
<p>This is permanent and cannot be undone!</p> <button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
</div> <h4 class="modal-title" id="myModalLabel">Confirm Delete</h4>
<div class="modal-footer"> </div>
<button type="button" class="btn btn-dark" data-dismiss="modal">Cancel</button> <div class="modal-body" style="text-align: center;">
<button type="button" class="btn btn-danger btn-ok" data-dismiss="modal" id="confirm-delete">Delete</button> <p>Are you REALLY sure you want to delete <strong><span id="deleteCount"></span></strong> history item(s)?</p>
</div> <p>This is permanent and cannot be undone!</p>
</div> </div>
<div class="modal-footer">
<button type="button" class="btn btn-dark" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-danger btn-ok" data-dismiss="modal" id="confirm-delete">Delete</button>
</div> </div>
</div> </div>
</div> </div>
@@ -69,46 +102,53 @@
</%def> </%def>
<%def name="javascriptIncludes()"> <%def name="javascriptIncludes()">
<script src="interfaces/default/js/jquery.dataTables.min.js"></script> <script src="${http_root}js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.colVis.js"></script> <script src="${http_root}js/dataTables.colVis.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script> <script src="${http_root}js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script> <script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
<script src="interfaces/default/js/moment-with-locale.js"></script> <script src="${http_root}js/moment-with-locale.js"></script>
<script src="interfaces/default/js/tables/history_table.js"></script> <script src="${http_root}js/tables/history_table.js${cache_param}"></script>
<script> <script>
$(document).ready(function () { $(document).ready(function () {
function loadHistoryTable(media_type) { // Load user ids and names (for the selector)
$.ajax({
url: 'get_user_names',
type: 'GET',
dataType: 'json',
success: function (data) {
var select = $('#history-user');
data.sort(function (a, b) {
return a.friendly_name.localeCompare(b.friendly_name);
});
data.forEach(function (item) {
select.append('<option value="' + item.user_id + '">' +
item.friendly_name + '</option>');
});
}
});
function loadHistoryTable(media_type, selected_user_id) {
history_table_options.ajax = { history_table_options.ajax = {
url: 'get_history', url: 'get_history',
type: 'post', type: 'POST',
data: function (d) { data: function (d) {
return { return {
json_data: JSON.stringify(d), json_data: JSON.stringify(d),
media_type: media_type media_type: media_type,
user_id: selected_user_id
}; };
} }
} };
history_table = $('#history_table').DataTable(history_table_options); history_table = $('#history_table').DataTable(history_table_options);
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 11] }); var colvis = new $.fn.dataTable.ColVis(history_table, {
buttonText: '<i class="fa fa-columns"></i> Select columns',
buttonClass: 'btn btn-dark',
exclude: [0, 11]
});
$(colvis.button()).appendTo('div.colvis-button-bar'); $(colvis.button()).appendTo('div.colvis-button-bar');
clearSearchButton('history_table', history_table); clearSearchButton('history_table', history_table);
$('#history_table_filter').prepend('<div class="btn-group" data-toggle="buttons" id="media_type-selection" style="padding-right: 15px;"> \
<label class="btn btn-dark active"> \
<input type="radio" name="media_type-filter" id="history-all" value="all" autocomplete="off"> All \
</label> \
<label class="btn btn-dark"> \
<input type="radio" name="media_type-filter" id="history-movies" value="movie" autocomplete="off"> Movies \
</label> \
<label class="btn btn-dark"> \
<input type="radio" name="media_type-filter" id="history-tv_shows" value="episode" autocomplete="off"> TV Shows \
</label> \
<label class="btn btn-dark"> \
<input type="radio" name="media_type-filter" id="history-music" value="track" autocomplete="off"> Music \
</label> \
</div>');
$('#media_type-selection').on('change', function () { $('#media_type-selection').on('change', function () {
$('#media_type-selection > label').removeClass('active'); $('#media_type-selection > label').removeClass('active');
selected_filter = $('input[name=media_type-filter]:checked', '#media_type-selection'); selected_filter = $('input[name=media_type-filter]:checked', '#media_type-selection');
@@ -116,30 +156,38 @@
media_type = $(selected_filter).val(); media_type = $(selected_filter).val();
history_table.draw(); history_table.draw();
}); });
$('#history-user').on('change', function () {
selected_user_id = $(this).val() || null;
history_table.draw();
});
} }
var media_type = 'all'; var media_type = null;
loadHistoryTable(media_type); var selected_user_id = "${_session['user_group']}" == "admin" ? null : "${_session['user_id']}";
loadHistoryTable(media_type, selected_user_id);
% if _session['user_group'] == 'admin':
$('#row-edit-mode').on('click', function() { $('#row-edit-mode').on('click', function() {
$('#row-edit-mode-alert').fadeIn(200); $('#row-edit-mode-alert').fadeIn(200);
if ($(this).hasClass('active')) { if ($(this).hasClass('active')) {
if (history_to_delete.length > 0) { if (history_to_delete.length > 0) {
$('#deleteCount').text(history_to_delete.length); $('#deleteCount').text(history_to_delete.length);
$('#confirm-modal').modal(); $('#confirm-modal-delete').modal();
$('#confirm-modal').one('click', '#confirm-delete', function () { $('#confirm-modal-delete').one('click', '#confirm-delete', function () {
for (var i = 0; i < history_to_delete.length; i++) { history_to_delete.forEach(function(row, idx) {
$.ajax({ $.ajax({
url: 'delete_history_rows', url: 'delete_history_rows',
data: { row_id: history_to_delete[i] }, type: 'POST',
data: { row_id: row },
async: true, async: true,
success: function (data) { success: function (data) {
var msg = "History deleted"; var msg = "History deleted";
showMsg(msg, false, true, 2000); showMsg(msg, false, true, 2000);
} }
}); });
} });
history_table.draw(); history_table.draw();
}); });
} }
@@ -157,6 +205,11 @@
}); });
} }
}); });
% endif
});
$("#refresh-history-list").click(function() {
history_table.draw();
}); });
</script> </script>
</%def> </%def>

View File

@@ -5,19 +5,34 @@
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
<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">
<i class="fa fa-history"></i> History for <span id="date-header">${data}</span> % if data.get('media_type'):
<% h = {'episode': 'TV Show', 'track': 'Music'} %>
<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'):
<% h = {'copy': 'Direct Stream'} %>
<i class="fa fa-history"></i> ${h.get(data['transcode_decision'], data['transcode_decision'].title())} History for <span id="date-header">${data['start_date']}</span>
% else:
<i class="fa fa-history"></i> History for <span id="date-header">${data['start_date']}</span>
% endif
</span></strong> </span></strong>
</h4> </h4>
</div> </div>
<div class="modal-body" id="modal-text"> <div class="modal-body" id="modal-text">
<table class="display" id="history_table" width="100%"> <table class="display history_table" id="history_table_modal" width="100%">
<thead> <thead>
<tr> <tr>
<th align="left" id="started">Started</th> <th align="left" id="delete_row">Delete</th>
<th align="left" id="stopped">Stopped</th> <th align="left" id="date">Date</th>
<th align="left" id="friendly_name">User</th> <th align="left" id="friendly_name">User</th>
<th align="left" id="player">Player</th> <th align="left" id="ip_address">IP Address</th>
<th align="left" id="platform">Platform</th>
<th align="left" id="device">Player</th>
<th align="left" id="title">Title</th> <th align="left" id="title">Title</th>
<th align="left" id="started">Started</th>
<th align="left" id="paused_counter">Paused</th>
<th align="left" id="stopped">Stopped</th>
<th align="left" id="duration">Duration</th>
<th align="left" id="percent_complete"></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -27,52 +42,31 @@
<div class="modal-footer"></div> <div class="modal-footer"></div>
</div> </div>
</div> </div>
<div class="modal fade" id="info-modal" tabindex="-1" role="dialog" aria-labelledby="info-modal">
</div> <script src="${http_root}js/tables/history_table.js${cache_param}"></script>
<script src="interfaces/default/js/tables/history_table_modal.js"></script>
<script> <script>
$(document).ready(function() { $(document).ready(function() {
$('#date-header').html(moment('${data}','YYYY-MM-DD').format('ddd MMM Do YYYY')); $('#date-header').html(moment('${data["start_date"]}','YYYY-MM-DD').format('ddd MMM Do YYYY'));
history_table_modal_options.ajax = { history_table_options.ajax = {
url: 'get_history', url: 'get_history',
type: 'post',
data: function ( d ) { data: function ( d ) {
return { return {
json_data: JSON.stringify(d), json_data: JSON.stringify(d),
grouping: false, user_id: "${data['user_id']}",
start_date: '${data}' start_date: "${data['start_date']}",
media_type: "${data.get('media_type')}",
transcode_decision: "${data.get('transcode_decision')}"
}; };
} }
} };
history_table = $('#history_table').DataTable(history_table_modal_options); history_table = $('#history_table_modal').DataTable(history_table_options);
history_table.columns([0, 3, 4, 8, 10, 11]).visible(false);
clearSearchButton('history_table', history_table);
// Move #info-modal to parent container clearSearchButton('history_table_modal', history_table);
if (!($('#history-modal').next().is('#info-modal'))) {
$('#info-modal').appendTo($('#history-modal').parent());
}
$('#history-modal > #info-modal').remove();
$('#history-modal').css('z-index', '1050'); $('#history-modal').on('shown.bs.modal', function() {
$('.modal-backdrop').not('.modal-backdrop-stack').css('z-index', '1049'); history_table.columns.adjust().draw();
$('.modal-backdrop').not('.modal-backdrop-stack').addClass('modal-backdrop-stack');
$('#info-modal').on('show.bs.modal', function () {
// Fix position to match parent modal
var currentPadding = parseInt($('body').css('padding-right'));
$(this).children('.modal-dialog').css('left', -currentPadding / 2);
$('#history-modal').css('overflow-y', 'hidden');
setTimeout(function () {
$('#info-modal').css('z-index', '1060');
$('.modal-backdrop').not('.modal-backdrop-stack').css('z-index', '1059');
$('.modal-backdrop').not('.modal-backdrop-stack').addClass('modal-backdrop-stack');
}, 0);
});
$('#info-modal').on('hidden.bs.modal', function () {
$('body').addClass('modal-open');
$('#history-modal').css('overflow-y', 'auto');
}); });
}); });
</script> </script>

View File

@@ -57,816 +57,189 @@ DOCUMENTATION :: END
# Human readable duration # Human readable duration
def hd(seconds): def hd(seconds):
minutes = helpers.cast_to_float(seconds) / 60 m, s = divmod(helpers.cast_to_int(seconds), 60)
if minutes > 60: h, m = divmod(m, 60)
hours = int(minutes / 60) return str(h).zfill(1) + ':' + str(m).zfill(2)
minutes = int(minutes % 60)
if minutes > 0:
return "<h3>" + str(hours) + "</h3><p>hrs</p><h3>" + str(minutes) + "</h3><p>mins</p>"
else:
return "<h3>" + str(hours) + "</h3><p>hrs</p>"
else:
return "<h3>" + str(int(minutes)) + "</h3><p>mins</p>"
%> %>
% if data: % if data and any(top_stat['rows'] for top_stat in data):
<ul class="list-unstyled"> % for top_stat in data:
% if any(top_stat['rows'] for top_stat in data): % if top_stat['rows']:
% for top_stat in data: <%
% if top_stat['stat_id'] == 'top_tv' and top_stat['rows']: stat_id = top_stat['stat_id']
<div class="home-platforms-instance"> row0 = top_stat['rows'][0]
<li> %>
<div class="home-platforms-instance-info"> <div class="dashboard-stats-instance" id="stats-instance-${stat_id}" data-stat_id="${stat_id}">
<div class="home-platforms-instance-name"> <div class="dashboard-stats-container">
<h4>Most Watched TV</h4> % if stat_id in ('top_movies', 'popular_movies', 'top_tv', 'popular_tv', 'top_music', 'popular_music', 'last_watched'):
</div> % if row0['art']:
<div class="home-platforms-instance-playcount"> <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);">
<h4> % else:
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}"> <div id="stats-background-${stat_id}" class="dashboard-stats-background" style="background-image: url(images/art.png);">
${top_stat['rows'][0]['title']} % endif
</a> % elif stat_id == 'top_platforms':
</h4> <div id="stats-background-${stat_id}" class="dashboard-stats-background platform-${row0['platform_name']}-rgba no-image">
% if top_stat['stat_type'] == 'total_plays': % else:
<h3>${top_stat['rows'][0]['total_plays']}</h3> <div id="stats-background-${stat_id}" class="dashboard-stats-background flat">
<p> plays</p> % endif
% 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">
% 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>
% 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 '#' %>
<a id="stats-thumb-url-${stat_id}" href="${href}" title="${row0['title']}">
% if row0['thumb']:
<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: % else:
${top_stat['rows'][0]['total_duration'] | hd} <div id="stats-thumb-${stat_id}" class="dashboard-stats-${type}" style="background-image: url(images/${type}.png);"></div>
% endif
</a>
</div>
% elif stat_id == 'top_users':
<% user_href = 'user?user_id={}'.format(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">
<div id="stats-thumb-${stat_id}" class="dashboard-stats-circle" style="background-image: url(${row0['user_thumb'] or 'images/gravatar-default.png'})"></div>
</a>
% elif stat_id == 'top_platforms':
<div id="stats-thumb-${stat_id}" class="dashboard-stats-flat svg-icon platform-${row0['platform_name']} transparent hidden-xs"></div>
% elif stat_id == 'most_concurrent':
<div id="stats-thumb-${stat_id}" class="dashboard-stats-flat svg-icon stats-${stat_id} transparent hidden-xs"></div>
% endif
<div class="dashboard-stats-info-container">
<div id="stats-title-${stat_id}" class="dashboard-stats-info-title">
<h4>${top_stat['stat_title']}</h4>
% if stat_id.startswith('top') and top_stat.get('stat_type') == 'total_plays':
<span class="dashboard-stats-stats-units">plays</span>
% elif stat_id.startswith('top') and top_stat.get('stat_type') == 'total_duration':
<span class="dashboard-stats-stats-units">hh:mm</span>
% elif stat_id.startswith('popular'):
<span class="dashboard-stats-stats-units">users</span>
% elif stat_id == 'last_watched':
<span class="dashboard-stats-stats-units" id="last-watched-header-info">${row0['friendly_name']}</span>
% elif stat_id == 'most_concurrent':
<span class="dashboard-stats-stats-units" id="most-concurrent-header-info">streams</span>
% endif % endif
</div> </div>
</div> <div class="dashboard-stats-info-scroller scrollbar-macosx">
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}"> <div class="dashboard-stats-info scoller-content">
% if top_stat['rows'][0]['grandparent_thumb']: <ul class="list-unstyled dashboard-stats-info-list">
<div class="home-platforms-instance-poster"> % for row in top_stat['rows']:
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=450&fallback=poster);"></div> <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')}"
</div> data-art="${row.get('art')}" data-thumb="${row.get('thumb')}" data-platform="${row.get('platform_name')}"
% else: data-user_id="${row.get('user_id')}" data-friendly_name="${row.get('friendly_name')}" data-user_thumb="${row.get('user_thumb')}"
<div class="home-platforms-instance-poster"> data-last_watch="${row.get('last_watch')}" data-started="${row.get('started')}">
<div class="home-platforms-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div> <div class="sub-list">${loop.index + 1}</div>
</div> <div class="sub-value">
% endif % if stat_id in ('top_movies', 'popular_movies', 'top_tv', 'popular_tv', 'top_music', 'popular_music', 'last_watched'):
</a> <% href = 'info?rating_key={}'.format(row['rating_key']) if row['rating_key'] else '#' %>
% if len(top_stat['rows']) > 1: <a href="${href}" title="${row['title']}">
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div> ${row['title']}
<ul class="list-unstyled"> </a>
<div class="slider"> % elif stat_id == 'top_users':
<div class="home-platforms-instance-list"> <% user_href = 'user?user_id={}'.format(row['user_id']) if row['user_id'] else '#' %>
% for row in top_stat['rows']: <a href="${user_href}" title="${row['friendly_name']}">
% if loop.index > 0: ${row['friendly_name']}
<li> </a>
<div class="home-platforms-instance-list-info"> % elif stat_id == 'top_platforms':
<div class="home-platforms-instance-list-name"> ${row['platform']}
<h5> % elif stat_id == 'most_concurrent':
<a href="info?rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}"> ${row['title']}
${top_stat['rows'][loop.index]['title']}
</a>
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][loop.index]['total_plays']}</h3>
<p> plays</p>
% else:
${top_stat['rows'][loop.index]['total_duration'] | hd}
% endif % endif
</div> </div>
</div> <div class="sub-count">
<a href="info?rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}"> % if stat_id.startswith('top') and top_stat.get('stat_type') == 'total_plays':
% if top_stat['rows'][loop.index]['grandparent_thumb']: ${row['total_plays']}
<div class="home-platforms-instance-list-poster"> % elif stat_id.startswith('top') and top_stat.get('stat_type') == 'total_duration':
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=450&fallback=poster);"></div> ${row['total_duration'] | hd}
</div> % elif stat_id.startswith('popular'):
% else: ${row['users_watched']}
<div class="home-platforms-instance-poster2"> % elif stat_id == 'most_concurrent':
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div> ${row['count']}
</div>
% endif
</a>
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
</li>
% endif
% endfor
</div>
</div>
</ul>
% endif
</li>
</div>
% elif top_stat['stat_id'] == 'popular_tv' and top_stat['rows']:
<div class="home-platforms-instance">
<li>
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Most Popular TV</h4>
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
${top_stat['rows'][0]['title']}
</a>
</h4>
<h3>${top_stat['rows'][0]['users_watched']}</h3>
<p> users</p>
</div>
</div>
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['grandparent_thumb'] != '':
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=450&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
</a>
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
<a href="info?rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
${top_stat['rows'][loop.index]['title']}
</a>
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
<h3>${top_stat['rows'][loop.index]['users_watched']}</h3>
<p> users</p>
</div>
</div>
<a href="info?rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['grandparent_thumb']:
<div class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=450&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-poster2">
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
</a>
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
</li>
% endif
% endfor
</div>
</div>
</ul>
% endif
</li>
</div>
% elif top_stat['stat_id'] == 'top_movies' and top_stat['rows']:
<div class="home-platforms-instance">
<li>
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Most Watched Movie</h4>
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
${top_stat['rows'][0]['title']}
</a>
</h4>
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][0]['total_plays']}</h3>
<p> plays</p>
% else:
${top_stat['rows'][0]['total_duration'] | hd}
% endif
</div>
</div>
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['thumb']:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['thumb']}&width=300&height=450&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
</a>
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
<a href="info?rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
${top_stat['rows'][loop.index]['title']}
</a>
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][loop.index]['total_plays']}</h3>
<p> plays</p>
% else:
${top_stat['rows'][loop.index]['total_duration'] | hd}
% endif % endif
</div> </div>
</div> </li>
<a href="info?rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}"> % endfor
% if top_stat['rows'][loop.index]['thumb']: </ul>
<div class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['thumb']}&width=300&height=450&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-poster2">
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
</a>
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
</li>
% endif
% endfor
</div> </div>
</div> </div>
</ul> </div>
% endif </div>
</li>
</div> </div>
% elif top_stat['stat_id'] == 'popular_movies' and top_stat['rows']: </div>
<div class="home-platforms-instance"> % endif
<li> % endfor
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Most Popular Movie</h4>
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
${top_stat['rows'][0]['title']}
</a>
</h4>
<h3>${top_stat['rows'][0]['users_watched']}</h3>
<p> users</p>
</div>
</div>
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['thumb']:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['thumb']}&width=300&height=450&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
</a>
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
<a href="info?rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
${top_stat['rows'][loop.index]['title']}
</a>
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
<h3>${top_stat['rows'][loop.index]['users_watched']}</h3>
<p> users</p>
</div>
</div>
<a href="info?rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['thumb']:
<div class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['thumb']}&width=300&height=450&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-poster2">
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
</a>
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
</li>
% endif
% endfor
</div>
</div>
</ul>
% endif
</li>
</div>
% elif top_stat['stat_id'] == 'top_music' and top_stat['rows']:
<div class="home-platforms-instance">
<li>
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Most Listened to Artist</h4>
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
${top_stat['rows'][0]['title']}
</a>
</h4>
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][0]['total_plays']}</h3>
<p> plays</p>
% else:
${top_stat['rows'][0]['total_duration'] | hd}
% endif
</div>
</div>
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['grandparent_thumb']:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
</a>
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
<a href="info?rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
${top_stat['rows'][loop.index]['title']}
</a>
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][loop.index]['total_plays']}</h3>
<p> plays</p>
% else:
${top_stat['rows'][loop.index]['total_duration'] | hd}
% endif
</div>
</div>
<a href="info?rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['grandparent_thumb']:
<div class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-poster2">
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
</a>
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
</li>
% endif
% endfor
</div>
</div>
</ul>
% endif
</li>
</div>
% elif top_stat['stat_id'] == 'popular_music' and top_stat['rows']:
<div class="home-platforms-instance">
<li>
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Most Popular Artist</h4>
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
${top_stat['rows'][0]['title']}
</a>
</h4>
<h3>${top_stat['rows'][0]['users_watched']}</h3>
<p> users</p>
</div>
</div>
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['grandparent_thumb'] != '':
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
</a>
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
<a href="info?rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
${top_stat['rows'][loop.index]['title']}
</a>
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
<h3>${top_stat['rows'][loop.index]['users_watched']}</h3>
<p> users</p>
</div>
</div>
<a href="info?rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['grandparent_thumb']:
<div class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-poster2">
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
</a>
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
</li>
% endif
% endfor
</div>
</div>
</ul>
% endif
</li>
</div>
% elif top_stat['stat_id'] == 'top_users' and top_stat['rows']:
<div class="home-platforms-instance">
<li>
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Most Active User</h4>
</div>
<div class="home-platforms-instance-playcount">
<h4>
% if top_stat['rows'][0]['user_id']:
<a href="user?user_id=${top_stat['rows'][0]['user_id']}" title="${top_stat['rows'][0]['friendly_name']}">
% else:
<a href="user?user=${top_stat['rows'][0]['user']}" title="${top_stat['rows'][0]['friendly_name']}">
% endif
${top_stat['rows'][0]['friendly_name']}
</a>
</h4>
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][0]['total_plays']}</h3>
<p> plays</p>
% else:
${top_stat['rows'][0]['total_duration'] | hd}
% endif
</div>
</div>
% if top_stat['rows'][0]['user_id']:
<a href="user?user_id=${top_stat['rows'][0]['user_id']}" title="${top_stat['rows'][0]['friendly_name']}">
% else:
<a href="user?user=${top_stat['rows'][0]['user']}" title="${top_stat['rows'][0]['friendly_name']}">
% endif
% if top_stat['rows'][0]['user_thumb'] != '':
<div class="home-platforms-instance-poster">
<div class="home-platforms-instance-oval" style="background-image: url(${top_stat['rows'][0]['user_thumb']});"></div>
</div>
% else:
<div class="home-platforms-instance-poster">
<div class="home-platforms-instance-oval" style="background-image: url(interfaces/default/images/gravatar-default.png);"></div>
</div>
% endif
</a>
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
% if top_stat['rows'][loop.index]['user_id']:
<a href="user?user_id=${top_stat['rows'][loop.index]['user_id']}" title="${top_stat['rows'][loop.index]['friendly_name']}">
% else:
<a href="user?user=${top_stat['rows'][loop.index]['user']}" title="${top_stat['rows'][loop.index]['friendly_name']}">
% endif
${top_stat['rows'][loop.index]['friendly_name']}
</a>
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][loop.index]['total_plays']}</h3>
<p> plays</p>
% else:
${top_stat['rows'][loop.index]['total_duration'] | hd}
% endif
</div>
</div>
% if top_stat['rows'][loop.index]['user_id']:
<a href="user?user_id=${top_stat['rows'][loop.index]['user_id']}" title="${top_stat['rows'][loop.index]['friendly_name']}">
% else:
<a href="user?user=${top_stat['rows'][loop.index]['user']}" title="${top_stat['rows'][loop.index]['friendly_name']}">
% endif
% if top_stat['rows'][loop.index]['user_thumb'] != '':
<div class="home-platforms-instance-poster">
<div class="home-platforms-instance-list-oval" style="background-image: url(${top_stat['rows'][loop.index]['user_thumb']});"></div>
</div>
% else:
<div class="home-platforms-instance-poster">
<div class="home-platforms-instance-list-oval" style="background-image: url(interfaces/default/images/gravatar-default.png);"></div>
</div>
% endif
</a>
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
</li>
% endif
% endfor
</div>
</div>
</ul>
% endif
</li>
</div>
% elif top_stat['stat_id'] == 'top_platforms' and top_stat['rows']:
<div class="home-platforms-instance">
<li>
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Most Active Platform</h4>
</div>
<div class="home-platforms-instance-playcount">
<h4 title="${top_stat['rows'][0]['platform_type']}">${top_stat['rows'][0]['platform_type']}</h4>
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][0]['total_plays']}</h3>
<p> plays</p>
% else:
${top_stat['rows'][0]['total_duration'] | hd}
% endif
</div>
</div>
<div id="platform-stat" class="home-platforms-instance-poster" title="${top_stat['rows'][0]['platform_type']}">
<script>
$("#platform-stat").html("<div class='home-platforms-instance-box' style='background-image: url(" + getPlatformImagePath('${top_stat['rows'][0]['platform_type']}') + ");'>");
</script>
</div>
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5 title="${top_stat['rows'][loop.index]['platform_type']}">
${top_stat['rows'][loop.index]['platform_type']}
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][loop.index]['total_plays']}</h3>
<p> plays</p>
% else:
${top_stat['rows'][loop.index]['total_duration'] | hd}
% endif
</div>
</div>
<div class="home-platforms-instance-poster" id="home-platforms-instance-poster-${loop.index + 1}" title="${top_stat['rows'][loop.index]['platform_type']}">
<script>
$("#home-platforms-instance-poster-${loop.index + 1}").html("<div class='home-platforms-instance-list-box' style='background-image: url(" + getPlatformImagePath('${top_stat['rows'][loop.index]['platform_type']}') + ");'>");
</script>
</div>
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
</li>
% endif
% endfor
</div>
</div>
</ul>
% endif
</li>
</div>
% elif top_stat['stat_id'] == 'last_watched' and top_stat['rows']:
<div class="home-platforms-instance">
<li>
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Last Watched</h4>
</div>
<div class="home-platforms-instance-last-user">
<h4>
<a href="info?source=history&rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
${top_stat['rows'][0]['title']}
</a>
</h4>
<h5>
% if top_stat['rows'][0]['user_id']:
<a href="user?user_id=${top_stat['rows'][0]['user_id']}" title="${top_stat['rows'][0]['friendly_name']}">
% else:
<a href="user?user=${top_stat['rows'][0]['user']}" title="${top_stat['rows'][0]['friendly_name']}">
% endif
${top_stat['rows'][0]['friendly_name']}
</a>
</h5>
<p>
<span id="last-watch-stat">
<script>
$('#last-watch-stat').text(moment(${top_stat['rows'][0]['last_watch']},"X").format(date_format));
</script>
</span> - ${top_stat['rows'][0]['player']}
</p>
</div>
</div>
<a href="info?source=history&rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['thumb']:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['thumb']}&width=300&height=450&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
</a>
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
<a href="info?source=history&rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
${top_stat['rows'][loop.index]['title']}
</a>
</h5>
</div>
<div class="home-platforms-instance-list-last-user">
<h5>
% if top_stat['rows'][loop.index]['user_id']:
<a href="user?user_id=${top_stat['rows'][loop.index]['user_id']}" title="${top_stat['rows'][loop.index]['friendly_name']}">
% else:
<a href="user?user=${top_stat['rows'][loop.index]['user']}" title="${top_stat['rows'][loop.index]['friendly_name']}">
% endif
${top_stat['rows'][loop.index]['friendly_name']}
</a>
</h5>
<p>
<span id="home-platforms-instance-list-last-watch-${loop.index + 1}">
<script>
$('#home-platforms-instance-list-last-watch-${loop.index + 1}').text(moment(${top_stat['rows'][loop.index]['last_watch']},"X").format(date_format));
</script>
</span> - ${top_stat['rows'][loop.index]['player']}
</p>
</div>
</div>
<a href="info?source=history&rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['thumb']:
<div class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['thumb']}&width=300&height=450&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
</a>
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
</li>
% endif
% endfor
</div>
</div>
</ul>
% endif
</li>
</div>
% elif top_stat['stat_id'] == 'most_concurrent' and top_stat['rows']:
<div class="home-platforms-instance">
<li>
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Most Concurrent Streams</h4>
</div>
<div class="home-platforms-instance-playcount">
<h4>
<span id="most-concurrent-start">
<script>
$('#most-concurrent-start').text(moment(${top_stat['rows'][0]['started']},"X").format(date_format + ' ' + time_format));
</script>
</span>
</h4>
<h3>${top_stat['rows'][0]['count']}</h3>
<p> streams</p>
</div>
</div>
<div class="home-platforms-instance-poster">
<div class="home-platforms-instance-box" style="background-image: url(interfaces/default/images/home-stat_most-concurrent.png);"></div>
</div>
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
${top_stat['rows'][loop.index]['title']}
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
<h3>${top_stat['rows'][loop.index]['count']}</h3>
<p> streams
% if top_stat['rows'][loop.index]['started']:
- <span id="most-concurrent-start-${loop.index + 1}">
<script>
$('#most-concurrent-start-${loop.index + 1}').text(moment(${top_stat['rows'][loop.index]['started']},"X").format(date_format + ' ' + time_format));
</script>
</span>
% else:
- N/A
% endif
</p>
</div>
</div>
<div class="home-platforms-instance-poster">
<div class="home-platforms-instance-list-box" style="background-image: url(interfaces/default/images/home-stat_most-concurrent.png);"></div>
</div>
</li>
% endif
% endfor
</div>
</div>
</ul>
% endif
</li>
</div>
% endif
% endfor
% else:
<div class="text-muted">No stats to show for the selected period.</div><br>
% endif
</ul>
<script> <script>
var topZIndex = 2; $('.dashboard-stats-instance .dashboard-stats-info-scroller').scrollbar()
$('.home-platforms-instance-list-chevron').on('click', function() {
var instanceBoxChevron = $(this); function changeImages(elem) {
var instanceBox = $(this).parents('.home-platforms-instance'); var stat_id = $(elem).data('stat_id');
var instanceBoxSlider = instanceBox.find('.slider'); var art = $(elem).data('art');
var thumb = $(elem).data('thumb');
topZIndex++; var user_id = $(elem).data('user_id');
instanceBoxChevron.toggleClass('active'); var user_thumb = $(elem).data('user_thumb');
instanceBoxSlider.css('z-index', topZIndex); var rating_key = $(elem).data('rating_key');
instanceBoxSlider.stop().slideToggle(500); var [height, fallback] = ($.inArray(stat_id, ['top_music', 'popular_music']) > -1) ? [300, 'cover'] : [450, 'poster'];
var href;
if (stat_id == 'most_concurrent') {
return
} else if (stat_id == 'top_users') {
$('#stats-thumb-' + stat_id).css('background-image', 'url(' + (user_thumb || 'images/gravatar-default.png') + ')');
if (user_id) {
href = 'user?user_id=' + user_id;
} else {
href = '#';
}
$('#stats-thumb-url-' + stat_id).attr('href', href).prop('title', $(elem).data('friendly_name'));
} else if (stat_id == 'top_platforms') {
$('#stats-thumb-' + stat_id).removeClass(function (index, className) {
return (className.match (/(^|\s)platform-\S+/g) || []).join(' ');
}).addClass('platform-' + $(elem).data('platform'));
$('#stats-background-' + stat_id).removeClass(function (index, className) {
return (className.match (/(^|\s)platform-\S+/g) || []).join(' ');
}).addClass('platform-' + $(elem).data('platform') + '-rgba');
} else {
if (rating_key) {
href = 'info?rating_key=' + rating_key;
} else {
href = '#';
}
$('#stats-thumb-url-' + stat_id).attr('href', href).prop('title', $(elem).data('title'));
if (art) {
$('#stats-background-' + stat_id).css('background-image', 'url(pms_image_proxy?img=' + art + '&width=500&height=280&opacity=40&background=282828&blur=3&fallback=art)');
} else {
$('#stats-background-' + stat_id).css('background-image', 'url(images/art.png)');
}
if (thumb) {
$('#stats-thumb-' + stat_id).css('background-image', 'url(pms_image_proxy?img=' + thumb + '&width=300&height=' + height + '&fallback=' + fallback + ')');
$('#stats-thumb-' + stat_id + '-bg').css('background-image', 'url(pms_image_proxy?img=' + thumb + '&width=300&height=' + height + '&opacity=60&background=282828&blur=3&fallback=' + fallback + ')');
} else {
$('#stats-thumb-' + stat_id).css('background-image', 'url(images/' + fallback + '.png)');
$('#stats-thumb-' + stat_id + '-bg').css('background-image', 'url(images/' + fallback + '.png)');
}
}
}
$('.dashboard-stats-info-item').mouseenter(function () {
changeImages(this)
if ($(this).data('stat_id') == 'last_watched') {
var friendly_name = $(this).data('friendly_name');
var last_watch = moment($(this).data('last_watch'), 'X').format(date_format);
$('#last-watched-header-info').html(friendly_name);
} else if ($(this).data('stat_id') == 'most_concurrent') {
var started = moment($(this).data('started'), 'X').format(date_format + ' ' + time_format);
$('#most-concurrent-header-info').html(started);
}
});
$('.dashboard-stats-instance').mouseleave(function () {
changeImages($(this).find('.dashboard-stats-info-item').first())
if ($(this).data('stat_id') == 'last_watched') {
$('#last-watched-header-info').text($(this).find('.dashboard-stats-info-item').first().data('friendly_name'));
} else if ($(this).data('stat_id') == 'most_concurrent') {
$('#most-concurrent-header-info').text('streams');
}
}); });
</script> </script>
% else: % else:

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="${http_root}images/favicon/mstile-150x150.png?v=2.0.5"/>
<TileColor>#282a2d</TileColor>
</tile>
</msapplication>
</browserconfig>

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 971 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,18 @@
{
"name": "Tautulli",
"icons": [
{
"src": "${http_root}images/favicon/android-chrome-192x192.png?v=2.0.5",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "${http_root}images/favicon/android-chrome-256x256.png?v=2.0.5",
"sizes": "256x256",
"type": "image/png"
}
],
"theme_color": "#282a2d",
"background_color": "#282a2d",
"display": "standalone"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -0,0 +1 @@
<svg version="1" xmlns="http://www.w3.org/2000/svg" width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000" preserveAspectRatio="xMidYMid meet"><g transform="translate(0.000000,700.000000) scale(0.100000,-0.100000)" fill="#000000" stroke="none"><path d="M5695 6555 c-135 -34 -244 -94 -342 -189 -40 -39 -73 -76 -73 -83 0 -7 -4 -13 -10 -13 -14 0 -87 -156 -106 -225 -22 -83 -26 -234 -8 -320 17 -79 86 -230 133 -288 l30 -39 -48 -71 c-39 -57 -159 -228 -251 -357 -69 -97 -398 -564 -416 -590 -13 -19 -60 -87 -105 -150 -45 -63 -107 -151 -138 -195 -30 -44 -59 -84 -63 -90 -7 -9 -251 -354 -346 -490 -92 -131 -173 -245 -175 -245 -1 0 -34 9 -72 21 -130 38 -325 31 -454 -18 -168 -63 -313 -196 -385 -354 -39 -87 -65 -183 -68 -256 0 -24 -3 -43 -4 -43 -2 0 -43 46 -91 102 -49 57 -100 117 -115 133 -14 17 -128 149 -253 295 -125 146 -251 292 -279 324 -56 65 -77 89 -108 126 -58 68 -152 178 -172 200 -12 14 -50 57 -83 96 l-61 71 27 44 c58 93 91 217 92 342 2 161 -38 294 -125 412 -133 181 -316 279 -542 292 -470 27 -833 -434 -699 -887 74 -251 275 -437 530 -490 132 -28 334 -6 421 45 l42 24 173 -197 c96 -108 186 -210 200 -227 15 -16 163 -187 330 -380 458 -529 491 -567 526 -605 18 -19 31 -35 30 -36 -6 -5 -265 -161 -277 -167 -8 -4 -34 -20 -58 -35 -194 -124 -634 -382 -651 -382 -12 0 -46 20 -75 44 -60 49 -180 112 -242 127 -21 5 -48 12 -59 15 -11 4 -65 9 -121 11 -81 4 -117 1 -182 -15 -261 -66 -462 -270 -528 -537 -10 -40 -11 -217 -2 -258 5 -23 11 -51 14 -61 29 -145 147 -312 284 -403 123 -82 224 -114 370 -118 83 -3 124 2 240 29 36 9 133 57 187 94 60 41 111 91 153 152 14 19 28 37 32 40 19 15 71 140 89 217 17 73 20 107 16 198 -4 61 -7 121 -9 134 -3 28 -46 0 482 321 179 108 379 228 444 265 104 59 120 65 133 52 13 -13 12 -22 -10 -78 -49 -123 -58 -165 -62 -262 -7 -149 25 -286 89 -383 47 -72 91 -128 125 -158 19 -17 39 -36 45 -42 27 -25 136 -94 150 -94 8 0 17 -4 20 -9 3 -5 16 -11 28 -14 13 -3 50 -12 83 -21 74 -19 278 -15 345 7 198 65 358 196 435 358 16 34 20 36 49 28 17 -4 49 -10 71 -14 22 -3 99 -16 170 -30 72 -13 144 -26 160 -29 28 -5 101 -18 170 -31 17 -3 80 -14 140 -25 61 -11 124 -22 140 -25 17 -4 49 -9 72 -12 40 -5 42 -7 48 -47 14 -98 29 -147 73 -235 36 -75 61 -110 121 -171 154 -154 280 -210 480 -213 134 -2 180 5 273 40 212 83 371 262 427 481 24 93 25 255 2 342 -64 241 -245 428 -481 501 -62 18 -97 23 -200 22 -107 0 -136 -4 -205 -26 -44 -15 -109 -43 -145 -64 -83 -48 -208 -171 -250 -245 -17 -32 -35 -60 -38 -61 -4 -2 -46 4 -93 13 -48 10 -104 20 -125 23 -22 3 -46 8 -54 11 -8 3 -33 7 -55 10 -38 5 -58 9 -122 21 -16 3 -53 10 -83 15 -30 6 -66 12 -79 15 -13 2 -103 19 -200 36 -169 30 -207 42 -196 60 10 16 -28 155 -62 224 -19 39 -54 96 -78 127 l-45 58 40 52 c96 125 143 266 143 433 1 164 -27 263 -108 391 -19 30 -35 57 -35 61 0 3 31 49 69 102 57 81 450 638 625 889 28 40 62 88 76 107 14 18 194 274 400 568 291 414 379 534 393 531 10 -2 27 -6 37 -9 78 -25 240 -29 338 -9 433 87 677 573 489 974 -93 200 -255 332 -478 389 -87 22 -227 25 -304 6z"/></g></svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="483.904px" height="409.539px" viewBox="66.712 194.513 483.904 409.539"
enable-background="new 66.712 194.513 483.904 409.539" xml:space="preserve">
<g>
<g>
<path fill="none" d="M41.209,627.586c0-151.979,0-303.963,0-456.118c177.822,0,355.688,0,533.881,0c0,151.922,0,304.021,0,456.118
C397.214,627.586,219.233,627.586,41.209,627.586z M461.314,421.571c-110.652,0-220.389,0-329.873,0c0,18.87,0,36.226,0,54.729
c110.29,0,219.734,0,329.824,0c0,6.858-0.271,12.563,0.058,18.231c0.659,11.344,8.853,15.958,18.112,9.46
c22.087-15.499,43.824-31.503,65.474-47.611c7.678-5.715,7.621-10.63-0.234-16.467c-21.352-15.862-42.87-31.508-64.563-46.902
c-9.542-6.773-17.488-2.864-18.691,8.976C460.813,407.959,461.314,414.046,461.314,421.571z M130.996,574.741
c74.536,0,148.057,0,222.423,0c0,6.464-0.617,11.836,0.192,16.98c0.662,4.21,2.17,10.746,4.826,11.622
c4.329,1.427,10.994,0.66,14.77-1.943c21.297-14.688,42.098-30.1,62.911-45.474c8.887-6.564,8.992-11.503,0.233-18.001
c-20.777-15.419-41.647-30.727-62.83-45.579c-3.569-2.503-10.381-4.832-13.03-3.118c-3.676,2.376-5.784,8.447-6.81,13.308
c-1.126,5.336-0.257,11.091-0.257,17.757c-75.009,0-148.525,0-222.43,0C130.996,538.558,130.996,555.663,130.996,574.741z
M130.83,281.392c49.453,0,97.705,0,146.88,0c0,6.838-0.232,12.506,0.049,18.148c0.585,11.758,9.078,16.246,18.887,9.342
c21.767-15.316,43.232-31.064,64.624-46.902c8.01-5.932,7.995-11.301-0.134-17.342c-21.053-15.65-42.257-31.103-63.625-46.318
c-10.735-7.647-18.836-3.478-19.734,9.846c-0.378,5.611-0.063,11.27-0.063,18.431c-49.546,0-98.1,0-146.885,0
C130.83,245.229,130.83,262.325,130.83,281.392z M188.205,379.701c0,6.939-0.606,12.297,0.19,17.438
c0.649,4.198,2.088,10.688,4.753,11.61c4.316,1.496,11.054,0.904,14.8-1.673c21.612-14.857,42.736-30.435,63.834-46.026
c8.481-6.265,8.471-11.812-0.159-18.227c-21.054-15.647-42.241-31.123-63.625-46.315c-10.656-7.571-18.899-3.211-19.724,10.07
c-0.365,5.875-0.062,11.793-0.062,18.885c-20.45,0-38.938,0-57.202,0c0,18.619,0,35.973,0,54.238
C149.953,379.701,168.131,379.701,188.205,379.701z M66.712,280.18c17.568,0,33.699,0,49.59,0c0-18.261,0-35.579,0-53.046
c-16.925,0-33.07,0-49.59,0C66.712,245.159,66.712,262.481,66.712,280.18z M66.869,325.488c0,18.556,0,35.876,0,53.543
c16.862,0,33,0,49.278,0c0-18.274,0-35.852,0-53.543C99.359,325.488,83.5,325.488,66.869,325.488z M116.673,422.747
c-17.484,0-33.644,0-49.668,0c0,17.835,0,34.781,0,51.779c17.017,0,33.178,0,49.668,0
C116.673,456.924,116.673,440.208,116.673,422.747z M116.497,520.842c-17.01,0-33.43,0-49.552,0c0,18.244,0,35.566,0,53.021
c16.944,0,33.084,0,49.552,0C116.497,555.793,116.497,538.471,116.497,520.842z"/>
<path fill="#FFFFFF" d="M461.314,421.571c0-7.525-0.503-13.612,0.105-19.586c1.203-11.839,9.149-15.749,18.691-8.976
c21.691,15.396,43.211,31.04,64.563,46.902c7.855,5.837,7.912,10.752,0.234,16.467c-21.648,16.108-43.387,32.112-65.474,47.611
c-9.261,6.498-17.453,1.884-18.112-9.46c-0.329-5.67-0.058-11.373-0.058-18.231c-110.09,0-219.534,0-329.824,0
c0-18.503,0-35.857,0-54.729C240.927,421.571,350.662,421.571,461.314,421.571z"/>
<path fill="#FFFFFF" d="M130.996,574.741c0-19.078,0-36.185,0-54.448c73.904,0,147.42,0,222.43,0
c0-6.666-0.869-12.421,0.257-17.757c1.024-4.859,3.134-10.932,6.81-13.308c2.649-1.714,9.461,0.615,13.029,3.118
c21.184,14.854,42.054,30.16,62.831,45.579c8.759,6.498,8.652,11.437-0.233,18.001c-20.813,15.374-41.614,30.786-62.911,45.474
c-3.774,2.604-10.439,3.369-14.77,1.943c-2.656-0.876-4.165-7.412-4.826-11.622c-0.811-5.146-0.192-10.518-0.192-16.98
C279.053,574.741,205.532,574.741,130.996,574.741z"/>
<path fill="#FFFFFF" d="M130.83,281.392c0-19.067,0-36.163,0-54.795c48.785,0,97.339,0,146.885,0
c0-7.161-0.315-12.82,0.063-18.431c0.898-13.323,8.999-17.493,19.734-9.846c21.368,15.215,42.572,30.668,63.625,46.318
c8.129,6.041,8.144,11.411,0.133,17.342c-21.391,15.838-42.855,31.586-64.623,46.902c-9.81,6.904-18.302,2.417-18.887-9.342
c-0.281-5.643-0.049-11.31-0.049-18.148C228.535,281.392,180.283,281.392,130.83,281.392z"/>
<path fill="#FFFFFF" d="M188.205,379.701c-20.074,0-38.252,0-57.192,0c0-18.265,0-35.619,0-54.238c18.264,0,36.752,0,57.202,0
c0-7.092-0.303-13.01,0.062-18.885c0.825-13.281,9.067-17.641,19.724-10.07c21.383,15.193,42.57,30.668,63.625,46.315
c8.63,6.416,8.64,11.962,0.159,18.227c-21.099,15.591-42.222,31.169-63.834,46.026c-3.746,2.577-10.484,3.169-14.8,1.673
c-2.666-0.923-4.104-7.412-4.753-11.61C187.599,391.999,188.205,386.64,188.205,379.701z"/>
<path fill="#FFFFFF" d="M66.712,280.18c0-17.699,0-35.021,0-53.046c16.52,0,32.665,0,49.59,0c0,17.468,0,34.786,0,53.046
C100.411,280.18,84.281,280.18,66.712,280.18z"/>
<path fill="#FFFFFF" d="M66.869,325.488c16.63,0,32.49,0,49.278,0c0,17.692,0,35.27,0,53.543c-16.278,0-32.416,0-49.278,0
C66.869,361.364,66.869,344.044,66.869,325.488z"/>
<path fill="#E5A00D" d="M116.673,422.747c0,17.461,0,34.177,0,51.779c-16.49,0-32.652,0-49.668,0c0-16.998,0-33.944,0-51.779
C83.029,422.747,99.188,422.747,116.673,422.747z"/>
<path fill="#FFFFFF" d="M116.497,520.842c0,17.629,0,34.951,0,53.021c-16.468,0-32.608,0-49.552,0c0-17.455,0-34.777,0-53.021
C83.067,520.842,99.487,520.842,116.497,520.842z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -0,0 +1,5 @@
<!-- 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>artist</title>
<path fill="#fff" d="M9.201 24.681c0-6.699 0-13.358 0-20.035 7.594-1.505 15.157-3.004 22.768-4.513 0 0.172 0 0.319 0 0.465 0 7.067-0.026 14.135 0.021 21.202 0.010 1.498-0.59 2.57-1.716 3.423-1.999 1.512-4.26 2.145-6.751 1.88-0.504-0.054-1.020-0.205-1.481-0.418-1.502-0.695-1.856-2.122-0.908-3.48 0.826-1.184 1.99-1.924 3.302-2.433 1.362-0.528 2.774-0.843 4.252-0.719 0.324 0.027 0.646 0.084 0.994 0.13 0-4.345 0-8.679 0-13.050-6.062 1.204-12.099 2.404-18.16 3.608 0 0.196 0 0.345 0 0.495 0 5.174-0.006 10.349 0.004 15.523 0.003 1.409-0.802 2.302-1.854 3.056-0.889 0.637-1.859 1.114-2.906 1.426-1.524 0.453-3.067 0.627-4.619 0.169-0.952-0.281-1.789-0.736-2.010-1.83-0.136-0.673 0.098-1.269 0.459-1.822 0.772-1.183 1.947-1.853 3.193-2.388 1.662-0.714 3.394-1.043 5.207-0.698 0.048 0.009 0.099 0.005 0.206 0.010z"></path>
</svg>

After

Width:  |  Height:  |  Size: 979 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,5 @@
<!-- 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>movie</title>
<path fill="#fff" d="M0 1.416c10.695 0 21.315 0 32 0 0 9.719 0 19.417 0 29.168-10.635 0-21.293 0-32 0 0-9.699 0-19.399 0-29.168zM9.202 15.129c4.535 0 9.065 0 13.609 0 0-3.798 0-7.579 0-11.355-4.563 0-9.075 0-13.609 0 0 3.801 0 7.551 0 11.355zM9.215 28.909c4.581 0 9.093 0 13.61 0 0-3.818 0-7.585 0-11.382-4.549 0-9.062 0-13.61 0 0 3.803 0 7.57 0 11.382zM6.813 5.983c0-0.753 0-1.467 0-2.209-1.138 0-2.235 0-3.33 0 0 0.766 0 1.48 0 2.209 1.131 0 2.21 0 3.33 0zM25.231 3.754c0 0.783 0 1.494 0 2.219 1.141 0 2.235 0 3.33 0 0-0.763 0-1.476 0-2.219-1.12 0-2.198 0-3.33 0zM25.233 12.938c0 0.777 0 1.492 0 2.19 1.149 0 2.248 0 3.335 0 0-0.754 0-1.452 0-2.19-1.116 0-2.197 0-3.335 0zM25.227 22.074c0 0.783 0 1.496 0 2.218 1.139 0 2.235 0 3.335 0 0-0.758 0-1.471 0-2.218-1.119 0-2.196 0-3.335 0zM3.472 26.689c0 0.768 0 1.481 0 2.221 1.133 0 2.226 0 3.34 0 0-0.763 0-1.475 0-2.221-1.119 0-2.197 0-3.34 0zM28.579 26.711c-1.112 0-2.225 0-3.353 0 0 0.749 0 1.462 0 2.202 1.137 0 2.233 0 3.353 0 0-0.748 0-1.447 0-2.202zM6.817 15.155c0-0.774 0-1.468 0-2.21-1.133 0-2.229 0-3.338 0 0 0.761 0 1.473 0 2.21 1.127 0 2.207 0 3.338 0zM3.463 19.73c1.165 0 2.242 0 3.346 0 0-0.759 0-1.469 0-2.189-1.143 0-2.239 0-3.346 0 0 0.748 0 1.446 0 2.189zM28.559 19.733c0-0.764 0-1.479 0-2.188-1.144 0-2.241 0-3.34 0 0 0.752 0 1.448 0 2.188 1.114 0 2.195 0 3.34 0zM6.791 24.304c0-0.798 0-1.511 0-2.215-1.145 0-2.225 0-3.312 0 0 0.766 0 1.481 0 2.215 1.129 0 2.211 0 3.312 0zM3.489 8.378c0 0.771 0 1.464 0 2.145 1.138 0 2.219 0 3.319 0 0-0.74 0-1.431 0-2.145-1.129 0-2.211 0-3.319 0zM28.554 10.538c0-0.775 0-1.464 0-2.137-1.146 0-2.242 0-3.319 0 0 0.747 0 1.438 0 2.137 1.131 0 2.21 0 3.319 0z"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -0,0 +1,6 @@
<!-- 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>photo</title>
<path fill="#fff" d="M25.208 2.266c0 1.514 0 2.976 0 4.513 2.281 0 4.505 0 6.792 0 0 7.681 0 15.287 0 22.955-10.643 0-21.3 0-32 0 0-7.626 0-15.236 0-22.913 2.258 0 4.486 0 6.792 0 0-1.546 0-3.029 0-4.555 6.152 0 12.226 0 18.415 0zM16.008 9.209c-5.026-0.004-9.12 4.079-9.123 9.099-0.004 4.961 4.099 9.069 9.074 9.085 5.022 0.016 9.124-4.047 9.159-9.070 0.035-4.985-4.087-9.109-9.109-9.114z"></path>
<path fill="#fff" d="M20.601 18.292c0.003 2.551-2.070 4.626-4.61 4.613-2.558-0.013-4.595-2.069-4.591-4.634 0.003-2.524 2.038-4.557 4.577-4.572 2.562-0.015 4.621 2.030 4.624 4.593z"></path>
</svg>

After

Width:  |  Height:  |  Size: 746 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,12 @@
<!-- 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>playlist</title>
<path fill="#fff" d="M9.167 10.268c7.653 0 15.208 0 22.82 0 0 1.147 0 2.268 0 3.451-7.583 0-15.172 0-22.82 0 0-1.134 0-2.274 0-3.451z"></path>
<path fill="#fff" d="M9.14 21.73c0-1.152 0-2.257 0-3.424 7.609 0 15.212 0 22.86 0 0 1.132 0 2.252 0 3.424-7.607 0-15.191 0-22.86 0z"></path>
<path fill="#fff" d="M9.217 5.679c0-1.145 0-2.23 0-3.363 7.562 0 15.101 0 22.683 0 0 1.113 0 2.213 0 3.363-7.539 0-15.080 0-22.683 0z"></path>
<path fill="#fff" d="M9.225 29.708c0-1.132 0-2.214 0-3.336 7.558 0 15.086 0 22.668 0 0 1.086 0 2.186 0 3.336-7.526 0-15.071 0-22.668 0z"></path>
<path fill="#fff" d="M0.007 10.279c1.58 0 3.043 0 4.551 0 0 1.153 0 2.272 0 3.444-1.511 0-3.011 0-4.551 0 0-1.157 0-2.292 0-3.444z"></path>
<path fill="#fff" d="M4.527 2.292c0 1.183 0 2.284 0 3.424-1.496 0-2.957 0-4.479 0 0-1.142 0-2.276 0-3.424 1.51 0 2.971 0 4.479 0z"></path>
<path fill="#fff" d="M4.571 18.3c0 1.151 0 2.254 0 3.416-1.515 0-3.019 0-4.571 0 0-1.127 0-2.247 0-3.416 1.513 0 3.001 0 4.571 0z"></path>
<path fill="#fff" d="M4.54 26.352c0 1.137 0 2.218 0 3.354-1.494 0-2.975 0-4.506 0 0-1.094 0-2.192 0-3.354 1.489 0 2.965 0 4.506 0z"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,6 @@
<!-- 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>show</title>
<path fill="#fff" d="M0 26.565c0-8.38 0-16.706 0-25.089 10.661 0 21.307 0 32 0 0 8.343 0 16.686 0 25.089-10.637 0-21.283 0-32 0zM3.514 4.937c0 5.355 0 10.634 0 15.901 8.375 0 16.691 0 24.994 0 0-5.331 0-10.612 0-15.901-8.356 0-16.656 0-24.994 0z"></path>
<path fill="#fff" d="M6.874 30.524c0-0.553 0-1.056 0-1.602 6.084 0 12.136 0 18.25 0 0 0.509 0 1.029 0 1.602-6.050 0-12.12 0-18.25 0z"></path>
</svg>

After

Width:  |  Height:  |  Size: 555 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1,5 @@
<!-- 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>video</title>
<path fill="#fff" d="M20.662 27.439c-6.971 0-13.797 0-20.662 0 0-7.639 0-15.235 0-22.878 6.846 0 13.672 0 20.588 0 0 2.962 0 5.932 0 9.091 3.87-2.316 7.591-4.542 11.412-6.828 0 6.153 0 12.176 0 18.33-3.769-2.257-7.494-4.488-11.338-6.789 0 3.070 0 6.035 0 9.075z"></path>
</svg>

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="900px"
height="300px" viewBox="0 0 900 300" enable-background="new 0 0 900 300" xml:space="preserve">
<g id="Layer_1">
<g>
<path fill="none" d="M401.343,203.396c7.493,0,14.836,0,22.407,0c-3.766-12.354-7.495-24.586-11.333-37.176
C408.665,178.818,405.017,191.064,401.343,203.396z"/>
<path fill="#FFFFFF" d="M436.772,189.627c-4.399-12.521-8.814-25.034-13.224-37.553c-7.552,0-15.105,0-22.657,0.002
c-0.14,0.611-0.221,1.246-0.428,1.836c-8.502,24.335-17.017,48.666-25.526,72.996c-1.45,4.146-2.887,8.298-4.362,12.535
c6.686,0,13.198,0,19.792,0c2.095-6.873,4.172-13.693,6.248-20.514c10.593,0,21.056,0,31.594,0
c2.102,6.894,4.177,13.707,6.245,20.489c6.66,0,13.146,0,19.772,0c-0.229-0.676-0.408-1.213-0.597-1.747
C448.014,221.656,442.4,205.639,436.772,189.627z M401.343,203.396c3.674-12.332,7.322-24.578,11.074-37.176
c3.837,12.59,7.567,24.82,11.333,37.176C416.179,203.396,408.836,203.396,401.343,203.396z"/>
<path fill="#FFFFFF" d="M371.072,152.459c-21.916,0-43.668,0-65.421,0c0,5.111,0,10.227,0,15.341c7.836,0,15.672,0,23.691,0
c0,24.046,0,47.786,0,71.621c6.164,0,12.144,0,18.361,0c0-23.901,0-47.698,0-71.682c7.948,0,15.66,0,23.369,0
C371.072,162.549,371.072,157.549,371.072,152.459z"/>
<path fill="#FFFFFF" d="M532.615,152.555c-6.176,0-12.154,0-18.349,0c0,0.842,0,1.592,0,2.34c0,16.42,0.021,32.838-0.021,49.258
c-0.006,2.675-0.119,5.373-0.494,8.018c-0.997,7.07-4.634,11.153-11.06,12.587c-3.731,0.83-7.491,0.754-11.238,0
c-5.745-1.157-9.344-4.668-10.58-10.297c-0.678-3.088-0.958-6.317-0.976-9.487c-0.094-16.738-0.045-33.478-0.045-50.217
c0-0.732,0-1.467,0-2.148c-6.296,0-12.275,0-18.329,0c0,0.591,0,1.035,0,1.48c0,18.209-0.013,36.416,0.018,54.625
c0.003,1.908,0.127,3.835,0.396,5.727c1.632,11.408,7.683,19.563,18.562,23.516c11.146,4.052,22.489,3.83,33.593-0.393
c7.937-3.017,13.483-8.627,16.483-16.617c1.474-3.93,2.044-8.024,2.042-12.211c-0.006-18.146-0.002-36.289-0.002-54.436
C532.615,153.744,532.615,153.188,532.615,152.555z"/>
<path fill="#FFFFFF" d="M688.532,152.555c-6.16,0-12.14,0-18.349,0c0,0.924,0,1.62,0,2.318c0,16.482,0.021,32.967-0.021,49.449
c-0.006,2.609-0.125,5.244-0.49,7.824c-1.003,7.127-4.74,11.291-11.226,12.654c-3.674,0.771-7.373,0.702-11.056-0.037
c-5.74-1.156-9.354-4.652-10.596-10.281c-0.682-3.086-0.964-6.317-0.979-9.487c-0.094-16.738-0.044-33.478-0.044-50.216
c0-0.739,0-1.478,0-2.18c-6.278,0-12.26,0-18.332,0c0,0.582,0,1.024,0,1.467c0.003,18.271-0.011,36.543,0.021,54.815
c0.002,1.847,0.132,3.707,0.391,5.533c1.626,11.411,7.669,19.567,18.546,23.533c11.213,4.09,22.621,3.836,33.771-0.445
c7.851-3.019,13.345-8.612,16.315-16.541c1.521-4.052,2.06-8.274,2.056-12.592c-0.018-17.953-0.008-35.905-0.008-53.858
C688.532,153.893,688.532,153.27,688.532,152.555z"/>
<path fill="#FFFFFF" d="M542.405,167.793c7.813,0,15.522,0,23.479,0c0,23.979,0,47.771,0,71.648c6.172,0,12.102,0,18.425,0
c0-23.948,0-47.738,0-71.729c7.947,0,15.655,0,23.378,0c0-5.158,0-10.115,0-15.115c-21.819,0-43.53,0-65.281,0
C542.405,157.691,542.405,162.648,542.405,167.793z"/>
<path fill="#FFFFFF" d="M725.407,152.58c-6.199,0-12.177,0-18.193,0c0,29.021,0,57.92,0,86.857c17.832,0,35.528,0,53.335,0
c0-5.191,0-10.146,0-15.307c-11.72,0-23.322,0-35.142,0C725.407,200.143,725.407,176.361,725.407,152.58z"/>
<path fill="#FFFFFF" d="M790.668,152.593c-6.197,0-12.172,0-18.216,0c0,28.985,0,57.833,0,86.831c17.905,0,35.6,0,53.371,0
c0-5.105,0-10.107,0-15.316c-11.729,0-23.335,0-35.155,0C790.668,200.119,790.668,176.339,790.668,152.593z"/>
<path fill="#FFFFFF" d="M838.183,239.464c6.083,0,12.021,0,18.096,0c0-29.09,0-57.987,0-86.879c-6.12,0-12.098,0-18.096,0
C838.183,181.611,838.183,210.514,838.183,239.464z"/>
<ellipse fill="#E5A00D" cx="847.229" cy="129.416" rx="12.459" ry="12.44"/>
</g>
</g>
<g id="Layer_2_1_">
<g>
<image overflow="visible" opacity="0.2" width="279" height="216" xlink:href="13AD46AC.png" transform="matrix(1 0 0 1 15.5 73.5)">
</image>
<g>
<path fill="#FFFFFF" d="M243.77,212.601c-10.482,0-19.533,6.118-23.783,14.977l-37.755-5.478
c-0.133-14.445-11.881-26.114-26.356-26.114c-5.163,0-9.975,1.489-14.041,4.051l-53.649-60.787
c3.091-4.319,4.914-9.605,4.914-15.319c0-14.56-11.802-26.362-26.363-26.362c-14.56,0-26.363,11.803-26.363,26.362
c0,14.559,11.803,26.361,26.363,26.361c4.484,0,8.704-1.122,12.399-3.096l54.223,61.438c-2.439,3.994-3.846,8.688-3.846,13.712
c0,14.56,11.803,26.363,26.364,26.363c10.422,0,19.43-6.05,23.708-14.828l37.832,5.491c0.22,14.369,11.929,25.953,26.354,25.953
c14.56,0,26.363-11.804,26.363-26.362S258.33,212.601,243.77,212.601z"/>
</g>
</g>
<g>
<image overflow="visible" opacity="0.2" width="279" height="279" xlink:href="13AD46AD.png" transform="matrix(1 0 0 1 15.5 10.5)">
</image>
<g>
<path fill="#E5A00D" d="M243.77,34.779c-14.56,0-26.363,11.802-26.363,26.362c0,7.17,2.867,13.667,7.512,18.42l-58.424,82.548
c-3.25-1.431-6.84-2.23-10.619-2.23c-14.56,0-26.363,11.8-26.363,26.36c0,2.592,0.38,5.094,1.078,7.46L86.2,221.181
c-4.82-5.271-11.754-8.58-19.461-8.58c-14.56,0-26.363,11.803-26.363,26.361s11.803,26.362,26.363,26.362
c14.561,0,26.363-11.804,26.363-26.362c0-2.518-0.36-4.951-1.019-7.256l44.477-27.534c4.815,5.183,11.686,8.429,19.318,8.429
c14.561,0,26.364-11.803,26.364-26.361c0-6.424-2.301-12.31-6.119-16.883l58.973-83.322c2.72,0.948,5.637,1.468,8.677,1.468
c14.561,0,26.363-11.802,26.363-26.361C270.135,46.582,258.33,34.779,243.77,34.779z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="298.961px" height="300px" viewBox="0 0 298.961 300" enable-background="new 0 0 298.961 300" xml:space="preserve">
<g>
<image overflow="visible" opacity="0.2" width="289" height="224" xlink:href="93124B54.png" transform="matrix(1 0 0 1 4.9805 70.5)">
</image>
<g>
<path fill="#FFFFFF" d="M241.811,215.25c-10.935,0-20.375,6.382-24.809,15.623l-39.383-5.715
c-0.139-15.068-12.393-27.242-27.493-27.242c-5.385,0-10.405,1.554-14.646,4.229l-55.963-63.414
c3.224-4.505,5.127-10.02,5.127-15.981c0-15.188-12.312-27.5-27.5-27.5s-27.5,12.312-27.5,27.5s12.312,27.5,27.5,27.5
c4.677,0,9.079-1.171,12.934-3.23l56.56,64.089c-2.544,4.168-4.012,9.064-4.012,14.307c0,15.188,12.312,27.5,27.5,27.5
c10.872,0,20.269-6.311,24.731-15.467l39.463,5.727c0.229,14.99,12.443,27.074,27.49,27.074c15.188,0,27.5-12.313,27.5-27.5
S256.998,215.25,241.811,215.25z"/>
</g>
</g>
<g>
<image overflow="visible" opacity="0.2" width="289" height="289" xlink:href="93124B55.png" transform="matrix(1 0 0 1 4.9805 5.5)">
</image>
<g>
<path fill="#E5A00D" d="M241.811,29.75c-15.188,0-27.5,12.312-27.5,27.5c0,7.48,2.99,14.258,7.836,19.216l-60.943,86.113
c-3.389-1.493-7.135-2.329-11.076-2.329c-15.188,0-27.5,12.313-27.5,27.5c0,2.704,0.397,5.314,1.125,7.783l-46.306,28.668
c-5.028-5.5-12.261-8.951-20.3-8.951c-15.188,0-27.5,12.313-27.5,27.5s12.312,27.5,27.5,27.5s27.5-12.313,27.5-27.5
c0-2.627-0.376-5.165-1.064-7.57l46.396-28.724c5.022,5.407,12.189,8.794,20.15,8.794c15.188,0,27.5-12.313,27.5-27.5
c0-6.701-2.399-12.84-6.382-17.611l61.515-86.92c2.837,0.988,5.88,1.532,9.052,1.532c15.188,0,27.5-12.312,27.5-27.5
S256.998,29.75,241.811,29.75z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Some files were not shown because too many files have changed in this diff Show More