Compare commits

...

1013 Commits

Author SHA1 Message Date
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
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
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
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
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
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
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
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
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
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
Alex Malinovich
85a02771a7 Fix 404s for icon files and invalid paths 2017-02-21 01:44:12 -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
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
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
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
JonnyWong16
965fd170bd Merge branch 'dev' 2016-02-21 20:32:14 -08:00
JonnyWong16
2610d29b60 v1.3.8 2016-02-21 20:31:51 -08:00
JonnyWong16
064131c842 Uncheck monitor remote access if remote access diabled on server 2016-02-21 17:20:18 -08:00
JonnyWong16
00b6bf8394 Return default ip_address/poster_url if database query fails 2016-02-21 17:11:49 -08:00
JonnyWong16
2a885d709d Allow disabling poster upload to Imgur
* Disabled by default
2016-02-21 17:06:05 -08:00
JonnyWong16
5bed46c0aa Encode poster title to UTF-8 for Imgur upload 2016-02-21 17:05:10 -08:00
JonnyWong16
8b27c7e01a Remove poster url from notification logs table 2016-02-21 16:42:29 -08:00
JonnyWong16
177902a286 Remove media tags from script_args for server notifications 2016-02-21 16:42:08 -08:00
JonnyWong16
48b0f7dc27 Fix NoneType error in set_notify_state 2016-02-21 16:33:42 -08:00
JonnyWong16
d5f4a1a48a Make readme consistent with settings page 2016-02-21 16:18:26 -08:00
JonnyWong16
de9f60aa7f Add notification log table 2016-02-21 15:45:28 -08:00
JonnyWong16
c93b65b299 Rework notify_log table to save each notification separately 2016-02-21 15:44:21 -08:00
JonnyWong16
3c6a6cdc5b Fix wording on settings page 2016-02-21 14:56:19 -08:00
JonnyWong16
b669f3d715 Fix regression unable to clear the http password 2016-02-21 09:58:27 -08:00
JonnyWong16
f663fac220 Save Imgur URL to database 2016-02-21 09:34:51 -08:00
JonnyWong16
bc42e79bb5 Catch HTTP errors for Imgur upload 2016-02-21 09:33:31 -08:00
JonnyWong16
ca29333cd0 Log if opening secure websocket 2016-02-20 20:50:20 -08:00
JonnyWong16
f9f478e100 Update CONTRIBUTING.md with info about issue reporting and feature requests 2016-02-20 20:47:33 -08:00
JonnyWong16
97c414d1ad Merge branch 'dev' 2016-02-20 19:54:37 -08:00
JonnyWong16
7afbd98d17 v1.3.7 2016-02-20 19:53:21 -08:00
JonnyWong16
1f5c60588e Change Facebook help text 2016-02-20 08:45:00 -08:00
JonnyWong16
284ab45a17 Upload Plex posters to Imgur for notifications 2016-02-19 23:25:33 -08:00
JonnyWong16
eab6365af9 Disable IP logging checkbox depending on server version 2016-02-19 21:02:48 -08:00
JonnyWong16
de86516a0a Disable monitor remote access checkbox if remote access is disabled
* And anonymize URLs
2016-02-18 22:48:02 -08:00
JonnyWong16
3e50e11933 Simplify log_type 2016-02-18 22:26:13 -08:00
JonnyWong16
e2ac8be451 Cleanup save settings 2016-02-18 22:24:19 -08:00
JonnyWong16
0e53252a27 Move get poster to notification handler 2016-02-18 21:09:07 -08:00
JonnyWong16
b1ecff3d10 Add TV posters to Facebook notifications 2016-02-18 18:52:07 -08:00
JonnyWong16
0fee4fee2a Fix typo from e38e98d9e7 2016-02-18 12:03:28 -08:00
drzoidberg33
66282d817c Merge pull request #551 from drzoidberg33/scanner-log-view
Add Plex Media Scanner log files to Log viewer.
2016-02-18 18:08:11 +02:00
Tim Van
932c93e573 Ensure we default to the server log. 2016-02-18 18:06:36 +02:00
Tim Van
71d30af582 Add Plex Media Scanner log files to Log viewer. 2016-02-18 18:01:42 +02:00
JonnyWong16
1c8428c3ea Add backup back to api 2016-02-18 06:53:07 -08:00
JonnyWong16
e38e98d9e7 Some code cleanup for libraries and users 2016-02-17 22:10:00 -08:00
JonnyWong16
85b3f081bf Add scheduled database backups 2016-02-17 18:41:55 -08:00
JonnyWong16
3926d97fc6 Open settings links in new tabs 2016-02-17 18:41:16 -08:00
JonnyWong16
13ac8f2ea4 Revert homepage watch statistic back to "last watched" 2016-02-17 18:33:01 -08:00
JonnyWong16
d94f991ab5 Add icon to scheduler status 2016-02-17 18:32:17 -08:00
JonnyWong16
d476d2e96a Merge pull request #541 from JonnyWong16/ssl-certificates
Create self-signed HTTPS certificates
2016-02-15 18:38:15 -08:00
JonnyWong16
635bf364ac Hide HTTPS Domains and IPs if not creating self-signed certificate 2016-02-15 18:36:01 -08:00
JonnyWong16
e1c7a37f62 Only create self-signed certificate if enabled 2016-02-15 18:36:01 -08:00
JonnyWong16
9d780701f5 Create self-signed HTTPS certificates 2016-02-15 18:36:01 -08:00
JonnyWong16
0bd40405b5 Test poster images for Facebook notifications 2016-02-14 22:36:19 -08:00
JonnyWong16
25c2f95e48 Separate out scheduler table to allow reloading 2016-02-14 21:02:14 -08:00
JonnyWong16
5d738e58eb Schedule PlexPy database backup task 2016-02-14 18:25:58 -08:00
JonnyWong16
70325f9247 Bold "bell icon" on notification agents page 2016-02-14 18:25:36 -08:00
JonnyWong16
38c9c5a6ea Add configuration and scheduler info to settings page 2016-02-14 17:51:14 -08:00
JonnyWong16
c90dd147bb Rename config_id to agent_id 2016-02-14 11:39:03 -08:00
JonnyWong16
322f106e75 Log JS errors from the WebUI 2016-02-14 11:35:14 -08:00
JonnyWong16
91a5529438 Some APIv2 cleanup 2016-02-14 11:03:32 -08:00
JonnyWong16
8f7dd2df6a Merge pull request #377 from Hellowlol/api2
Api2
2016-02-13 09:30:29 -08:00
Hellowlol
2fcd55eb60 API2 2016-02-10 22:09:41 +01:00
JonnyWong16
9359567a8a Add optional subject line to notification agents 2016-02-09 23:00:10 -08:00
JonnyWong16
42bfacfb19 Add IMDB, TVDB, TMDb, last.fm, and trakt to notification options 2016-02-09 22:20:17 -08:00
JonnyWong16
71131c699e Add total duration to libraries and users tables 2016-02-09 17:58:56 -08:00
JonnyWong16
6ebfc516a6 Add ETA to current activity 2016-02-09 17:08:59 -08:00
JonnyWong16
5c952b1d86 Fix regression where {stream_duration} not reported 2016-02-09 17:08:44 -08:00
JonnyWong16
1d9a4e0b99 Add view_offset to history grouping logic 2016-02-08 17:34:24 -08:00
JonnyWong16
ebae628d8d Fix typo in notification exclusion tag usage modal 2016-02-07 23:23:36 -08:00
JonnyWong16
9865460fe5 Move PMS_SSL to correct section in config file 2016-02-07 16:12:37 -08:00
drzoidberg33
39884b71fe Merge pull request #529 from drzoidberg33/machine-id-fix
Fix bad SSL connections.
2016-02-08 02:08:51 +02:00
Tim Van
82b7128c04 Allow secure websocket connections. 2016-02-08 01:29:57 +02:00
Tim Van
16756ddb8c Don't chose a custom URL when picking a hostname for local SSL configs. 2016-02-08 00:21:40 +02:00
JonnyWong16
877002961f Use custom library icons in library statistics 2016-02-07 12:42:24 -08:00
JonnyWong16
7e9e68ecd8 Fix video media flags for tracks 2016-02-07 12:42:07 -08:00
Tim Van
6419190272 Revert silly naming bug. 2016-02-07 22:34:38 +02:00
Tim Van
ac42563c5e Refresh PMS URL when changing is_remote option in settings. 2016-02-07 22:28:04 +02:00
Tim Van
98c1063e07 Allows us to retrieve the serverId again if we have secure connections required. 2016-02-07 22:21:46 +02:00
Tim Van
a4dfc57cbe Fix some issues with possible mismatching serverIDs causing bad ssl connections. 2016-02-07 15:00:06 +02:00
JonnyWong16
db543b8912 Add {machine_id} to notification options 2016-02-04 08:34:15 -08:00
JonnyWong16
49fb4540a2 Merge branch 'dev' 2016-02-03 20:55:10 -08:00
JonnyWong16
e2120393a2 v1.3.6 2016-02-03 20:54:28 -08:00
JonnyWong16
0b301fff3f Fix regression where duration not reported as min 2016-02-03 09:32:32 -08:00
JonnyWong16
eeb351e991 Update readme 2016-02-02 22:34:46 -08:00
JonnyWong16
1095e29b4d Fix FreeBSD and FreeNAS init scripts daemonizing 2016-02-02 21:23:48 -08:00
JonnyWong16
be058eaff7 Merge branch 'dev' 2016-02-02 21:13:34 -08:00
JonnyWong16
f409dda2ef v1.3.5 2016-02-02 21:12:53 -08:00
JonnyWong16
f409cdda8f Merge pull request #502 from JonnyWong16/startup-tasks-after-daemonizing
Run startup tasks after daemonizing
2016-02-02 21:03:52 -08:00
JonnyWong16
9cd6396c35 Add method to delete duplicate libraries 2016-02-02 20:54:34 -08:00
JonnyWong16
ee754ea533 Remove trailing slash from Facebook redirect URI 2016-02-02 20:38:16 -08:00
JonnyWong16
36de20dd75 Fix getting new pms_identifier for server only 2016-02-02 20:33:47 -08:00
JonnyWong16
a957e8eb4f Clean up time formats for server notifications 2016-02-02 20:33:08 -08:00
JonnyWong16
14a90d84ec Add {stream_time}, {remaining_time}, and {progress_time} to notification options 2016-01-31 16:15:06 -08:00
JonnyWong16
fae9bc618a Initialize PlexPy after daemonizing 2016-01-31 15:13:35 -08:00
JonnyWong16
3248e6500e Clean up build_notify_text
* session is now a dict, so no need for "default values"
2016-01-31 13:34:51 -08:00
JonnyWong16
c17bf79d79 Fix server verification for unpublished servers 2016-01-31 11:32:44 -08:00
JonnyWong16
1ff1270bfa Clean up powershell for scripts 2016-01-30 16:18:45 -08:00
JonnyWong16
b1a2cf33d8 Merge pull request #498 from Hellowlol/ps1
add support for powershell
2016-01-30 15:54:34 -08:00
Hellowlol
b2292e98c1 add support for powershell 2016-01-31 00:18:58 +01:00
JonnyWong16
4d156a8911 Allow expanding of media info table when missing added at date 2016-01-30 00:48:51 -08:00
JonnyWong16
7193b6518b Fix removing unique constraints from database 2016-01-30 00:40:06 -08:00
JonnyWong16
cff6b44109 Merge branch 'dev' 2016-01-29 21:32:37 -08:00
JonnyWong16
fb7ad9438e v1.3.4 2016-01-29 21:31:25 -08:00
JonnyWong16
afc265a188 Fix schedulers not starting with library update 2016-01-29 21:26:27 -08:00
JonnyWong16
01fe7bf612 Reorganize notification options 2016-01-29 19:06:08 -08:00
JonnyWong16
1cb75bd053 Remove unnecessary quoting of script arguments 2016-01-29 18:47:12 -08:00
JonnyWong16
0eaea4d011 Fix empty libraries not added 2016-01-29 18:38:19 -08:00
JonnyWong16
67377a2561 Fix server verification in settings 2016-01-27 23:32:21 -08:00
JonnyWong16
a8aae9f1f5 Fix libraries and users refresh 2016-01-27 23:32:01 -08:00
JonnyWong16
a9ce92decb Change Telegram wording 2016-01-27 21:30:35 -08:00
JonnyWong16
c19162295a Update Facebook instructions 2016-01-27 21:20:04 -08:00
JonnyWong16
58796c45ed Remove built in Twitter consumer key and secret 2016-01-27 21:19:18 -08:00
JonnyWong16
d94b348780 Fix buffer notifications even when disabled with websockets 2016-01-27 19:52:30 -08:00
JonnyWong16
95f92bd292 Add unique identifiers to notification options 2016-01-27 19:51:58 -08:00
JonnyWong16
bc52ac3559 Remove media type toggles from recently added notifications 2016-01-27 19:51:36 -08:00
JonnyWong16
8bbc6a6611 Fix libraries without section_id in database 2016-01-27 19:51:10 -08:00
JonnyWong16
8902b93a26 Merge branch 'dev' 2016-01-26 00:14:38 -08:00
JonnyWong16
ae36af807d v1.3.3 2016-01-26 00:13:58 -08:00
JonnyWong16
fd256625c6 Fix Plays by Month graph not loading 2016-01-25 18:43:51 -08:00
JonnyWong16
bee543a25a Disable datatables caching 2016-01-25 18:30:30 -08:00
JonnyWong16
55eb79cb52 Even faster library updating 2016-01-25 12:01:59 -08:00
JonnyWong16
35965a8320 Merge branch 'dev' 2016-01-24 22:52:47 -08:00
JonnyWong16
8a902ae3e6 v1.3.2 2016-01-24 22:51:36 -08:00
JonnyWong16
52bed5bf98 Attempt at improved library updating 2016-01-24 22:19:48 -08:00
JonnyWong16
9e83f6d779 Another fix for 'datestamp' and 'timestamp' 2016-01-24 09:52:20 -08:00
elseym
0873beaed2 enable pushover html support by default, introduce option to deactivate 2016-01-24 18:06:36 +01:00
JonnyWong16
0ba5012464 Merge branch 'dev' 2016-01-23 22:59:46 -08:00
JonnyWong16
73ff28465d v1.3.1 2016-01-23 22:58:44 -08:00
JonnyWong16
7484d65dbb Fix datestamp and timestamp notification options 2016-01-23 22:53:13 -08:00
JonnyWong16
4a120e7a54 Fix unable to startup if library refresh fails 2016-01-23 21:06:41 -08:00
JonnyWong16
8d63d85821 Fix star rating overlapping text 2016-01-23 19:14:54 -08:00
JonnyWong16
5cec84a802 More descriptive libraries updating message 2016-01-23 19:13:16 -08:00
JonnyWong16
48da41690d Fix empty brackets on tables 2016-01-23 19:12:13 -08:00
JonnyWong16
1c82241f30 Fix notifier config ajax calls for reverse proxies 2016-01-23 16:23:20 -08:00
JonnyWong16
b1ea3bcd4e Rename last watched to last played 2016-01-23 14:06:25 -08:00
JonnyWong16
05e485b55e Merge branch 'dev' 2016-01-23 13:23:45 -08:00
JonnyWong16
c62e0e4e99 v1.3.0 2016-01-23 13:21:51 -08:00
JonnyWong16
3c6a1a02b8 Merge pull request #462 from jackwilsdon/fix-restart-dev
Use os.execv instead of subprocess.Popen to restart the process
2016-01-23 13:16:13 -08:00
JonnyWong16
cc287607cd Allow custom search query to update metadata 2016-01-23 12:40:41 -08:00
JonnyWong16
b24e9a2185 Allow custom redirect uri with Facebook notifier 2016-01-23 08:12:41 -08:00
JonnyWong16
01791eac52 Fix rating_key on sync table 2016-01-23 08:05:04 -08:00
JonnyWong16
651b57a93f Add datestamp and timestamp notification options 2016-01-22 19:16:15 -08:00
JonnyWong16
cc857364f4 Fix typos in Notifiers logger 2016-01-22 18:01:32 -08:00
JonnyWong16
f29d7c8cfb Fix stream info modal on Users and Libraries pages 2016-01-22 17:59:20 -08:00
JonnyWong16
af4d0248d9 Revert https cert and key to custom directory 2016-01-22 10:17:17 -08:00
JonnyWong16
2990664b2b Fix section_id for plexwatch import 2016-01-22 09:09:37 -08:00
Jack Wilsdon
ed52038bc4 Use os.execv instead of subprocess.Popen to restart the process
This fixes #460.
2016-01-22 13:19:27 +00:00
JonnyWong16
ee125dfadc Forgot 'not' in 2dcae5e219 2016-01-19 08:31:49 -08:00
JonnyWong16
196048cf38 Work around for iOS web app links opening in Safari 2016-01-19 00:06:14 -08:00
JonnyWong16
5faf357045 Disable logging while library update in progress 2016-01-18 23:48:31 -08:00
JonnyWong16
4e0f06f24d Remove unique constraint for section_id and username 2016-01-18 22:20:14 -08:00
JonnyWong16
717530fff7 Fix Users list not sorting alphabetically 2016-01-18 19:55:10 -08:00
JonnyWong16
4a5e38dc1e Fix error refreshing library counts when XML fails
* Also increase http request timeout to 20 seconds
2016-01-18 19:27:58 -08:00
JonnyWong16
419f8dadad Fix another typo 2016-01-18 19:03:55 -08:00
JonnyWong16
2dcae5e219 Fix folders not created in the data directory 2016-01-18 18:52:01 -08:00
JonnyWong16
36a99f70a3 Fix error when script directory doesn't exist 2016-01-18 18:30:22 -08:00
JonnyWong16
c98cf858c1 Fix typo on edit library and edit user modals 2016-01-18 18:24:07 -08:00
JonnyWong16
dd463f00a7 Fix Facebook authorization not working 2016-01-18 18:22:48 -08:00
JonnyWong16
2459340c6f Fix user duplicated in Library user stats 2016-01-18 12:59:26 -08:00
JonnyWong16
76db5ffa3a Use font awesome for star rating 2016-01-17 22:16:12 -08:00
JonnyWong16
2db0e9c280 Add all media flags 2016-01-17 22:14:16 -08:00
JonnyWong16
db6dbe6c19 Fix refresh media info table doubling rows 2016-01-17 22:14:12 -08:00
JonnyWong16
ecedd4d231 Merge pull request #263 from drzoidberg33/library-id-changes
Library id changes
2016-01-17 16:43:46 -08:00
JonnyWong16
1809b95e2d Add setting to enable calculating total file sizes
* Setting is disabled by default
2016-01-17 16:15:28 -08:00
JonnyWong16
0d7e261bd1 Improved caching and fixed tables 2016-01-17 12:34:23 -08:00
JonnyWong16
908941fb82 Prettier thumbnail popovers 2016-01-17 01:10:25 -08:00
JonnyWong16
fbacc4f789 Add media info icons to info page 2016-01-16 23:17:04 -08:00
Jonathan Wong
3c1290e8fd Some more minor changes 2016-01-16 19:27:40 -08:00
Jonathan Wong
35528ef602 Get file sizes for media info table 2016-01-16 18:23:08 -08:00
Jonathan Wong
c0f0cb0d9e Don't cache last watched or play count 2016-01-16 04:10:21 -08:00
Jonathan Wong
4a65dc1d6e Start database section id update on its own thread 2016-01-16 03:31:00 -08:00
Jonathan Wong
b4a25e33bb Fix websocket log spam
* Bug where websocket reports a session playing while /status/sessions
reports nothing.
2016-01-16 03:28:39 -08:00
Jonathan Wong
7f1a08dd04 Final clean up 2016-01-16 01:51:50 -08:00
Jonathan Wong
6152a1e913 Fix bugs with media info table 2016-01-15 22:15:45 -08:00
Jonathan Wong
002cb93187 Clean up for welcome page 2016-01-15 20:59:14 -08:00
Jonathan Wong
381c3da31c Add media info table to library page 2016-01-15 20:59:02 -08:00
Jonathan Wong
10e4d562ab Clean up graphs.py 2016-01-15 20:58:57 -08:00
Jonathan Wong
2a85e11ad9 Add library recently added 2016-01-15 20:58:55 -08:00
Jonathan Wong
95b55760ad Add sortable homepage cards 2016-01-15 20:58:53 -08:00
Jonathan Wong
636f898da8 Massive code cleanup
* Finish up library pages (toggles and notifications)
* Update user pages to match library pages
* Fix no current activity bif thumbnail at the start of a stream
* Improved logging throughout PlexPy
2016-01-15 20:58:44 -08:00
Jonathan Wong
5fedac691d Add individual library page 2016-01-15 20:50:18 -08:00
Jonathan Wong
979d68957e Clean up users page to match libraries page 2016-01-15 20:49:59 -08:00
Jonathan Wong
a5b0837cf5 Add libraries page 2016-01-15 20:49:41 -08:00
Jonathan Wong
8ba68dcfcf Change home cards config to list type 2016-01-15 20:49:22 -08:00
Jonathan Wong
8f367d140f Add item counts to database
* Add schedule task to refresh libraries list
* Update library stats to use library_sections table
2016-01-15 20:49:04 -08:00
Jonathan Wong
771885f27f Add update metadata feature
* Use rating_key instead of item_id for history info
2016-01-15 20:48:47 -08:00
Jonathan Wong
09aac22909 Initial library_id changes
* Give the library sections their own db table.
2016-01-15 20:48:29 -08:00
Jonathan Wong
1de3c0d559 Fixes for testing script notifications 2016-01-15 00:33:40 -08:00
JonnyWong16
0988b68c8c Merge pull request #391 from PHoSawyer/dev
CentOS 6.X startup script
2016-01-13 00:24:31 -08:00
Jonathan Wong
325ad4094e Clean up Web Apps 2016-01-13 00:16:50 -08:00
JonnyWong16
16a09407e4 Merge pull request #436 from zobe123/dev
Web Apps
2016-01-13 00:12:12 -08:00
JonnyWong16
84256f42c6 Merge pull request #419 from JonnyWong16/facebook-agent
Add Facebook notification agent
2016-01-12 23:28:03 -08:00
JonnyWong16
7befbef6ec Add Facebook notification agent 2016-01-12 23:22:54 -08:00
Jonathan Wong
754df5bea7 Fix to get new pms identifier on server change 2016-01-12 22:39:32 -08:00
Jonathan Wong
78ee646558 Fix for empty most concurrent stat 2016-01-12 22:06:21 -08:00
Jonathan Wong
3d6f89d309 Clean up scripts 2016-01-12 21:38:47 -08:00
JonnyWong16
e321479712 Merge pull request #373 from Hellowlol/scripts
Scripts
2016-01-12 21:05:26 -08:00
Hellowlol
9328b7e586 Add scripts 2016-01-12 22:12:48 +01:00
zobe123
50ace54cd0 improvements 2016-01-12 20:59:32 +01:00
Hellowlol
ad365c7dd0 fix conflicts 2016-01-11 22:24:13 +01:00
zobe123
11427dbecd added commits how JonnyWong16 wanted
* added iOS WebAPP Icons/Splashscreens
* added android WebAPP Icons/Splashscreens
* added IE10 Icons
* Updated plexpy.css - prevents the text is larger than the box on small
screens.
2016-01-11 21:31:46 +01:00
Jonathan Wong
b490831a50 More concurrent stream stats
* Also fix graph queries
2016-01-08 22:49:04 -08:00
JonnyWong16
af76017a79 Fix datatable paging visual bug in Firefox 2016-01-08 17:58:04 -08:00
JonnyWong16
43409b3089 Fix month name localization on play totals graph
#423
2016-01-07 20:37:00 -08:00
Jonathan Wong
bfad769f93 Return message for missing changelog file 2016-01-06 18:54:30 -08:00
Jonathan Wong
7e5dce1c14 Fix regression for grouped recently added metadata 2016-01-03 23:49:58 -08:00
JonnyWong16
8ba4bebe01 Merge pull request #401 from Hellowlol/patch-4
Enable webapp for mobile devices
2015-12-31 20:16:39 -08:00
JonnyWong16
78a87db017 Merge pull request #414 from JonnyWong16/miscellaneous-fixes
Allow SSL when verifying server in settings and test notifications
2015-12-31 20:14:12 -08:00
JonnyWong16
b73a259f68 Clean up Slack agent 2015-12-31 20:13:54 -08:00
JonnyWong16
65f27ee605 Add Email from name option 2015-12-31 20:06:31 -08:00
JonnyWong16
6d5b5e15d5 Remove PlexPy Pushover API token
* User's own API token is now required
2015-12-31 20:06:29 -08:00
JonnyWong16
f31c4dcccd Add test notification for all agents 2015-12-31 20:04:08 -08:00
JonnyWong16
1e616fa585 Allow SSL when verifying server in settings 2015-12-31 20:02:54 -08:00
JonnyWong16
0d2666f7d3 Merge pull request #418 from richipargo/slack-agent
Add slack as a notification agent
2015-12-31 19:58:57 -08:00
Ricardo Tapia
0dd8970668 added url icon validation 2015-12-31 21:13:20 -06:00
Ricardo Tapia
89cda3dcff typo for telegram agent 2015-12-31 21:08:24 -06:00
Ricardo Tapia
1d48688518 finished slack integration 2015-12-31 21:04:33 -06:00
richipargo
0b59f5e29c Slack notification config 2015-12-31 16:26:10 -06:00
Ricardo Tapia
5aebc8d191 slack config options 2015-12-31 15:34:53 -06:00
richipargo
6e00c5da04 Return Settings 2015-12-31 15:21:01 -06:00
Ricardo Tapia
50b06e041c initial agent settings 2015-12-31 13:22:27 -06:00
JonnyWong16
1c539f00dd Fix duration for grouped home stats 2015-12-27 19:46:29 -08:00
JonnyWong16
87ca432ec8 Fix get server friendly name after wizard 2015-12-26 19:55:36 -08:00
Hellowlol
ca33f4a2a5 webapp
https://github.com/drzoidberg33/plexpy/issues/398
2015-12-27 01:07:31 +01:00
Jonathan Wong
9409303f24 Merge branch 'dev' 2015-12-22 19:36:10 -08:00
Jonathan Wong
94a3d35c90 v1.2.16 2015-12-22 19:35:11 -08:00
Jonathan Wong
851de4934b Change logs to 50 line default 2015-12-22 19:31:59 -08:00
JonnyWong16
2942640eb9 Fix most concurrent stat for empty database 2015-12-22 10:21:55 -08:00
PHoSawyer
1cef037db5 CentOS 6.X startup script
Init file for CentOS 6.X systems, variables exist for different install directorys. Please note, current version of Python is 2.6 and PlexPy requires 2.7. A variable exists to point to this path.

Since PlexPy is based on Headphones, I just copied the init script for Headphones and changed the paths and added the Python2.7 path
2015-12-21 15:20:35 +00:00
Jonathan Wong
a00d43092d Merge branch 'dev' 2015-12-20 09:34:38 -08:00
Jonathan Wong
45c2f50018 v1.2.15 2015-12-20 09:33:04 -08:00
JonnyWong16
ef8c6e82e6 Merge pull request #381 from JonnyWong16/miscellaneous-fixes
Group watch statistics history
2015-12-20 03:22:39 -08:00
Jonathan Wong
3eebb58da5 Fix most concurrent count with duplicate time entires 2015-12-20 03:14:39 -08:00
Jonathan Wong
447c50fd03 Group watch statistics history 2015-12-19 20:40:30 -08:00
Jonathan Wong
0620ebebcf Touch up current activity status bar hover effect 2015-12-17 23:26:26 -08:00
JonnyWong16
cf081ee291 Merge pull request #380 from zobe123/patch-1
Added Statusbar hover effect with percentage
2015-12-17 23:18:22 -08:00
zobe123
3c29b8e9c5 Update plexpy.css
Added Statusbar hover effect with percentage
2015-12-17 23:33:53 +01:00
zobe123
6143da5a6a Update pmsconnect.py
some additions to Show readable transcode progress
2015-12-17 23:25:29 +01:00
JonnyWong16
664f71575c Merge pull request #370 from JonnyWong16/miscellaneous-fixes
Miscellaneous fixes
2015-12-16 19:52:07 -08:00
Jonathan Wong
9ae111b8a1 Fix Growl notifications 2015-12-16 19:42:51 -08:00
Jonathan Wong
18682c7a2e Add logger info for Boxcar2 notification sent 2015-12-15 19:56:14 -08:00
Jonathan Wong
b21c50dfcf Fix typo on settings page 2015-12-13 23:53:22 -08:00
Jonathan Wong
49b6965e8e Add CC and BCC and multiple email recipients 2015-12-13 15:08:43 -08:00
Jonathan Wong
c6cc2b8831 Save graph type/days/tab to config file
* Change input for graph days range
2015-12-13 11:35:33 -08:00
Jonathan Wong
f9f65eae53 Add duration to history table footer 2015-12-13 09:36:54 -08:00
Jonathan Wong
b51d442673 Add notification for remote access/server back up 2015-12-13 09:31:11 -08:00
Jonathan Wong
5863b62ccf Add notifier name to modal title 2015-12-12 17:32:32 -08:00
Jonathan Wong
66bb922012 Add stream details to notification options
* Also beautify modal
2015-12-12 17:31:52 -08:00
Jonathan Wong
53876e8f0d Add time range to most concurrent stat
* Reorder cards
2015-12-12 16:21:54 -08:00
Jonathan Wong
cb7ba7fdde Clean up if statement in current activity header 2015-12-12 14:36:57 -08:00
Jonathan Wong
9cf6793b24 Add most concurrent streams home statistic 2015-12-12 14:34:42 -08:00
Jonathan Wong
6e62ffdd22 Get Pushbullet devices automatically using API 2015-12-12 14:34:11 -08:00
Jonathan Wong
c042d9e39a Fix metadata for grouped recently added notifications 2015-12-12 14:31:04 -08:00
Jonathan Wong
1262de2ae2 Clean up notifiers 2015-12-12 14:30:42 -08:00
JonnyWong16
307230cec8 Merge pull request #365 from zobe123/patch-1
Update current_activity_header.html
2015-12-12 14:10:27 -08:00
drzoidberg33
4fa2711e78 Merge pull request #367 from drzoidberg33/frontend-tweaks
Fix greedy search bar.
2015-12-12 16:20:44 +02:00
Tim
5c9c2f9ab8 Fix greedy search bar. 2015-12-12 16:19:30 +02:00
zobe123
604155b41b Update current_activity_header.html
remove "no"
2015-12-11 22:23:14 +01:00
zobe123
6e4198e7be Update current_activity_header.html
dynamic "s" at the word stream/streams
added "no" before Activity when their is no activity
2015-12-10 23:56:02 +01:00
drzoidberg33
14d4940d05 Merge pull request #363 from InAnimaTe/dev
add .pem cert to ignore list
2015-12-09 18:47:22 +02:00
Mario Loria
a6b0cdef97 add .pem cert to ignore list 2015-12-09 11:00:53 -05:00
Tim
6265943607 Merge branch 'dev' 2015-12-07 22:32:00 +02:00
Tim
de39f7691c v1.2.14 2015-12-07 22:31:00 +02:00
drzoidberg33
921a219beb Merge pull request #352 from drzoidberg33/security-fixes
Fix regression on select_single queries Resolves #350
2015-12-07 22:26:33 +02:00
Tim
b9c95d49a6 Fix regression on select_single queries. 2015-12-07 22:22:47 +02:00
Jonathan Wong
fc0be6bce2 Merge branch 'dev' 2015-12-06 11:41:08 -08:00
Jonathan Wong
8db891cfe6 v1.2.13 2015-12-06 11:40:17 -08:00
JonnyWong16
f6e77cc578 Merge pull request #346 from JonnyWong16/miscellaneous-fixes
Fix current activity
2015-12-06 11:36:05 -08:00
Jonathan Wong
a3782f9150 Fix dict key for IP address in current activity 2015-12-06 11:30:33 -08:00
drzoidberg33
7546c7ef42 Merge pull request #345 from drzoidberg33/security-fixes
Security fixes
2015-12-06 21:23:43 +02:00
Jonathan Wong
53de8cda30 Match newline between tags for notification text 2015-12-06 11:13:46 -08:00
Tim
1fb7473dc5 Sanitize sync row items. 2015-12-06 21:04:33 +02:00
Tim
cc9d09bd54 Allow HTML encoded content to be displayed in notification setting descriptions. 2015-12-06 20:49:00 +02:00
Tim
42ff4a2f62 Merge branch 'dev' 2015-12-06 20:02:18 +02:00
Tim
3fa5f80fc4 v1.2.12 2015-12-06 20:01:38 +02:00
drzoidberg33
9b5b7ef8db Merge pull request #343 from drzoidberg33/security-fixes
No need to sanitize same items more than once.
2015-12-06 19:59:34 +02:00
Tim
560acf62fe No need to sanitize same items more than once. 2015-12-06 18:45:02 +02:00
drzoidberg33
27d12922da Merge pull request #339 from drzoidberg33/security-fixes
Move dict_factory out of database class.
2015-12-06 18:10:26 +02:00
Tim
37b92f3d88 Move dict_factory out of database class. 2015-12-06 18:09:18 +02:00
Tim
79d5c0c92e Merge branch 'dev' 2015-12-06 17:33:12 +02:00
Tim
0bdaedd486 Fix more regresssions. 2015-12-06 17:32:25 +02:00
drzoidberg33
018a201688 Merge pull request #338 from drzoidberg33/security-fixes
More dict key fixes.
2015-12-06 17:21:54 +02:00
Tim
a5bd7e6563 More dict key fixes. 2015-12-06 17:19:09 +02:00
drzoidberg33
a055feccd5 Merge pull request #337 from drzoidberg33/security-fixes
Fix changelog modal output.
2015-12-06 16:38:54 +02:00
Tim
ba68a9b52b Fix changelog modal output. 2015-12-06 16:32:07 +02:00
Tim
49669dc7e0 Merge branch 'dev' 2015-12-06 16:16:39 +02:00
Tim
5bdf79606e v1.2.10 2015-12-06 16:16:03 +02:00
drzoidberg33
ff3a9e47df Merge pull request #335 from drzoidberg33/security-fixes
Fix count type graphs.
2015-12-06 16:12:28 +02:00
Tim
a18ba24f4a Fix count type graphs. 2015-12-06 16:07:57 +02:00
Tim
baeb744a7c Merge branch 'dev' 2015-12-06 14:53:04 +02:00
Tim
d07add383f v1.2.9 2015-12-06 14:52:19 +02:00
drzoidberg33
a1f18bc133 Merge pull request #334 from drzoidberg33/security-fixes
Escape input on friendy_name change.
2015-12-06 14:41:31 +02:00
Tim
e00c23bc49 Escape input on friendy_name change. 2015-12-06 14:39:50 +02:00
drzoidberg33
0228a356e4 Merge pull request #333 from drzoidberg33/security-fixes
Better sanitization on templates and datatables output.
2015-12-06 14:18:22 +02:00
Tim
b0fa0d534e Better sanitization on templates and datatables output. 2015-12-06 14:09:38 +02:00
Jonathan Wong
1157fda96c Hide Pushalot notifier message logging 2015-12-06 00:52:43 -08:00
Jonathan Wong
bbf774379d Merge branch 'dev' 2015-12-05 23:45:35 -08:00
Jonathan Wong
24c8c4319d v1.2.8 2015-12-05 23:44:02 -08:00
JonnyWong16
3b8f9f5892 Merge pull request #328 from JonnyWong16/miscellaneous-fixes
Fix recently added
2015-12-05 23:28:49 -08:00
Jonathan Wong
b47ccd06f9 Sanitize player name 2015-12-05 23:26:54 -08:00
Jonathan Wong
8c4292f9ac Fix recently added using added at time 2015-12-05 14:23:10 -08:00
JonnyWong16
a8fbf8ab1d Merge pull request #327 from zobe123/dev
add Microsoft Edge platform
2015-12-05 11:05:30 -08:00
zobe123
38e9938666 Add Microsoft Edge platform image. 2015-12-05 13:31:56 +01:00
zobe123
93c4a0652e Revert "Add Image for Microsoft Edge"
This reverts commit d12b57e1de.
2015-12-05 13:29:10 +01:00
zobe123
2fff6647fd Revert "Update msedge.png"
This reverts commit 36f0f60c49.
2015-12-05 13:29:01 +01:00
zobe123
36f0f60c49 Update msedge.png 2015-12-05 13:02:53 +01:00
zobe123
d12b57e1de Add Image for Microsoft Edge 2015-12-05 13:02:19 +01:00
zobe123
deb16428ed Update script.js 2015-12-05 12:57:26 +01:00
drzoidberg33
a75aba4aee Merge pull request #324 from JonnyWong16/miscellaneous-fixes
Only schedule job for recently added or monitor remote access if sett…
2015-12-04 20:12:44 +02:00
Jonathan Wong
bb5aa2be3d Remember previous recently added items
* Only pull metadata if there are new recently added items since the
last check
2015-12-03 19:50:46 -08:00
Jonathan Wong
ef6ef98541 Clean up settings help text and wording 2015-12-03 19:07:24 -08:00
Jonathan Wong
89f581f63e Only schedule job for recently added or monitor remote access if setting enabled 2015-12-03 18:40:18 -08:00
JonnyWong16
6081fa329b Merge pull request #321 from JonnyWong16/miscellaneous-fixes
Miscellaneous fixes
2015-12-03 10:39:12 -08:00
Jonathan Wong
112811f3e2 Fix subject UTF-8 encode for Prowl notifier 2015-12-02 19:18:04 -08:00
Jonathan Wong
ede07595c3 Match newline characters in notification text 2015-12-02 19:15:46 -08:00
JonnyWong16
08d65623dd Merge pull request #306 from JonnyWong16/miscellaneous-fixes
Delete users
2015-12-02 17:05:39 -08:00
Jonathan Wong
7540b5fb34 Fix recently added notification delay 2015-12-01 22:54:58 -08:00
Jonathan Wong
10c54c2d10 Only show IPv4 addresses 2015-12-01 21:57:02 -08:00
Jonathan Wong
b8d9c8cc47 Set blank metadata so recently added check continues when and item isn't found 2015-12-01 21:50:47 -08:00
Jonathan Wong
bac5018b27 Add channel support to Telegram notifier 2015-12-01 21:31:48 -08:00
Jonathan Wong
c65d9898c8 Add icon for Apple tvOS 2015-12-01 20:05:37 -08:00
Jonathan Wong
d7284c40bd Allow unicode in notification subject and body 2015-12-01 20:03:25 -08:00
Jonathan Wong
1c00f82097 Add ability to delete users 2015-11-27 21:13:17 -08:00
Jonathan Wong
c501923f2b Hide Pushalot notifier response logging 2015-11-27 18:13:20 -08:00
Jonathan Wong
81b22a8c36 Merge branch 'dev' 2015-11-27 06:38:31 -08:00
Jonathan Wong
beb66396fe v1.2.7 2015-11-27 06:33:03 -08:00
Jonathan Wong
aaf3de68cf Fix IP address in notifications 2015-11-27 06:29:41 -08:00
Jonathan Wong
c827c9e825 Fix IP logging again
* Really this time...
2015-11-27 12:33:34 +02:00
Tim van der Westhuizen
5100fdbc96 Merge branch 'dev' 2015-11-27 10:53:28 +02:00
Tim van der Westhuizen
fae3f38a88 v1.2.6 2015-11-27 10:52:29 +02:00
Tim van der Westhuizen
a8236222fb Catch null ratingKeys in plexWatch db importer.
Make sure we have a string when parsing the latinToAscii function.
2015-11-27 10:45:25 +02:00
Jonathan Wong
2be4d9b6c9 Merge branch 'dev' 2015-11-26 19:08:46 -08:00
Jonathan Wong
00934b04d2 Fix IP logging again
* Really this time...
2015-11-26 19:06:51 -08:00
Jonathan Wong
1e28b22c70 Merge branch 'dev' 2015-11-25 20:23:44 -08:00
Jonathan Wong
776061605f Fix IP logging again 2015-11-25 20:20:06 -08:00
Jonathan Wong
683e5663e1 Merge branch 'dev' 2015-11-25 19:16:50 -08:00
Jonathan Wong
090011c9a5 v1.2.5 2015-11-25 19:15:40 -08:00
Jonathan Wong
30b11bce98 Actually add video and audio decision to notifications 2015-11-25 19:13:08 -08:00
Jonathan Wong
2a91ec1560 Fix season and episode number notification option return at least one digit 2015-11-25 19:07:23 -08:00
Jonathan Wong
908ce1ff8d Fix IP address logging 2015-11-25 19:02:59 -08:00
Jonathan Wong
fac47ee68b Fix log spam if notifications turned off 2015-11-25 18:14:08 -08:00
Jonathan Wong
0f8c122ee3 Add video and audio decision to notification options 2015-11-25 18:12:20 -08:00
Jonathan Wong
893c91a15d Merge branch 'dev' 2015-11-24 18:51:35 -08:00
Jonathan Wong
6d152cf308 v1.2.4 2015-11-24 18:49:35 -08:00
Jonathan Wong
af2d0446da Hide fix metadata button for now 2015-11-24 18:21:59 -08:00
Jonathan Wong
244b03ba3e No restart required for monitoring remote access 2015-11-23 23:10:49 -08:00
Jonathan Wong
50e0629890 Fix unicode server name 2015-11-23 23:10:31 -08:00
Jonathan Wong
c296b38b78 Fix text glitch on welcome wizard 2015-11-23 23:10:16 -08:00
Jonathan Wong
f7cdfd3f30 Upgrade config file from previous versions 2015-11-23 23:10:01 -08:00
drzoidberg33
44cb2400d0 Remove donate link 2015-11-23 10:56:44 +02:00
Jonathan Wong
d297597fa6 Separate out movie and tv logging 2015-11-22 22:19:37 -08:00
Jonathan Wong
168e74aa23 Add logger for recently added 2015-11-22 22:15:28 -08:00
Jonathan Wong
35fa8a749b Fix PMS IP error message 2015-11-22 12:28:24 -08:00
Jonathan Wong
21a1870884 Fix callback in wrong spot 2015-11-22 12:24:57 -08:00
Jonathan Wong
1d86187f79 Fix "Please verify your server" setting bug 2015-11-22 12:11:22 -08:00
JonnyWong16
558f7873f5 Merge pull request #289 from JonnyWong16/miscellaneous-fixes
Use Plex API to check remote access down
2015-11-22 10:33:30 -08:00
Jonathan Wong
a20a52f5f1 Refresh port mapping before checking remote access 2015-11-22 10:22:15 -08:00
Jonathan Wong
17bb57d5f5 Apply media type toggles to recently added 2015-11-21 10:28:26 -08:00
Jonathan Wong
e6aef01508 Separate out TV notification toggle in settings 2015-11-21 10:27:51 -08:00
Jonathan Wong
013d957e47 Use Plex API to check remote access down 2015-11-21 10:13:26 -08:00
Jonathan Wong
99e064e040 Add wording for Pushover group key 2015-11-20 19:04:54 -08:00
JonnyWong16
9e5334ac81 Merge pull request #282 from JonnyWong16/miscellaneous-fixes
IPv6 support, fix recently added, get server name, notify server down
2015-11-20 06:28:02 -08:00
Jonathan Wong
fd43cf5dd4 Add setting to enable remote access monitoring 2015-11-19 19:40:50 -08:00
Jonathan Wong
9aea663754 Logger info for email notification sent 2015-11-17 23:39:02 -08:00
Jonathan Wong
223e2b2b32 Add notification for Plex external port down 2015-11-17 23:38:46 -08:00
Jonathan Wong
ca91adbd53 Add check for Plex external port down 2015-11-17 23:35:41 -08:00
Jonathan Wong
4fffbf8a0c Add server uptime 2015-11-17 19:31:13 -08:00
Jonathan Wong
c3ea35806e Move check for server down to check_active_sessions 2015-11-17 06:57:02 -08:00
Jonathan Wong
1c4df69e61 Toggle bell icon for on_down 2015-11-16 23:52:03 -08:00
Jonathan Wong
707c30b0af Fix missing pmsconnect 2015-11-16 23:28:43 -08:00
Jonathan Wong
4d87666a42 Schedule job to check if server down 2015-11-16 23:19:59 -08:00
Jonathan Wong
b28ac1543a Add notification for server down 2015-11-16 23:19:37 -08:00
Jonathan Wong
1983597cf1 Fix get_server_friendly_name 2015-11-16 22:51:21 -08:00
Jonathan Wong
69a3b5134f Switch recently added to only use activity pinger
* Fixed activity pinger logic for grouping notifications
2015-11-16 21:19:04 -08:00
Jonathan Wong
53044c75dd Add setting for recently added notification delay 2015-11-16 21:17:47 -08:00
Jonathan Wong
12056ac2ba Get server name as a scheduled task 2015-11-16 18:31:22 -08:00
Jonathan Wong
7c8fb58600 Change input to textarea for notification body 2015-11-15 23:51:31 -08:00
Jonathan Wong
da2e7635bd Fix notification tags removal for show and artist 2015-11-15 23:50:58 -08:00
Jonathan Wong
f8b75eadc6 Improved get server friendly name
* Add server friendly name to page title
2015-11-15 21:35:53 -08:00
Jonathan Wong
e9bc767c3b Fix username for database queries
* Get the updated username from the users table instead of the one
stored in the session_history table.
2015-11-15 20:59:04 -08:00
Jonathan Wong
1644bbd4b7 Check for IPv4 mapped IPv6 address in PMS logs 2015-11-15 10:26:03 -08:00
Jonathan Wong
18b328a387 Fix private IP address for IPv6 2015-11-15 10:17:28 -08:00
Tim van der Westhuizen
98411f0715 Move IP geolocation service. Temporary until a suitable replacement can be found. 2015-11-13 17:51:25 +02:00
JonnyWong16
fcb3474312 Merge pull request #278 from JonnyWong16/miscellaneous-fixes
Add IP address to current activity
2015-11-12 06:13:08 -08:00
Jonathan Wong
6362b51902 Add ip_address to notification options
* Also track_name
2015-11-11 14:48:59 -08:00
Jonathan Wong
d79d5d5b39 Better IP address handling for current activity 2015-11-11 09:16:28 -08:00
Jonathan Wong
80df8f6191 Add IP address to sessions for PMS 0.9.14 2015-11-11 08:59:55 -08:00
Jonathan Wong
fd9cf7017b Add IP address to current activity 2015-11-10 19:28:14 -08:00
JonnyWong16
2eed2d54ca Merge pull request #274 from JonnyWong16/miscellaneous-fixes
Add more metadata options to notifications
2015-11-09 19:16:08 -08:00
Jonathan Wong
0c33e7492a Open notifier description links in new window 2015-11-09 17:55:37 -08:00
Jonathan Wong
dd137e5c36 Minor notifier text changes 2015-11-08 15:44:59 -08:00
Jonathan Wong
dea9663adf Add more metadata options to notifications 2015-11-08 15:38:30 -08:00
Tim van der Westhuizen
767dd20bdc Make sure we set the PMS client identifier when auto verifying servers at first run. 2015-11-06 17:18:22 +02:00
Tim
c350943041 Add some debug logging for websocket timeline events. 2015-11-05 22:49:05 +02:00
drzoidberg33
c60340d88b Merge pull request #269 from JonnyWong16/miscellaneous-fixes
Miscellaneous fixes
2015-11-02 23:17:41 +02:00
drzoidberg33
276c0e5c7d Merge pull request #267 from onedr0p/feature/telegram_notifications
Feature/telegram notifications
2015-11-02 23:11:55 +02:00
Jonathan Wong
054f116017 Fix title encode for Pushover notifications 2015-11-01 20:38:22 -08:00
Jonathan Wong
e9017a8342 Escape double quotes in search query 2015-11-01 20:37:28 -08:00
Devin Buhl
9cff20ca16 set text format on encode 2015-11-01 11:03:36 -05:00
Devin Buhl
6cbfacaeae added event / suject to notifcation text 2015-10-31 01:59:13 -04:00
devin
8ebfa20db0 Fixed notifications, and added strings to describe bot token and chat id 2015-10-28 20:36:09 -04:00
devin
5beb4876fb removed telegram lib, updated wording, and used a simple request for sending the notif 2015-10-28 20:28:41 -04:00
devin
c723d33d38 telegram updates to notifiers.py 2015-10-28 07:31:07 -04:00
devin
f75fca12c8 telegram updates to config.py 2015-10-28 07:30:41 -04:00
devin
8671707e4d added telegram lib from repo leandrotoledo/python-telegram-bot 2015-10-28 07:29:57 -04:00
drzoidberg33
a9316ebea1 Merge pull request #265 from drzoidberg33/ip-lookup-provider
Change IP lookup provider
2015-10-28 13:06:35 +02:00
Tim van der Westhuizen
ef86740466 Change order of location details in IP lookup. 2015-10-27 15:25:40 +02:00
Tim van der Westhuizen
57cb755668 Change IP lookup provider to Telize.com which supply an SSL endpoint. 2015-10-27 13:53:47 +02:00
JonnyWong16
aa75cf2b73 Merge pull request #259 from JonnyWong16/recently-added
Recently added
2015-10-26 18:04:11 -07:00
Jonathan Wong
3f8224fec5 List notifications agents alphabetically 2015-10-26 18:00:51 -07:00
Jonathan Wong
0b67abb2a2 Fix typos 2015-10-26 17:52:51 -07:00
Jonathan Wong
872ef2771e Fix double recently added episode notifications 2015-10-25 22:00:51 -07:00
Jonathan Wong
3b457304e9 Fix build_notify_text again
* Separate session and timeline
2015-10-25 21:12:19 -07:00
Jonathan Wong
974c672a87 Format code 2015-10-25 17:38:41 -07:00
Jonathan Wong
b9f47df930 Update activity_pinger for recently added 2015-10-25 17:21:49 -07:00
Jonathan Wong
4c388f60d6 Add config to group recently added by grandparent 2015-10-25 13:30:25 -07:00
Jonathan Wong
d6b31dc542 Set on_created notification in database 2015-10-25 12:20:00 -07:00
Jonathan Wong
539cd60e92 Fix notification_handler 2015-10-24 21:23:19 -07:00
Jonathan Wong
056bcd1488 Update notification handler for timeline events 2015-10-24 21:23:03 -07:00
Jonathan Wong
1c58a47073 Update websocket and handler for timeline events 2015-10-24 21:22:46 -07:00
Jonathan Wong
32cf1ada8b Add config settings for on_created
* Note: on_created is recently added
2015-10-24 21:22:29 -07:00
Jonathan Wong
968132099e Change metadata 'type' to 'media_type' 2015-10-24 21:18:09 -07:00
Tim van der Westhuizen
7b3874dcaa Add Plex Media Player icon. 2015-10-23 11:37:13 +02:00
Tim van der Westhuizen
0302b2412a Fix platform overrides for graphs. 2015-10-22 18:12:50 +02:00
Tim van der Westhuizen
4ac5329019 Add Konvergo to platform name overrides. 2015-10-22 17:45:23 +02:00
Tim van der Westhuizen
37bc68573c Implement IFTTT notification option. PR #241. 2015-10-22 16:04:31 +02:00
Tim
dc8996c4d2 Escape single quotes for usernames on user stats page. 2015-10-21 22:06:02 +02:00
drzoidberg33
1ef9d72534 Merge pull request #256 from JonnyWong16/miscellaneous-fixes
Miscellaneous fixes
2015-10-20 13:15:49 +02:00
Jonathan Wong
db7225fbad Clean up code 2015-10-20 00:48:26 -07:00
Jonathan Wong
2c354ad783 Fix bug in search query 2015-10-18 17:47:21 -07:00
Jonathan Wong
b96abc8853 Add detailed logger messages for database queries 2015-10-18 13:53:23 -07:00
Jonathan Wong
c4dc81e8fb Change order args are created for datatable query
* Make sure search filter args are created after custom_where
2015-10-18 13:29:29 -07:00
Jonathan Wong
be753983fe Fix breadcrumbs for update metadata page 2015-10-18 13:14:22 -07:00
Jonathan Wong
1bcb34d7eb Add button to fix metadata on info pages 2015-10-18 13:02:16 -07:00
Jonathan Wong
2243cd1de9 Add filtering of media_type from history table 2015-10-18 11:50:01 -07:00
Jonathan Wong
1ff58a85dc Fix bug in "Last Watched" statistics
*Fix if two users watched the same item, it would only show the most
recent user.
2015-10-18 10:27:18 -07:00
Tim
428706d9a7 Merge branch 'dev' 2015-10-18 00:27:41 +02:00
Tim
5967636ef9 v1.2.3 2015-10-18 00:26:44 +02:00
drzoidberg33
ddc9563de9 Merge pull request #252 from JonnyWong16/miscellaneous-fixes
Miscellaneous fixes
2015-10-16 16:40:23 +02:00
Jonathan Wong
3d1a1b5e45 Fix watch stats not showing on homepage 2015-10-15 18:02:28 -07:00
Jonathan Wong
60b330573e Increase width of user watch time stats 2015-10-13 20:59:24 -07:00
Jonathan Wong
76c1558473 Add {remaining_duration} to notifications
* Also clean up/reorder notification parameters
2015-10-13 20:42:26 -07:00
Tim
5fe47d797f v1.2.2 2015-10-12 20:22:39 +02:00
Tim
dd5ba05c88 v1.2.1 2015-10-12 20:19:58 +02:00
drzoidberg33
26d825dc09 Merge pull request #239 from JonnyWong16/miscellaneous-fixes
Notification agent sounds
2015-10-12 12:01:20 +02:00
Jonathan Wong
3299ec7c82 Clean up Pushover sound code 2015-10-12 00:54:26 -07:00
Jonathan Wong
c25c48c1a6 Add watched percent to history table tooltip 2015-10-12 00:28:05 -07:00
Jonathan Wong
2680162b67 Add dropdown for Boxcar sounds 2015-10-11 23:48:12 -07:00
Jonathan Wong
7d3d2957c3 Add dropdown for Pushover sounds 2015-10-11 23:45:58 -07:00
Jonathan Wong
c12862ffba Add select dropdown to notification agents
* Change priority selections to dropdown
2015-10-11 22:36:00 -07:00
Jonathan Wong
9968f8b6dd Clean up home_stats code 2015-10-11 17:58:17 -07:00
Jonathan Wong
2ea6ae648c Order sync table by State > User > Title 2015-10-11 17:58:02 -07:00
drzoidberg33
75f6ed3fc1 Merge pull request #228 from BrianInAz/pushover-sounds
Added ability to set custom notification sound for Pushover
2015-10-07 20:47:20 +02:00
drzoidberg33
39c5156d08 Merge pull request #217 from Hellowlol/patch-1
If we fail to parse a response, log the uri
2015-10-07 20:46:04 +02:00
drzoidberg33
2f2069e0ad Merge pull request #213 from Hellowlol/gdp
Good day plex!
2015-10-07 20:45:27 +02:00
drzoidberg33
be4e8985b7 Merge pull request #200 from Hellowlol/apistuff
initial api changes
2015-10-07 20:32:31 +02:00
John
3e344ce56c fix typo 2015-10-04 20:38:37 +02:00
Brian Charbonneau
ca4e6cde3e Fixed indent. Replaced tabs with spaces 2015-10-03 23:34:33 -07:00
Brian Charbonneau
1ad982f5b7 Removed newlines 2015-10-03 23:25:57 -07:00
Brian Charbonneau
280a5ae744 Added ability to set custom notification sound for Pushover 2015-10-03 22:05:27 -07:00
Hellowlol
b1e27d9bc2 If we fail to parse a response, log the uri
and the original response
2015-10-02 20:34:47 +02:00
John
92bbf8e994 select needs name to serialize 2015-10-01 20:51:52 +02:00
drzoidberg33
cf49f4d6bf Merge pull request #220 from JonnyWong16/miscellaneous-fixes
Player in tables and top level info pages
2015-10-01 20:15:50 +02:00
Jonathan Wong
721bd606cb Change info navbar to use bootstrap breadcrumb 2015-09-30 00:00:21 -07:00
Jonathan Wong
61865ace64 Add link to top level info page from library statistics 2015-09-29 23:34:03 -07:00
Jonathan Wong
5b88058133 Add top level info pages with history table
* Movies / TV Shows / Music
2015-09-29 23:23:03 -07:00
Jonathan Wong
2616e14c83 Add "player" to tables
* Also rename user platforms to user players
* Fix other platform vs. player ambiguities
2015-09-29 22:43:23 -07:00
Jonathan Wong
f1c4bf6249 Fix current activity details for tracks 2015-09-29 20:43:08 -07:00
Jonathan Wong
e884d018ed Fix indents 2015-09-29 15:52:10 -07:00
John
9d925cce03 add getSync, fix named argument 2015-09-29 23:27:19 +02:00
John
ff8d9f9f4c fix parsing of servers, remove unbound var 2015-09-29 23:16:34 +02:00
Tim
c65d8a1ec6 Merge branch 'dev' 2015-09-29 22:32:16 +02:00
Tim
2346033871 v1.2.1 2015-09-29 22:31:17 +02:00
Tim
6103d14a6f Fix for null paused_counter issue. 2015-09-29 22:27:39 +02:00
John
f7bffdc050 Add stuff to api
getLog finished
2015-09-28 23:07:45 +02:00
John
37df262b24 Good day plex! 2015-09-28 23:00:06 +02:00
1568 changed files with 94488 additions and 93389 deletions

7
.gitignore vendored
View File

@@ -15,12 +15,17 @@
version.lock
logs/*
cache/*
*.mmdb
# HTTPS Cert/Key #
##################
*.crt
*.key
*.csr
*.pem
# Mergetool
*.orgin
# OS generated files #
######################
@@ -31,7 +36,7 @@ Icon?
Thumbs.db
#Ignore files generated by PyCharm
.idea/*
*.idea/*
#Ignore files generated by vi
*.swp

1929
API.md

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,652 @@
# Changelog
## v1.4.23 (2017-09-30)
* Fix: Playstation 4 platform name.
* Fix: PlexWatch and Plexivity import.
* Fix: Pushbullet authorization header.
## v1.4.22 (2017-08-19)
* Fix: Cleaning up of old config backups.
* Fix: Temporary fix for incorrect source media info.
## v1.4.21 (2017-07-01)
* New: Updated donation methods.
## v1.4.20 (2017-06-24)
* New: Added platform image for the PlexTogether player.
* Fix: Corrected math used to calculate human duration. (Thanks @senepa)
* Fix: Sorting of 4k in media info tables.
* Fix: Update file sizes when refreshing media info tables.
* Fix: Support a custom port for Mattermost (Slack) notifications.
## v1.4.19 (2017-05-31)
* Fix: Video resolution not showing up for transcoded streams on PMS 1.7.x.
## v1.4.18 (2017-04-22)
* New: Added some new Arnold quotes. (Thanks @senepa)
* Fix: Text wrapping in datatable footers.
* Fix: API command get_apikey. (Thanks @Hellowlol)
## v1.4.17 (2017-03-04)
* New: Configurable month range for the Plays by month graph. (Thanks @Pbaboe)
* New: Option to chanage the week to start on Monday for the the Plays by day of week graph. (Thanks @Pbaboe)
* Fix: Invalid iOS icon file paths. (Thanks @demonbane)
* Fix: Plex Web 3.0 URLs on info pages and notifications.
* Fix: Update bitcoin donation link to Coinbase.
* Fix: Update init scripts. (Thanks @ampsonic)
## v1.4.16 (2016-11-25)
* Fix: Websocket for new json response on PMS 1.3.0.
* Fix: Update stream and transcoder tooltip percent.
* Fix: Typo in the edit user modal.
## v1.4.15 (2016-11-11)
* New: Add stream and transcoder progress percent to the current activity tooltip.
* Fix: Refreshing of images in the cache when authentication is disabled.
* Fix: Plex.tv authentication with special characters in the username or password.
* Fix: Line breaks in the info page summaries.
* Fix: Redirect to the proper http root when restarting.
* Fix: API result type and responses showing incorrectly. (Thanks @Hellowlol)
* Change: Use https URL for app.plex.tv.
* Change: Show API traceback errors in the browser with debugging enabled. (Thanks @Hellowlol)
* Change: Increase table width on mobile devices and max width set to 1750px. (Thanks @XusBadia)
## v1.4.14 (2016-10-12)
* Fix: History logging locking up if media is removed from Plex before PlexPy can save the session.
* Fix: Unable to save API key in the settings.
* Fix: Some typos in the settings. (Thanks @Leafar3456)
* Change: Disable script timeout by setting timeout to 0 seconds.
## v1.4.13 (2016-10-08)
* New: Option to set the number of days to keep PlexPy backups.
* New: Option to add a supplementary url to Pushover notifications.
* New: Option to set a timeout duration for script notifications.
* New: Added flush temporary sessions button to extra settings for emergency use.
* New: Added pms_image_proxy to the API.
* Fix: Insanely long play durations being recorded when connection to the Plex server is lost.
* Fix: Script notification output not being sent to the logger.
* Fix: New libraries not being added to homepage automatically.
* Fix: Success message shown incorrectly when sending a test notification.
* Fix: PlexPy log level filter not working.
* Fix: Admin username not shown in login logs.
* Fix: FeatHub link in readme document.
* Change: Posters disabled by default for all notification agents.
* Change: Disable manual changing of the PlexPy API key.
* Change: Force refresh the Plex.tv token when fetching a new token.
* Change: Script notifications run in a new thread with the timeout setting.
* Change: Watched percent moved to general settings.
* Change: Use human readable file sizes to the media info tables. (Thanks @logaritmisk)
* Change: Update pytz library.
## v1.4.12 (2016-09-18)
* Fix: PMS update check not working for MacOSX.
* Fix: Square covers for music stats on homepage.
* Fix: Card width on the homepage for iPhone 6/7 Plus. (Thanks @XusBadia)
* Fix: Check for running PID when starting PlexPy. (Thanks @spolyack)
* Fix: FreeBSD service script not stopping PlexPy properly.
* Fix: Some web UI cleanup.
* Change: GitHub repostitory moved.
## v1.4.11 (2016-09-02)
* Fix: PlexWatch and Plexivity import errors.
* Fix: Searching in history datatables.
* Fix: Notifications not sending for Local user.
## v1.4.10 (2016-08-15)
* Fix: Missing python ipaddress module preventing PlexPy from starting.
## v1.4.9 (2016-08-14)
* New: Option to include current activity in the history tables.
* New: ISP lookup info in the IP address modal.
* New: Option to disable web page previews for Telegram notifications.
* Fix: Send correct JSON header for Slack/Mattermost notifications.
* Fix: Twitter and Facebook test notifications incorrectly showing as "failed".
* Fix: Current activity progress bars extending past 100%.
* Fix: Typo in the setup wizard. (Thanks @wopian)
* Fix: Update PMS server version before checking for a new update.
* Change: Compare distro and build when checking for server updates.
* Change: Nicer y-axis intervals when viewing "Play Duration" graphs.
## v1.4.8 (2016-07-16)
* New: Setting to specify PlexPy backup interval.
* Fix: User Concurrent Streams Notifications by IP Address checkbox not working.
* Fix: Substitute {update_version} in fallback PMS update notification text.
* Fix: Check version for automatic IP logging setting.
* Fix: Use library refresh interval.
## v1.4.7 (2016-07-14)
* New: Use MaxMind GeoLite2 for IP address lookup.
* Note: The GeoLite2 database must be installed from the settings page.
* New: Check for Plex updates using plex.tv downloads instead of the server API.
* Note: Check for Plex updates has been disabled and must be re-enabled in the settings.
* New: More notification options for Plex updates.
* New: Notifications for concurrent streams by a single user.
* New: Notifications for user streaming from a new device.
* New: HipChat notification agent. (Thanks @aboron)
* Fix: Username showing as blank when friendly name is blank.
* Fix: Direct stream count wrong in the current activity header.
* Fix: Current activity reporting direct stream when reducing the stream quality switches to transcoding.
* Fix: Apostophe in an Arnold quote causing the shutdown/restart page to crash.
* Fix: Disable refreshing posters in guest mode.
* Fix: PlexWatch/Plexivity import unable to select the "grouped" database table.
* Change: Updated Facebook notification instructions.
* Change: Subject line optional for Join notifications.
* Change: Line break between subject and body text instead of a colon for Facebook, Slack, Twitter, and Telegram.
* Change: Allow Mattermost notifications using the Slack config.
* Change: Better formatting for Slack poster notifications.
* Change: Telegram only notifies once instead of twice when posters are enabled.
* Change: Host Open Sans font locally instead of querying Google Fonts.
## v1.4.6 (2016-06-11)
* New: Added User and Library statistics to the API.
* New: Ability to refresh individual poster images without clearing the entire cache. (Thanks @Hellowlol)
* New: Added {added_date}, {updated_date}, and {last_viewed_date} to metadata notification options.
* New: Log level filter for Plex logs. (Thanks @sanderploegsma)
* New: Log level filter for PlexPy logs.
* New: Button to download Plex logs directly from the web interface.
* New: Advanced setting in the config file to change the number of Plex log lines retrieved.
* Fix: FreeBSD and FreeNAS init scripts to reflect the path in the installation guide. (Thanks @nortron)
* Fix: Monitoring crashing when failed to retrieve current activity.
## v1.4.5 (2016-05-25)
* Fix: PlexPy unable to start if failed to get shared libraries for a user.
* Fix: Matching port number when retrieving the PMS url.
* Fix: Extract mapped IPv4 address in Plexivity import.
* Change: Revert back to internal url when retrieving PMS images.
## v1.4.4 (2016-05-24)
* Fix: Image queries crashing the PMS when playing clips from channels.
* Fix: Plexivity import if IP address is missing.
* Fix: Tooltips shown behind the datatable headers.
* Fix: Current activity instances rendered in a random order causing them to jump around.
## v1.4.3 (2016-05-22)
* Fix: PlexPy not starting without any authentication method.
## v1.4.2 (2016-05-22)
* New: Option to use HTTP basic authentication instead of the HTML login form.
* Fix: Unable to save settings when enabling the HTTP proxy setting.
* Change: Match the PMS port when retrieving the PMS url.
## v1.4.1 (2016-05-20)
* New: HTTP Proxy checkbox in the settings. Enable this if using an SSL enabled reverse proxy in front of PlexPy.
* Fix: Check for blank username/password on login.
* Fix: Persist current activity artwork blur across refreshes when transcoding details are visible.
* Fix: Send notifications to multiple XBMC/Plex Home Theater devices.
* Fix: Reset PMS identifier when clicking verify server button in settings.
* Fix: Crash when trying to group current activity session in database.
* Fix: Check current activity returns sessions when refreshing.
* Fix: Logs sorted out of order.
* Fix: Resolution reported incorrectly in the stream info modal.
* Fix: PlexPy crashing when hashing password in the config file.
* Fix: CherryPy doubling the port number when accessing PlexPy locally with http_proxy enabled.
* Change: Sort by most recent for ties in watch statistics.
* Change: Refresh Join devices when changing the API key.
* Change: Format the Join device IDs.
* Change: Join notifications now sent with Python Requests module.
* Change: Add paging for recently added in the API.
## v1.4.0 (2016-05-15)
* New: An HTML form login page with sessions support.
* New: Guest access control for shared users using Plex.tv authentication.
* Enable the option in the settings and toggle guest access per user from Users > Edit mode.
* Guests can only view their own user data. Other user info is removed/masked.
* Guests can only view media from libraries that are shared with them (content rating and label filters are respected). Other libraries are removed/masked.
* All settings and admin controls are restricted from guests.
* All current activity on the server is shown, but with masked user/metadata info.
* New: Login logs table on the User and Logs pages.
* New: Filter the history table by user.
* New: Filter the graphs by user. (Thanks @Otger)
* New: Option to hash the admin passowrd in the config file.
* New: Options to enable/disable/rearrange each section on the homepage
* New: Toggle media types for recently added items on the homepage.
* New: Option to enter an Imgur API client ID for uploading posters.
* Note: The shared Imgur client id will be removed in a future PlexPy update! Please enter your own client id in the settings to continue uploading posters!
* New: HTML support for Email.
* New: Posters and HTML support for Telegram.
* New: Poster support for Slack.
* New: Poster support for Twitter.
* New: Re-added Plex Home Theater notification agent.
* New: Browser notification agent (experimental).
* New: Added {plex_url} as a notification option.
* New: Added transcode decision to the activity header.
* New: Documentation for APIv2 (see API.md for details).
* New: Import a Plexivity database into PlexPy.
* New: Prettier fallback image for art/episodes.
* New: Prettier confirm modal dialogues.
* New: Cache images to reduce Plex API calls. This can be disabled in the under Settings > Extra Settings. (Thanks @Hellowlol)
* New: Scheduled backups of the config file.
* New: Button to clear the PlexPy cache/images in the settings.
* New: Button to manually backup the PlexPy database/config in the settings.
* New: Button to clear the PlexPy logs in the settings.
* New: Button to download PlexPy log file on the Logs tab.
* New: Advanced setting in config file to change the Plex API timeout value.
* Fix: Mixed content HTTP request in settings (for reverse proxies with SSL).
* Fix: Rename recently "watched" music to "played".
* Change: Current activity details now persists across refreshes.
* Change: Smoother transitions between preview thumbnails in current activity.
* Change: Datatables now display all columns and scroll horizontally on smaller screens.
* Change: Ability to change the base URL for reverse proxies in the web interface.
* Change: Added a "Verify Server" button in the settings.
* Change: Added request status code in the logs for notifer errors.
* Change: Remove in-memory logs and read lines from log file instead. (Thanks @Hellowlol)
* Change: Limit number of failed attempts to write sessions to history. Default is 5 attempts.
* Change: A bunch of UI updates.
* Change: A bunch of backend code cleanup.
* Removed: All unused Python packages.
## v1.3.16 (2016-05-01)
* Fix: Viewing photos crashing PlexPy.
* Fix: Persist Users > Edit mode on datatable page change.
* Fix: PMS update notifications broken.
* Change: Cache notifications poster with thread ID to avoid overwritting images.
## v1.3.15 (2016-04-18)
* Fix: Slack notifications failing when using and icon URL.
* Fix: 127.0.0.1 showing as an external IP address on the history tables.
* Fix: Regression file sizes not shown in the media info table footer.
* Fix: Retrieving proper PMS URL when multiple connections are published to plex.tv.
* Fix: Some typos in the logger.
* Fix: Some other typos in the WebUI. (Thanks @xtjoeytx)
* Change: Optimized mobile web app icons and spash screens. (Thanks @alotufo)
## v1.3.14 (2016-03-29)
* Fix: Regression for missing notify_action for script notifications.
* Fix: Typo for home stats cards in the settings.
## v1.3.13 (2016-03-27)
* Fix: Only mask strings longer than 5 characters in logs.
## v1.3.12 (2016-03-27)
* Fix: "Check GitHub for updates" not rescheduling when toggling setting.
* Fix: Bug where notifications would fail if metadata is not found.
* Fix: Bug where notifications would fail if unable to upload poster to Imgur.
* Fix: PlexPy will now start properly for different Python environment variables.
* New: Feature requests moved to FeatHub.
* New: Ability to specify a GitHub API token for updates (optional).
* New: Mask out sensitive information from the logs.
* New: New and updated Arnold quotes. (Thanks @Vilsol & @Chrisophogus)
* New: "First" and "Last" page buttons to datatables.
* New: Access log file from the "Help & Info" page.
* New: CherryPy environment options (for development). (Thanks @codedecay)
* New: PlexPy development environment (for development only).
* Change: Facebook posts with a posters now include a summary.
* Change: Facebook posts now use a default poster if the poster is not found or unable to upload to Imgur.
* Change: IFTTT events can be fromatted with the {action} name.
* Change: Logs now use ISO date format to avoid locale encoding errors. (Thanks @alshain)
* Remove: Non-functioning Plex notification agent.
## v1.3.11 (2016-03-15)
* Fix: Typo preventing history logging for websockets.
## v1.3.10 (2016-03-12)
* Fix: Actually allow HTML tags for Pushover.
* Fix: PlexPy not restarting on Windows if there is a space in the folder path.
* Fix: Reconnect websocket when changing PMS SSL setting.
* Fix: Datatables not loading when view_offset or duration is blank.
* Fix: Bug when checking the PMS version in the settings.
* Fix: Auto-refreshing of log tables.
* Fix: Logging of IPv6 addresses. (PMS version >0.9.14 only.)
* Fix: Hide days selection from the Play Totals graph page.
* Fix: PlexPy overwriting user's own SSL certificate/key.
* Fix: Multiple watched notifications when using websocket.
* Fix: Some missing python library imports.
* Fix: Some typos in settings and PlexWatch importer.
* New: Ability to get notified of PMS updates.
* New: Ability to disable the link to Plex Web with Facebook notifications and use IMDB, TVDB, TMDb, or Last.fm instead.
* New: Ability to reset Imgur poster url from the info page if the poster is changed.
* New: Tooltips on the current activity progress bars.
* New: Side scrolling of Recently Added/Recently Played items.
* New: Document all date/time format options.
* New: Button to clear notification logs.
* New: Customizable backup, cache, and log directories.
* Change: Retry writing sessions to history if it fails, so sessions don't get lost. (Activity pinger only, not availble for websocket.)
* Change: Save any unknown sessions to the "Local" user.
* Change: History table modal is filtered depending on which graph series is clicked.
* Change: Revert back to saving the state of datatables (search, sorting, entries per page, etc.).
* Change: Newlines are not longer stripped from notification text which allows for finer control of how notifications look.
* Change: Updated FreeNAS/FreeBSD init scripts. (Must have updated jails.) (Thanks @chiviak)
## v1.3.9 (2016-02-21)
* Fix: Recently added notification not sent to all notification agents.
* New: Pushover HTML support. (Thanks @elseym)
## v1.3.8 (2016-02-21)
* Fix: Regression unable to clear HTTP password.
* Fix: Remove media tags from script arguments for server notifications.
* Fix: Encode poster titles to UTF-8 for Imgur upload.
* Fix: Allow notifications to send without poster if Imgur upload fails.
* New: Notification Logs table in the Logs tab.
* New: Toggle in settings to enable posters in notifications. (Disabled by default.)
* Change: Save Imgur poster URL to database so upload is not needed every time.
* Change: Notify log in database to log each event as a separate entry.
* Change: Monitor remote access is unchecked if remote access is disabled on server.
## v1.3.7 (2016-02-20)
* Fix: Verifying server with SSL enabled.
* Fix: Regression where {stream_duration} reported as 0.
* Fix: Video metadata flags showing up for track info.
* Fix: Custom library icons not applied to Library Statistics.
* Fix: Typos in the Web UI.
* New: ETA to Current Activity overlay.
* New: Total duration to Libraries and Users tables.
* New: {machine_id} to notification options.
* New: IMDB, TVDB, TMDb, Last.fm, and Trackt IDs/URLs to notification options.
* New: {poster_url} to notification options using Imgur.
* New: Poster and link for Facebook notifications.
* New: Log javascript errors from the Web UI.
* New: Configuration and Scheduler info to the settings page.
* New: Schedule background task to backup the PlexPy database.
* New: URL anonymizer for external links.
* New: Plex Media Scanner log file to Log viewer.
* New: API v2 (sill very experimental). (Thanks @Hellowlol)
* Change: Allow secure websocket connections.
* Change: History grouping now accounts for the view offset.
* Change: Subject line can be toggled off for Facebook, Slack, Telegram, and Twitter.
* Change: Create self-signed SSL certificates when enabling HTTPS.
* Change: Revert homepage "Last Played" to "Last Watched".
* Change: Disable monitor remote access checkbox if remote access is not enabled on the PMS.
* Change: Disable IP logging checkbox if PMS version is 0.9.14 or greater.
## v1.3.6 (2016-02-03)
* Fix: Regression where {duration} not reported in minutes.
* Fix: Proper daemonizing in FreeBSD and FreeNAS init scripts.
* Change: Update readme documentation.
## v1.3.5 (2016-02-02)
* Fix: Removing unique constraints from database.
* Fix: Unable to expand media info table when missing "Added At" date.
* Fix: Server verification for unpublished servers.
* Fix: Updating PMS identifier for server change.
* New: {stream_time}, {remaining_time}, and {progress_time} to notification options.
* New: Powershell script support. (Thanks @Hellowlol)
* New: Method to delete duplicate libraries.
* Change: Daemonize before running start up tasks.
## v1.3.4 (2016-01-29)
* Fix: Activity checker not starting with library update (history not logging).
* Fix: Libraries duplicated in database.
* Fix: Buffer notifications even when disabled when using websockets.
* Fix: Libraries and Users lists not refreshing.
* Fix: Server verification in settings.
* Fix: Empty libraries not added to database.
* New: Unique identifiers to notification options.
* Remove: Requirement of media type toggles for recently added notifications.
* Remove: Built in Twitter key and secret.
* Change: Unnecessary quoting of script arguments.
* Change: Facebook notification instructions.
## v1.3.3 (2016-01-26)
* Fix: Plays by Month graph not loading.
* Change: Disable caching for datatables.
* Change: Improved updating library data in the database again.
## v1.3.2 (2016-01-24)
* Fix: 'datestamp' and 'timestamp' for server notifications.
* Change: New method for updating library data in database.
## v1.3.1 (2016-01-23)
* Fix: Notifiers authorization popups for reverse proxies.
* Fix: Empty brackets in titles on tables.
* Fix: Star rating overlapping text.
* Fix: Unable to startup when library refresh fails.
* Fix: Unable to parse 'datestamp' and 'timestamp' format.
* Change: Rename "Last Watched" to "Last Played".
* Change: More descriptive libraries updating message.
## v1.3.0 (2016-01-23)
* New: Brand new Libraries section.
* New: Lots of new library statistics.
* New: Media info table for libraries.
* New: Web app for Android and iOS. (Thanks @zobe123)
* New: Slack notification agent. (Thanks @richipargo)
* New: Facebook notification agent.
* New: Custom script notification agent. (Thanks @Hellowlol)
* New: Custom "From Name" to email notification agent.
* New: Ability to test notifications / send custom one-off notifications.
* New: 'datestamp' and 'timestamp' notification options.
* New: More concurrent stream statistics.
* New: Media info flags on the info pages.
* New: Ability to fix broken metadata if the item has been moved in Plex.
* New: Ability to rearrange the homepage statistics cards.
* New: CentOS startup script (Thanks @PHoSawyer)
* Fix: Server name blank after first run wizard.
* Fix: Incorrect duration for grouped home stats.
* Fix: Allow SSL when verifying server in settings.
* Fix: Metadata for grouped recently added notifications.
* Fix: Unable to access settings with missing changelog file.
* Fix: Month name localization on play totals graphs.
* Fix: Get new PMS identifier when changing servers.
* Fix: Websocket log spam when there is no active session.
* Fix: Logs and cache folder not created in the data directory.
* Fix: Title links on sync table.
* Fix: Other various minor bugs and graphical glitches.
* Change: Prettier thumbnail popovers on tables.
* Change: Star ratings to use css/font-awesome.
* Change: More detailed logging info to warnings and errors.
* Change: Better PlexPy process restart handling (Thanks @jackwilsdon)
* Change: Massive behind the scenes code cleanup.
* Remove: Built in Pushover API token (User's own API token is now required).
## v1.2.16 (2015-12-22)
* Fix Most Concurrent stream stat for emtpy databases
* Change logs to 50 lines by default
## v1.2.15 (2015-12-20)
* Fix navbar covering current activity on smaller screens.
* Fix metadata for grouped recently added notifications.
* Fix Growl notification agent not working.
* Change graph days selection.
* Change watch statistics to match table history grouping.
* Add automatic discovery of Pushbullet devices.
* Add Most Concurrent Streams watch statistic.
* Add precentage to current activity progress bars.
* Add a bunch of stream details to notification options.
* Add notification for Plex Remote Access/Plex Media Server back up.
* Add CC/BCC and multiple recipients to email notification agent.
* Add total watch time to history table footer.
## v1.2.14 (2015-12-07)
* Fix regression with PlexWatch db importer and buffer warnings.
## v1.2.13 (2015-12-06)
* Fix match newlines between tags in notification text.
* Fix current activity not showing on PMS 0.9.12.
## v1.2.12 (2015-12-06)
* Fix for "too many open files" error.
## v1.2.11 (2015-12-06)
* Fix more regressions (sorry).
## v1.2.10 (2015-12-06)
* Fix broken count graphs regression.
## v1.2.9 (2015-12-06)
* Fix and improve text sanitization.
## v1.2.8 (2015-12-06)
* Fix sanitize player names
* Fix recently added notification delay
* Fix recently added metadata queries
* Fix multiple lines in notification body text
* Fix UTF-8 encoding in Prowl notifications subject line
* Change to only log IPv4 addresses
* Add global toggle for recently added notifcations
* Add feature to delete users
* Add channel support for Telegram notification agent
* Add icon for Apple tvOS
* Add icon for Microsoft Edge
## v1.2.7 (2015-11-27)
* Fix IP address option in notifications
## v1.2.6 (2015-11-27)
* Fixes for IP logging in PMS < 0.9.14.x.
* Fix issue in plexWatch importer when trying to import item with no ratingKey.
## v1.2.5 (2015-11-25)
* Add video_decision and audio_decision to notification options
* Fix IP address logging
* Fix log spam if notifications disabled
## v1.2.4 (2015-11-24)
* Add filtering by media type in the history table
* Add IFTTT notification agent
* Add Telegram notification agent
* Add notifications for recently added media
* Add notifications for server down and remote access down
* Add more metadata to notifications options
* Add IP address to notification options (for PMS 0.9.14 and above)
* Add server uptime to notification options
* Add IP address to current activity
* Add IPv6 address logging
* Add PMS server name to the page title
* Fix bug in "Last Watched" statistic
* Fix bug in search query
* Fix bug on user pages for usernames with single quotes
* Fix name for new Plex Media Center
* Fix Pushover notifications with unicode characters
* Fix bug with showing old usernames in datatables
* Fix bug with "Please verify your server" in settings
* Change IP lookup provider
* Change notifications custom body text to larger text box
* Change movie/tv logging and notifications into individual options
## v1.2.3 (2015-10-18)
* Added "remaining time" as notification substitution.
* Fix bug on home stats cards.
* Fix visual bug on user page.
## v1.2.2 (2015-10-12)
* Add server discovery on first run.
* Add column to tables for Platform.
* Add link to top level breadcrumbs on info pages.
* Add ability to change notification sounds for Pushover and Boxcar.
* Show watched percentage tooltip on progress column in history tables.
* More logging in event an http request fails.
* Code cleanups and other fixes.
* Fix ordering on sync table.
* Fix bug on home stats cards.
* Fix bug on activity pane where music details were not shown.
## v1.2.1 (2015-09-29)
* Fix for possible issue when paused_counter is null.
## v1.2.0 (2015-09-29)
* Added option to group consecutive plays in the history tables.

View File

@@ -1,12 +1,45 @@
# Contributing to PlexPy
## 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.
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. 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.
* Use the search function. Chances are that your problem is already discussed. Do not append to (closed) issues if your problem does not fit the discussion.
* Visit the [Troubleshooting](../../wiki/TroubleShooting) wiki first.
* Use [proper formatting](https://help.github.com/articles/github-flavored-markdown/). Paste your logs in code blocks.
* Close your issue if you resolved it.
##### 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/JonnyWong16/plexpy/wiki) for
[ [Installation] ](https://github.com/JonnyWong16/plexpy/wiki/Installation) and
[ [FAQs] ](https://github.com/JonnyWong16/plexpy/wiki/Frequently-Asked-Questions-(FAQ)).
- For basic questions try asking on [Gitter](https://gitter.im/plexpy/general) 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/JonnyWong16/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
Feature requests are handled on [FeatHub](http://feathub.com/JonnyWong16/plexpy).
1. Search the existing requests to see if your suggestion has already been submitted.
2. If a similar request exists, give it a thumbs up (+1), or add additional comments to the request.
3. If no similar requests exist, you can create a new one. Make sure to provide a clear title to easily identify the feature request.
## Pull Requests
If you think you can contribute code to the PlexPy repository, do not hesitate to submit a pull request.

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/JonnyWong16/plexpy
* 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.
-->

View File

@@ -1,4 +1,11 @@
#!/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 -*-
# This file is part of PlexPy.
#
# PlexPy is free software: you can redistribute it and/or modify
@@ -20,13 +27,14 @@ import sys
# Ensure lib added to path, before any other imports
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 locale
import signal
import time
import plexpy
from plexpy import config, database, logger, web_socket, webstart
# Register signals, such as CTRL + C
signal.signal(signal.SIGINT, plexpy.sig_handler)
@@ -74,11 +82,14 @@ def main():
'-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(
'--dev', action='store_true', help='Start PlexPy 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(
'--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)')
@@ -93,6 +104,10 @@ def main():
logger.initLogger(console=not plexpy.QUIET, log_dir=False,
verbose=plexpy.VERBOSE)
if args.dev:
plexpy.DEV = True
logger.debug(u"PlexPy is running in the dev environment.")
if args.daemon:
if sys.platform == 'win32':
sys.stderr.write(
@@ -107,8 +122,21 @@ def main():
# 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)
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
@@ -133,7 +161,7 @@ def main():
if args.config:
config_file = args.config
else:
config_file = os.path.join(plexpy.DATA_DIR, 'config.ini')
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):
@@ -149,13 +177,26 @@ def main():
'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')
plexpy.DB_FILE = os.path.join(plexpy.DATA_DIR, database.FILENAME)
if plexpy.DAEMON:
plexpy.daemonize()
# Read config and start logging
plexpy.initialize(config_file)
if plexpy.DAEMON:
plexpy.daemonize()
# 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()
# Force the http port if neccessary
if args.port:
@@ -179,30 +220,19 @@ def main():
'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_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)
# 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:
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)

178
README.md
View File

@@ -1,125 +1,85 @@
#PlexPy
# PlexPy
[![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-PlexPy-738bd7.svg?style=flat-square)](https://discord.gg/36ggawe)
[![Gitter](https://img.shields.io/badge/Gitter-PlexPy-ed1965.svg?style=flat-square)](https://gitter.im/plexpy/general)
[![Plex Forums](https://img.shields.io/badge/Plex%20Forums-PlexPy-E5A00D.svg?style=flat-square)](https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program)
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
If you'd like to buy me a beer, hit the donate button below. All donations go to the project maintainer (primarily for the procurement of liquid refreshment).
* Responsive web design viewable on desktop, tablet and mobile web browsers.
* Themed to complement Plex/Web.
* Easy configuration setup (no separate web server required).
* Monitor current Plex Media Server activity.
* Fully customizable notifications for stream activity and recently added media.
* Top statistics on home page with configurable duration and measurement metric.
* Global watching history with search/filtering & dynamic column sorting.
* Full user list with general information and comparison stats.
* Individual user information including devices IP addresses.
* Complete library statistics and media file information.
* Rich analytics presented using Highcharts graphing.
* Beautiful content information pages.
* Full sync list data on all users syncing items from your library.
* And many more!!
[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=G9HZK9BDJLKT6)
## Preview
* [Full preview gallery on Imgur](https://imgur.com/a/RwQPM)
###Support
-----------
* PlexPy Wiki: https://github.com/drzoidberg33/plexpy/wiki
![PlexPy Homepage](https://i.imgur.com/0D0uFJg.jpg)
## Installation and Support
###Features
-----------
* Responsive web design viewable on desktop, tablet and mobile web browsers
* Themed to complement Plex/Web
* Easy configuration setup via html form
* Current Plex Media Server viewing activity including:
* number of current users
* title
* progress
* platform
* user
* state (playing, paused, buffering, etc)
* stream type (direct, transcoded)
* video type & resolution
* audio type & channel count.
* Top statistics on home page with configurable duration and measurement metric:
* Most watched TV
* Most popular TV
* Most watched Movie
* Most popular Movie
* Most active user
* Most active platform
* Recently added media and how long ago it was added
* Global watching history with search/filtering & dynamic column sorting
* date
* user
* platform
* ip address
* title
* stream information details
* start time
* paused duration length
* stop time
* duration length
* watched progress
* show/hide columns
* delete mode - allows deletion of specific history items
* Full user list with general information and comparison stats
* Individual user information
* username and gravatar (if available)
* daily, weekly, monthly, all time stats for play count and duration length
* individual platform stats for each user
* public ip address history with last seen date and geo tag location
* recently watched content
* watching history
* synced items
* assign users custom friendly names within PlexPy
* assign users custom avatar URL within PlexPy
* disable history logging per user
* disable notifications per user
* option to purge all history per user.
* Rich analytics presented using Highcharts graphing
* user-selectable time periods of 30, 90 or 365 days
* daily watch count and duration
* totals by day of week and hours of the day
* totals by top 10 platform
* totals by top 10 users
* detailed breakdown by transcode decision
* source and stream resolutions
* transcode decision counts by user and platform
* total monthly counts
* Content information pages
* movies (includes watching history)
* tv shows (includes watching history)
* tv seasons
* tv episodes (includes watching history)
* Full sync list data on all users syncing items from your library
## Installation and Notes
* [Installation page](../../wiki/Installation) shows you how to install PlexPy.
* [Usage guide](../../wiki/Usage-guide) introduces you to PlexPy.
* [Troubleshooting page](../../wiki/TroubleShooting) in the wiki can help you with common problems.
**Issues** can be reported on the GitHub issue tracker considering these rules:
1. Analyze your log, you just might find the solution yourself!
2. You read the wiki and searched existing issues, but this is not solving your problem.
3. Post the issue with a clear title, description and the HP log and use [proper markdown syntax](https://help.github.com/articles/github-flavored-markdown) to structure your text (code/log in code blocks).
4. Close your issue when it's solved! If you found the solution yourself please comment so that others benefit from it.
**Feature requests** can be reported on the GitHub issue tracker too:
1. Search for similar existing 'issues', feature requests can be recognized by the label 'Request'.
2. If a similar Request exists, post a comment (+1, or add a new idea to the existing request), otherwise you can create a new one.
If you **comply with these rules** you can [post your request/issue](http://github.com/drzoidberg33/plexpy/issues).
* [Installation Guides](https://github.com/JonnyWong16/plexpy/wiki/Installation) shows you how to install PlexPy.
* [FAQs](https://github.com/JonnyWong16/plexpy/wiki/Frequently-Asked-Questions-(FAQ)) in the wiki can help you with common problems.
**Support** the project by implementing new features, solving support tickets and provide bug fixes.
## 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/JonnyWong16/plexpy/wiki) for
[ [Installation] ](https://github.com/JonnyWong16/plexpy/wiki/Installation) and
[ [FAQs] ](https://github.com/JonnyWong16/plexpy/wiki/Frequently-Asked-Questions-(FAQ)).
- For basic questions try asking on [Gitter](https://gitter.im/plexpy/general) 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/JonnyWong16/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
Feature requests are handled on [FeatHub](http://feathub.com/JonnyWong16/plexpy).
1. Search the existing requests to see if your suggestion has already been submitted.
2. If a similar request exists, give it a thumbs up (+1), or add additional comments to the request.
3. If no similar requests exist, you can create a new one. Make sure to provide a clear title to easily identify the feature request.
## 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 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.

View File

@@ -2,11 +2,18 @@
<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">Import PlexWatch Database</h4>
<h4 class="modal-title">Import ${app} Database</h4>
</div>
<div class="modal-body" id="modal-text">
<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>
<div class="form-group">
<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>
</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 class="form-group">
<label for="table_name">Table Name</label>
@@ -23,7 +30,7 @@
<div class="col-xs-4">
<select id="table_name" class="form-control" name="table_name">
<option value="processed">processed</option>
<option value="processed">grouped</option>
<option value="grouped">grouped</option>
</select>
</div>
</div>
@@ -41,7 +48,7 @@
</div>
<div class="modal-footer">
<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">
</div>
</div>
@@ -54,8 +61,13 @@
var table_name = $("#table_name").val();
var import_ignore_interval = $("#import_ignore_interval").val();
$.ajax({
url: 'get_plexwatch_export_data',
data: {database_path: database_path, table_name:table_name, import_ignore_interval:import_ignore_interval},
url: 'import_database',
data: {
app: "${app}",
database_path: database_path,
table_name: table_name,
import_ignore_interval: import_ignore_interval
},
cache: false,
async: true,
success: function(data) {

View File

@@ -1,47 +1,156 @@
<%
import plexpy
from plexpy import version
import plexpy
from plexpy import version
from plexpy.helpers import anon_url
%>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>PlexPy - ${title}</title>
<title>PlexPy - ${title} | ${server_name}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link href="interfaces/default/css/bootstrap3/bootstrap.css" rel="stylesheet">
<link href="interfaces/default/css/plexpy.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css">
<link href="interfaces/default/css/font-awesome.min.css" rel="stylesheet">
<link href="${http_root}css/bootstrap3/bootstrap.css" rel="stylesheet">
<link href="${http_root}css/pnotify.custom.min.css" rel="stylesheet" />
<link href="${http_root}css/plexpy.css" rel="stylesheet">
<link href="${http_root}css/opensans.min.css" rel="stylesheet">
<link href="${http_root}css/font-awesome.min.css" rel="stylesheet">
${next.headIncludes()}
<link rel="icon" type="image/x-icon" href="interfaces/default/images/favicon.ico"/>
<!-- touch icons -->
<link rel="shortcut icon" href="interfaces/default/images/favicon.png">
<link rel="apple-touch-icon" href="interfaces/default/images/icon_iphone.png">
<link rel="apple-touch-icon" sizes="72x72" href="interfaces/default/images/icon_ipad.png">
<link rel="apple-touch-icon" sizes="114x114" href="interfaces/default/images/icon_iphone@2x.png">
<link rel="apple-touch-icon" sizes="144x144" href="interfaces/default/images/icon_ipad@2x.png">
<link rel="icon" type="image/x-icon" href="${http_root}images/favicon.ico"/>
<link rel="shortcut icon" href="${http_root}images/favicon.png">
<!-- Allow web app to be run in full-screen mode. -->
<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 -->
<!-- IE10 icon -->
<meta name="application-name" content="PlexPy" />
<meta name="msapplication-config" content="${http_root}xml/IEconfig.xml"/>
<!-- Android >M39 icon -->
<link rel="manifest" href="${http_root}json/Android-manifest.json">
<!-- iPad retina icon -->
<link href="${http_root}images/res/ios/icon-76@2x.png" sizes="152x152" rel="apple-touch-icon-precomposed">
<!-- iPad retina icon (iOS < 7) -->
<link href="${http_root}images/res/ios/icon-72@2x.png" sizes="144x144" rel="apple-touch-icon-precomposed">
<!-- iPad non-retina icon -->
<link href="${http_root}images/res/ios/icon-76.png" sizes="76x76" rel="apple-touch-icon-precomposed">
<!-- iPad non-retina icon (iOS < 7) -->
<link href="${http_root}images/res/ios/icon-72.png" sizes="72x72" rel="apple-touch-icon-precomposed">
<!-- iPhone 6 Plus icon -->
<link href="${http_root}images/res/ios/icon-60@2x.png" sizes="120x120" rel="apple-touch-icon-precomposed">
<!-- iPhone retina icon (iOS < 7) -->
<link href="${http_root}images/res/ios/icon@2x.png" sizes="114x114" rel="apple-touch-icon-precomposed">
<!-- iPhone non-retina icon (iOS < 7) -->
<link href="${http_root}images/res/ios/icon.png" sizes="57x57" rel="apple-touch-icon-precomposed">
<!-- iPhone / iPod Touch -->
<link href="${http_root}images/res/ios/icon-60@3x.png" sizes="180x180" rel="apple-touch-icon-precomposed">
<link href="${http_root}images/res/ios/icon-60.png" sizes="60x60" rel="apple-touch-icon-precomposed">
<!-- Spotlight Icon -->
<link href="${http_root}images/res/ios/icon-40.png" sizes="40x40" rel="apple-touch-icon-precomposed">
<link href="${http_root}images/res/ios/icon-40@2x.png" sizes="80x80" rel="apple-touch-icon-precomposed">
<!-- iPhone Spotlight and Settings Icon -->
<link href="${http_root}images/res/ios/icon-small.png" sizes="29x29" rel="apple-touch-icon-precomposed">
<link href="${http_root}images/res/ios/icon-small@2x.png" sizes="58x58" rel="apple-touch-icon-precomposed">
<!-- iPad Spotlight and Settings Icon -->
<link href="${http_root}images/res/ios/icon-50.png" sizes="50x50" rel="apple-touch-icon-precomposed">
<link href="${http_root}images/res/ios/icon-50@2x.png" sizes="100x100" rel="apple-touch-icon-precomposed">
<!-- STARTUP IMAGES -->
<!-- iPad retina portrait startup image -->
<link href="${http_root}images/res/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="${http_root}images/res/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="${http_root}images/res/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="${http_root}images/res/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="${http_root}images/res/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="${http_root}images/res/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="${http_root}images/res/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="${http_root}images/res/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="${http_root}images/res/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="${http_root}images/res/ios/Default~iphone.png"
media="(device-width: 320px) and (device-height: 480px)
and (-webkit-device-pixel-ratio: 1)"
rel="apple-touch-startup-image">
</head>
<body class="content">
<div class="container">
<div id="ajaxMsg" class="ajaxMsg"></div>
% if _session['user_group'] == 'admin':
% if plexpy.CONFIG.CHECK_GITHUB and not plexpy.CURRENT_VERSION:
<div id="updatebar" style="display: none;">
You're running an unknown version of PlexPy. <a href="update">Update</a> or
<a href="#" id="updateDismiss">Close</a>
You're running an unknown version of PlexPy.<br />
<a href="update">Update</a> or <a href="#" id="updateDismiss">Close</a>
</div>
% elif plexpy.CONFIG.CHECK_GITHUB and plexpy.CURRENT_VERSION != plexpy.LATEST_VERSION and plexpy.COMMITS_BEHIND > 0 and plexpy.INSTALL_TYPE != 'win':
<div id="updatebar" style="display: none;">
A <a
href="https://github.com/${plexpy.CONFIG.GIT_USER}/plexpy/compare/${plexpy.CURRENT_VERSION}...${plexpy.LATEST_VERSION}" target="_blank">
newer version</a> is available. You're ${plexpy.COMMITS_BEHIND} commits behind. <a href="update">Update</a> or
<a href="#" id="updateDismiss">Close</a>
A <a href="${anon_url('https://github.com/%s/plexpy/compare/%s...%s' % (plexpy.CONFIG.GIT_USER, plexpy.CURRENT_VERSION, plexpy.LATEST_VERSION))}" target="_blank">
newer version</a> is available.<br />
You're ${plexpy.COMMITS_BEHIND} commits behind.<br />
<a href="update">Update</a> or <a href="#" id="updateDismiss">Close</a>
</div>
% endif
% endif
<nav class="navbar navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
@@ -52,16 +161,16 @@ from plexpy import version
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="home">
<img alt="PlexPy" src="interfaces/default/images/logo-plexpy@2x.png" height="40">
<img alt="PlexPy" src="${http_root}images/logo-plexpy@2x.png" height="40">
</a>
</div>
<div class="collapse navbar-collapse navbar-right" id="navbar-collapse-1">
<ul class="nav navbar-nav">
<li>
<li class="hidden-sm hidden-xs">
<form action="search" method="post" class="form" id="search_form">
<div class="input-group">
<span class="input-textbox">
<input type="text" class="form-control" name="search_query" id="search_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 class="input-group-btn">
<button class="btn btn-dark btn-inactive" type="submit" id="search_button"><i class="fa fa-search"></i></button>
@@ -69,56 +178,209 @@ from plexpy import version
</div>
</form>
</li>
% if title=="Home":
<li class="active"><a href="home"><i class="fa fa-lg fa-home"></i></a></li>
% if title == "Home":
<li class="active"><a href="home"><i class="fa fa-lg fa-home"></i></a></li>
% 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
% if title=="Users" or title=="User":
<li class="active"><a href="users">Users</a></li>
% if title == "Libraries" or title == "Library" or title == "Info":
<li class="active"><a href="libraries">Libraries</a></li>
% else:
<li><a href="users">Users</a></li>
<li><a href="libraries">Libraries</a></li>
% endif
% if title=="History":
% if title == "Users" or title == "User":
<li class="active"><a href="users">Users</a></li>
% else:
<li><a href="users">Users</a></li>
% endif
% if title == "History":
<li class="active"><a href="history">History</a></li>
% else:
<li><a href="history">History</a></li>
% endif
% if title=="Graphs":
<li class="active"><a href="graphs">Graphs</a></li>
% if title == "Graphs":
<li class="active"><a href="graphs">Graphs</a></li>
% else:
<li><a href="graphs">Graphs</a></li>
<li><a href="graphs">Graphs</a></li>
% endif
% if title=="Synced Items":
<li class="active"><a href="sync">Synced Items</a></li>
% if title == "Synced Items":
<li class="active"><a href="sync">Synced Items</a></li>
% 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>
% if title == "Settings":
<li class="dropdown active">
% else:
<li><a href="logs">Logs</a></li>
% endif
% if title=="Settings":
<li class="active"><a href="settings">Settings</a></li>
% else:
<li><a href="settings">Settings</a></li>
<li class="dropdown">
% 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/plexpy/wiki/Frequently-Asked-Questions-(FAQ)' % plexpy.CONFIG.GIT_USER)}" target="_blank"><i class="fa fa-fw fa-question-circle"></i> FAQ</a></li>
<li><a href="settings?support=true"><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['expiry']:
<li><a href="${http_root}auth/logout"><i class="fa fa-fw fa-sign-out"></i> Sign Out</a></li>
% endif
</ul>
</li>
</ul>
</div>
</div>
</nav>
</div>
<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>
% 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 action="${http_root}auth/login" method="post">
<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">
<button 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">PlexPy 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 PlexPy!</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="#paypal-donation" role="tab" data-toggle="tab">PayPal</a></li>
<li><a href="#flattr-donation" role="tab" data-toggle="tab">Flattr</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="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=PlexPy&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="flattr-donation" style="text-align: center">
<p>
Click the button below to continue to Flattr.
</p>
<a href="${anon_url('https://flattr.com/submit/auto?user_id=JonnyWong16&url=https://github.com/JonnyWong16/plexpy&title=PlexPy&language=en_GB&tags=github&category=software')}" target="_blank">
<img src="images/flattr-badge-large.png" alt="Flattr">
</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
${next.headerIncludes()}
<div class="body-container">
${next.body()}
</div>
<script src="interfaces/default/js/jquery-2.1.4.min.js"></script>
<script src="interfaces/default/js/bootstrap3/bootstrap.min.js"></script>
<script src="interfaces/default/js/script.js"></script>
<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 src="${http_root}js/pnotify.custom.min.js"></script>
<script src="${http_root}js/script.js"></script>
<script src="${http_root}js/jquery.qrcode.min.js"></script>
% if _session['user_group'] == 'admin' and plexpy.CONFIG.BROWSER_ENABLED:
<script src="${http_root}js/ajaxNotifications.js"></script>
% else:
% endif
<script>
% if _session['user_group'] == 'admin':
$('#updateDismiss').click(function() {
$('#updatebar').slideUp('slow');
// Set cookie to remember dismiss decision for 1 hour.
@@ -128,28 +390,88 @@ ${next.headerIncludes()}
if (!getCookie('updateDismiss')) {
$('#updatebar').show();
}
</script>
<script>
$("#nav-shutdown").click(function() {
$("#confirm-message").text("Are you sure you want to shutdown PlexPy?");
$('#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 PlexPy?");
$('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-button', function () {
window.location.href = "restart";
});
});
$("#nav-update").first().one("click", function () {
// Allow the update bar to show again if previously dismissed.
setCookie('updateDismiss', 'true', 0);
$(this).html('<i class="fa fa-spin fa-refresh"></i> Checking');
window.location.href = "checkGithub";
});
$('#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) {
if ($('#search_query').hasClass('active') && $('#search_query').val().trim() != '') {
if ($('#query').hasClass('active') && $('#query').val().trim() != '') {
$.ajax({
type: 'post',
url: 'search',
data: { 'query': $('#search_query').val() }
data: { query: $('#query').val() }
})
} else {
e.preventDefault();
$('#search_button').removeClass('btn-inactive');
$('#search_query').clearQueue().val('').animate({ right: '0', width: '250px' }).addClass('active').focus();
$('#query').clearQueue().val('').animate({ right: '0', width: '200px' }).addClass('active').focus();
}
})
$('#search_query').on('blur', function (e) {
$('#query').on('blur', function (e) {
if ($(this).val().trim() == '') {
$(this).delay(200).animate({ right: '-250px', width: '0' }, function () {
$(this).delay(200).animate({ right: '-200px', width: '0' }, function () {
$('#search_button').addClass('btn-inactive');
}).removeClass('active');
}
});
$(document).ready(function () {
// Work around for iOS web app links opening in Safari
if (("standalone" in window.navigator) && window.navigator.standalone) {
// For iOS Apps
$('a').on('click', function (e) {
e.preventDefault();
var new_location = $(this).attr('href');
if (new_location != undefined && new_location.substr(0, 1) != '#' && $(this).attr('data-method') == undefined) {
window.location = new_location;
}
});
}
});
% if _session['user_group'] != 'admin':
$('#admin-login-modal').on('shown.bs.modal', function () {
$('#admin-login-modal #username').focus()
})
% endif
</script>
${next.javascriptIncludes()}
</body>

View File

@@ -0,0 +1,172 @@
<%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/plexpy/tree/%s' % (plexpy.CONFIG.GIT_USER, 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/plexpy/commit/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_BRANCH))}">${plexpy.CURRENT_VERSION}</a></td>
</tr>
% endif
<tr>
<td>Configuration File:</td>
<td>${plexpy.CONFIG_FILE}</td>
</tr>
<tr>
<td>Database File:</td>
<td>${plexpy.DB_FILE}</td>
</tr>
<tr>
<td>Log File:</td>
<td><a class="no-highlight" href="logFile" target="_blank">${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>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_VERSION}</td>
</tr>
<tr>
<td>Python Version:</td>
<td>${sys.version}</td>
</tr>
<tr>
<td class="top-line">Resources:</td>
<td class="top-line">
<a id="source-link" class="no-highlight" href="${anon_url('https://github.com/%s/plexpy' % plexpy.CONFIG.GIT_USER)}" target="_blank">GitHub Source</a> |
<a class="no-highlight guidelines-modal-link" href="${anon_url('https://github.com/%s/plexpy/issues' % plexpy.CONFIG.GIT_USER)}" data-id="issue">GitHub Issues</a> |
<a class="no-highlight guidelines-modal-link" href="${anon_url('http://feathub.com/%s/plexpy' % plexpy.CONFIG.GIT_USER)}" data-id="feature request">FeatHub Feature Requests</a> |
<a class="no-highlight" href="${anon_url('https://github.com/%s/plexpy/wiki' % plexpy.CONFIG.GIT_USER)}" target="_blank">PlexPy Wiki</a> |
<a id="faq-source-link" class="no-highlight" href="${anon_url('https://github.com/%s/plexpy/wiki/Frequently-Asked-Questions-(FAQ)' % plexpy.CONFIG.GIT_USER)}" target="_blank">PlexPy FAQ</a>
</td>
</tr>
<tr>
<td>Support:</td>
<td>
<a class="no-highlight support-modal-link" href="${anon_url('https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program')}" target="_blank">Plex Forums</a> |
<a class="no-highlight support-modal-link" href="${anon_url('https://gitter.im/plexpy/general')}" target="_blank">PlexPy Gitter Chat</a> |
<a id="best-support-link" class="no-highlight support-modal-link" href="${anon_url('https://discord.gg/011TFFWSuNFI02EKr')}" target="_blank">/r/Plex Discord Server</a> |
<a class="no-highlight support-modal-link" href="${anon_url('https://discord.gg/36ggawe')}" target="_blank">PlexPy Discord Server</a>
</td>
</tr>
</tbody>
</table>
<div id="guidelines-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="guidelines-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">Guidelines</h4>
</div>
<div class="modal-body">
<div style="text-align: center; margin-top: 20px; margin-bottom: 20px;">
<strong>Please read the <a href="#" target="_blank" id="guidelines-link">guidelines</a> in the README document <br />before submitting a new <span id="guidelines-type"></span>!</strong>
<br /><br />
Your post may be removed for failure to follow the guidelines.
</div>
</div>
<div class="modal-footer">
<a href="#" target="_blank" id="guidelines-continue" class="btn btn-bright">Continue</a>
</div>
</div>
</div>
</div>
<div id="support-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="support-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">Support</h4>
</div>
<div class="modal-body">
<div style="text-align: center; margin-top: 20px; margin-bottom: 20px;">
<strong>Please read the <a href="#" target="_blank" id="faq-link">FAQ</a> before asking for help!</strong>
</div>
</div>
<div class="modal-footer">
<a href="#" target="_blank" id="support-continue" class="btn btn-bright">Continue</a>
</div>
</div>
</div>
</div>
<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 PlexPy directory.<br />'
var url = 'install_geoip_db';
confirmAjaxCall(url, msg, '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, 'Uninstalling GeoLite2 database.', getConfigurationTable);
});
$('.guidelines-modal-link').on('click', function (e) {
e.preventDefault();
$('#guidelines-link').attr('href', $('#source-link').attr('href'));
$('#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();
$('#faq-link').attr('href', $('#faq-source-link').attr('href'));
$('#support-modal').modal();
$('#support-continue').attr('href', $(this).attr('href')).on('click', function () {
$('#support-modal').modal('hide');
});
});
});
</script>

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')}

File diff suppressed because it is too large Load Diff

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}}

View File

@@ -0,0 +1,401 @@
/**
* selectize.bootstrap3.css (v0.12.1) - Bootstrap 3 Theme
* Copyright (c) 20132015 Brian Reavis & contributors
*
* 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.
*
* @author Brian Reavis <brian@thirdroute.com>
*/
.selectize-control.plugin-drag_drop.multi > .selectize-input > div.ui-sortable-placeholder {
visibility: visible !important;
background: #f2f2f2 !important;
background: rgba(0, 0, 0, 0.06) !important;
border: 0 none !important;
-webkit-box-shadow: inset 0 0 12px 4px #ffffff;
box-shadow: inset 0 0 12px 4px #ffffff;
}
.selectize-control.plugin-drag_drop .ui-sortable-placeholder::after {
content: '!';
visibility: hidden;
}
.selectize-control.plugin-drag_drop .ui-sortable-helper {
-webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
.selectize-dropdown-header {
position: relative;
padding: 3px 12px;
border-bottom: 1px solid #d0d0d0;
background: #f8f8f8;
-webkit-border-radius: 4px 4px 0 0;
-moz-border-radius: 4px 4px 0 0;
border-radius: 4px 4px 0 0;
}
.selectize-dropdown-header-close {
position: absolute;
right: 12px;
top: 50%;
color: #333333;
opacity: 0.4;
margin-top: -12px;
line-height: 20px;
font-size: 20px !important;
}
.selectize-dropdown-header-close:hover {
color: #000000;
}
.selectize-dropdown.plugin-optgroup_columns .optgroup {
border-right: 1px solid #f2f2f2;
border-top: 0 none;
float: left;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.selectize-dropdown.plugin-optgroup_columns .optgroup:last-child {
border-right: 0 none;
}
.selectize-dropdown.plugin-optgroup_columns .optgroup:before {
display: none;
}
.selectize-dropdown.plugin-optgroup_columns .optgroup-header {
border-top: 0 none;
}
.selectize-control.plugin-remove_button [data-value] {
position: relative;
padding-right: 24px !important;
}
.selectize-control.plugin-remove_button [data-value] .remove {
z-index: 1;
/* fixes ie bug (see #392) */
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 17px;
text-align: center;
font-weight: bold;
font-size: 12px;
color: inherit;
text-decoration: none;
vertical-align: middle;
display: inline-block;
padding: 1px 0 0 0;
border-left: 1px solid rgba(0, 0, 0, 0);
-webkit-border-radius: 0 2px 2px 0;
-moz-border-radius: 0 2px 2px 0;
border-radius: 0 2px 2px 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.selectize-control.plugin-remove_button [data-value] .remove:hover {
background: rgba(0, 0, 0, 0.05);
}
.selectize-control.plugin-remove_button [data-value].active .remove {
border-left-color: rgba(0, 0, 0, 0);
}
.selectize-control.plugin-remove_button .disabled [data-value] .remove:hover {
background: none;
}
.selectize-control.plugin-remove_button .disabled [data-value] .remove {
border-left-color: rgba(77, 77, 77, 0);
}
.selectize-control {
position: relative;
}
.selectize-dropdown,
.selectize-input,
.selectize-input input {
color: #333333;
font-family: inherit;
font-size: inherit;
line-height: 20px;
-webkit-font-smoothing: inherit;
}
.selectize-input,
.selectize-control.single .selectize-input.input-active {
background: #ffffff;
cursor: text;
display: inline-block;
}
.selectize-input {
border: 1px solid #cccccc;
padding: 6px 12px;
display: inline-block;
width: 100%;
overflow: hidden;
position: relative;
z-index: 1;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-box-shadow: none;
box-shadow: none;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.selectize-control.multi .selectize-input.has-items {
padding: 5px 12px 2px;
}
.selectize-input.full {
background-color: #ffffff;
}
.selectize-input.disabled,
.selectize-input.disabled * {
cursor: default !important;
}
.selectize-input.focus {
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15);
}
.selectize-input.dropdown-active {
-webkit-border-radius: 4px 4px 0 0;
-moz-border-radius: 4px 4px 0 0;
border-radius: 4px 4px 0 0;
}
.selectize-input > * {
vertical-align: baseline;
display: -moz-inline-stack;
display: inline-block;
zoom: 1;
*display: inline;
}
.selectize-control.multi .selectize-input > div {
cursor: pointer;
margin: 0 3px 3px 0;
padding: 1px 3px;
background: #efefef;
color: #333333;
border: 0 solid rgba(0, 0, 0, 0);
}
.selectize-control.multi .selectize-input > div.active {
background: #428bca;
color: #ffffff;
border: 0 solid rgba(0, 0, 0, 0);
}
.selectize-control.multi .selectize-input.disabled > div,
.selectize-control.multi .selectize-input.disabled > div.active {
color: #808080;
background: #ffffff;
border: 0 solid rgba(77, 77, 77, 0);
}
.selectize-input > input {
display: inline-block !important;
padding: 0 !important;
min-height: 0 !important;
max-height: none !important;
max-width: 100% !important;
margin: 0 !important;
text-indent: 0 !important;
border: 0 none !important;
background: none !important;
line-height: inherit !important;
-webkit-user-select: auto !important;
-webkit-box-shadow: none !important;
box-shadow: none !important;
}
.selectize-input > input::-ms-clear {
display: none;
}
.selectize-input > input:focus {
outline: none !important;
}
.selectize-input::after {
content: ' ';
display: block;
clear: left;
}
.selectize-input.dropdown-active::before {
content: ' ';
display: block;
position: absolute;
background: #ffffff;
height: 1px;
bottom: 0;
left: 0;
right: 0;
}
.selectize-dropdown {
position: absolute;
z-index: 10;
border: 1px solid #d0d0d0;
background: #ffffff;
margin: -1px 0 0 0;
border-top: 0 none;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
-webkit-border-radius: 0 0 4px 4px;
-moz-border-radius: 0 0 4px 4px;
border-radius: 0 0 4px 4px;
}
.selectize-dropdown [data-selectable] {
cursor: pointer;
overflow: hidden;
}
.selectize-dropdown [data-selectable] .highlight {
background: rgba(255, 237, 40, 0.4);
-webkit-border-radius: 1px;
-moz-border-radius: 1px;
border-radius: 1px;
}
.selectize-dropdown [data-selectable],
.selectize-dropdown .optgroup-header {
padding: 3px 12px;
}
.selectize-dropdown .optgroup:first-child .optgroup-header {
border-top: 0 none;
}
.selectize-dropdown .optgroup-header {
color: #777777;
background: #ffffff;
cursor: default;
}
.selectize-dropdown .active {
background-color: #f5f5f5;
color: #262626;
}
.selectize-dropdown .active.create {
color: #262626;
}
.selectize-dropdown .create {
color: rgba(51, 51, 51, 0.5);
}
.selectize-dropdown-content {
overflow-y: auto;
overflow-x: hidden;
max-height: 200px;
}
.selectize-control.single .selectize-input,
.selectize-control.single .selectize-input input {
cursor: pointer;
}
.selectize-control.single .selectize-input.input-active,
.selectize-control.single .selectize-input.input-active input {
cursor: text;
}
.selectize-control.single .selectize-input:after {
content: ' ';
display: block;
position: absolute;
top: 50%;
right: 17px;
margin-top: -3px;
width: 0;
height: 0;
border-style: solid;
border-width: 5px 5px 0 5px;
border-color: #333333 transparent transparent transparent;
}
.selectize-control.single .selectize-input.dropdown-active:after {
margin-top: -4px;
border-width: 0 5px 5px 5px;
border-color: transparent transparent #333333 transparent;
}
.selectize-control.rtl.single .selectize-input:after {
left: 17px;
right: auto;
}
.selectize-control.rtl .selectize-input > input {
margin: 0 4px 0 -2px !important;
}
.selectize-control .selectize-input.disabled {
opacity: 0.5;
background-color: #ffffff;
}
.selectize-dropdown,
.selectize-dropdown.form-control {
height: auto;
padding: 0;
margin: 2px 0 0 0;
z-index: 1000;
background: #ffffff;
border: 1px solid #cccccc;
border: 1px solid rgba(0, 0, 0, 0.15);
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
}
.selectize-dropdown .optgroup-header {
font-size: 12px;
line-height: 1.42857143;
}
.selectize-dropdown .optgroup:first-child:before {
display: none;
}
.selectize-dropdown .optgroup:before {
content: ' ';
display: block;
height: 1px;
margin: 9px 0;
overflow: hidden;
background-color: #e5e5e5;
margin-left: -12px;
margin-right: -12px;
}
.selectize-dropdown-content {
padding: 5px 0;
}
.selectize-dropdown-header {
padding: 6px 12px;
}
.selectize-input {
min-height: 34px;
}
.selectize-input.dropdown-active {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.selectize-input.dropdown-active::before {
display: none;
}
.selectize-input.focus {
border-color: #66afe9;
outline: 0;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
}
.has-error .selectize-input {
border-color: #a94442;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.has-error .selectize-input:focus {
border-color: #843534;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
}
.selectize-control.multi .selectize-input.has-items {
padding-left: 9px;
padding-right: 9px;
}
.selectize-control.multi .selectize-input > div {
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
.form-control.selectize-control {
padding: 0;
height: auto;
border: none;
background: none;
-webkit-box-shadow: none;
box-shadow: none;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}

View File

@@ -32,6 +32,7 @@ user_thumb Returns the profile picture of the user owning the s
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.
@@ -67,20 +68,23 @@ DOCUMENTATION :: END
% 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?item_id=${a['rating_key']}">
% if (a['media_type'] == 'movie' or a['media_type'] == 'episode' or a['media_type'] == 'track') and a['rating_key']:
<a href="info?rating_key=${a['rating_key']}">
% else:
<a href="#">
% endif
<div class="dashboard-activity-poster">
% if a['media_type'] == 'movie' and not a['indexes']:
<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']:
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['art']}&width=500&height=280);"></div>
% if not a['art'].startswith('interfaces') or not a['thumb'].startswith('interfaces'):
% 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&fallback=art);"></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&fallback=art);"></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>
<div class="dashboard-activity-poster-face bif" style="background-image: url(pms_image_proxy?img=${a['bif_thumb']}&width=500&height=280&fallback=art); 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>
<div class="dashboard-activity-cover-face-bg" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=300&height=300&fallback=cover);"></div>
<div class="dashboard-activity-cover-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=300&height=300&fallback=cover);"></div>
% elif a['media_type'] == 'clip':
% if a['art'][:4] == 'http':
<div class="dashboard-activity-poster-face" style="background-image: url(${a['art']});"></div>
@@ -88,17 +92,23 @@ DOCUMENTATION :: END
<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>
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['art']}&width=500&height=280&fallback=art);"></div>
% else:
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=500&height=280);"></div>
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=500&height=280&fallback=art);"></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>
<div class="dashboard-activity-poster-face bif" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=500&height=500&fallback=cover);"></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
% else:
<div class="dashboard-activity-poster-face" style="background-image: url(${a['art']});"></div>
% endif
% if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% 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>
@@ -137,9 +147,9 @@ DOCUMENTATION :: END
<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':
% 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':
% 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':
@@ -191,25 +201,45 @@ DOCUMENTATION :: END
</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':
% if (a['media_type'] == 'movie' or a['media_type'] == 'episode' or a['media_type'] == 'track') and a['rating_key']:
</a>
% else:
</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 class="bufferbar" style="width: ${a['transcode_progress']}%" data-toggle="tooltip" title="Transcoder Progress">${a['transcode_progress']}%</div>
<div class="bar" style="width: ${a['progress_percent']}%" data-toggle="tooltip" title="Stream Progress">${a['progress_percent']}%</div>
</div>
</div>
<div class="dashboard-activity-metadata-wrapper">
% if a['user_id']:
<a href="user?user_id=${a['user_id']}">
<div class="dashboard-activity-metadata-user-thumb" style="background-image: url(${a['user_thumb']});"></div>
</a>
% else:
<div class="dashboard-activity-metadata-user-thumb" style="background-image: url(${a['user_thumb']});"></div>
% endif
<div class="dashboard-activity-metadata-title">
% if a['state'] == 'playing':
<i class="fa fa-play"></i>&nbsp;
@@ -218,38 +248,44 @@ DOCUMENTATION :: END
% elif a['state'] == 'buffering':
<i class="fa fa-spinner"></i>&nbsp;
% endif
% if a['rating_key']:
% if a['media_type'] == 'episode':
<a href="info?item_id=${a['rating_key']}" title="${a['grandparent_title']} - ${a['title']}">${a['grandparent_title']} - ${a['title']}</a>
<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?item_id=${a['rating_key']}" title="${a['title']}">${a['title']}</a>
<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?item_id=${a['rating_key']}" title="${a['grandparent_title']} - ${a['title']}">${a['grandparent_title']} - ${a['title']}</a>
<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
% else:
${a['title']}
% endif
</div>
<div class="dashboard-activity-metadata-subtitle">
% if a['rating_key']:
% 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?item_id=${a['parent_rating_key']}" title="${a['parent_title']}">${a['parent_title']}</a>
<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
% 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>
${a['friendly_name']}
% endif
</div>
</div>
@@ -272,6 +308,15 @@ DOCUMENTATION :: END
e.preventDefault();
$($(this).attr('data-target')).toggle();
});
// Add hover class to dashboard-instance
$('.dashboard-activity-poster, .dashboard-activity-progress-bar').hover(function() {
$(this).closest('.dashboard-instance').addClass('hover');
}, function() {
$(this).closest('.dashboard-instance').removeClass('hover');
});
$('.bar, .bufferbar').tooltip({container: 'body', placement: 'right', delay: 50});
</script>
% else:
<div class="text-muted">Nothing is currently being watched.</div><br>

View File

@@ -15,11 +15,24 @@ DOCUMENTATION :: END
</%doc>
% if data != None:
% if data == '0':
<h3>Activity</h3>
<%
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>
% elif data['stream_count'] == '1':
<h3>Activity &nbsp;&nbsp;<small>${data['stream_count']} stream ${s}</small></h3>
% else:
<h3>Activity &nbsp;&nbsp;<small>${data['stream_count']} streams ${s}</small></h3>
% endif
% else:
<h3>Activity <small>${data} stream(s)</small></h3>
<h3>Activity</h3>
% endif
% else:
<h3>Activity</h3>
% endif

View File

@@ -0,0 +1,278 @@
<%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.
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:
<%
from urllib import quote
from plexpy import helpers
data['indexes'] = helpers.cast_to_int(data['indexes'])
%>
<div class="dashboard-instance" id="instance-${data['session_key']}" data-id="${data['session_key']}">
<div class="dashboard-hover-container">
% if (data['media_type'] == 'movie' or data['media_type'] == 'episode' or data['media_type'] == 'track') and data['rating_key']:
<a href="info?rating_key=${data['rating_key']}">
% else:
<a href="#">
% endif
<div class="dashboard-activity-poster" id="poster-${data['session_key']}">
% if not data['art'].startswith('interfaces') or not data['thumb'].startswith('interfaces'):
% if (data['media_type'] == 'movie' and not data['indexes']) or (data['indexes'] and not data['view_offset']):
<div id="bif-${data['session_key']}" class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${data['art']}&width=500&height=280&fallback=art);"></div>
% elif (data['media_type'] == 'episode' and not data['indexes']) or (data['indexes'] and not data['view_offset']):
<div id="bif-${data['session_key']}" class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${data['art']}&width=500&height=280&fallback=art);"></div>
% elif data['indexes']:
<div id="bif-${data['session_key']}" class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${data['bif_thumb']}&width=500&height=280&fallback=art); display: none;"></div>
% else:
% if data['media_type'] == 'track':
<div class="dashboard-activity-cover-face-bg" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=300&height=300&fallback=cover);"></div>
<div class="dashboard-activity-cover-face" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=300&height=300&fallback=cover);"></div>
% elif data['media_type'] == 'clip':
% if data['art'].startswith('http'):
<div class="dashboard-activity-poster-face" style="background-image: url(${data['art']});"></div>
% elif data['thumb'].startswith('http'):
<div class="dashboard-activity-poster-face" style="background-image: url(${data['thumb']});"></div>
% else:
% if data['art']:
<!--Hacky solution to escape the image url until I come up with something better-->
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${quote(data['art'])}&width=500&height=280&fallback=art);"></div>
% else:
<!--Hacky solution to escape the image url until I come up with something better-->
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${quote(data['thumb'])}&width=500&height=280&fallback=art);"></div>
% endif
% endif
% elif data['media_type'] == 'photo':
<div id="bif-${data['session_key']}" class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=500&height=500&fallback=cover);"></div>
% else:
<div class="dashboard-activity-cover-face" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=300&height=300&fallback=cover);"></div>
% endif
% endif
% else:
<div class="dashboard-activity-poster-face" style="background-image: url(${data['art']});"></div>
% endif
% if _session['user_group'] == 'admin':
<span class="overlay-refresh-image left" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif
<div class="dashboard-activity-button-info">
<button type="button" class="btn btn-activity-info btn-lg" data-target="#stream-${data['session_key']}" data-id="${data['session_key']}">
<i class="fa fa-info-circle"></i>
</button>
</div>
<div id="stream-${data['session_key']}" class="dashboard-activity-info-details-overlay">
<div class="dashboard-activity-info-details-content">
<div id="platform-${data['session_key']}" title="${data['platform']}">
<script>
$("#platform-${data['session_key']}").html("<div class='dashboard-activity-info-platform-box' style='background-image: url(" + getPlatformImagePath('${data['platform']}') + ");'>");
</script>
</div>
<div class="dashboard-activity-info-platform">
<strong>${data['player']}</strong><br />
<span id="overlay-play-state-${data['session_key']}">
% if data['state'] == 'playing':
State &nbsp;<strong>Playing</strong>
% elif data['state'] == 'paused':
State &nbsp;<strong>Paused</strong>
% elif data['state'] == 'buffering':
State &nbsp;<strong>Buffering</strong>
% endif
</span>
</div>
<span id="transcode-state-${data['session_key']}">
% if data['video_decision'] == 'transcode' or data['audio_decision'] == 'transcode':
Stream &nbsp;<strong>Transcode (Speed: ${data['transcode_speed']})
% if data['throttled'] == '1':
(Throttled)
% endif
</strong>
% elif data['video_decision'] == 'copy' or data['audio_decision'] == 'copy':
Stream &nbsp;<strong>Direct Stream</strong>
% else:
Stream &nbsp;<strong>Direct Play</strong>
% endif
<br />
% if data['video_decision'] and data['media_type'] != 'photo':
% if data['video_decision'] == 'transcode':
Video &nbsp;<strong>Transcode (${data['transcode_video_codec']}) (${data['transcode_width']}x${data['transcode_height']})</strong>
% elif data['video_decision'] == 'copy':
Video &nbsp;<strong>Direct Stream (${data['transcode_video_codec']}) (${data['width']}x${data['height']})</strong>
% else:
Video &nbsp;<strong>Direct Play (${data['video_codec']}) (${data['width']}x${data['height']})</strong>
% endif
<br />
% endif
% if data['audio_decision']:
% if data['audio_decision'] == 'transcode':
Audio &nbsp;<strong>Transcode (${data['transcode_audio_codec']}) (${data['transcode_audio_channels']}ch)</strong>
% elif data['audio_decision'] == 'copy':
Audio &nbsp;<strong>Direct Stream (${data['transcode_audio_codec']}) (${data['transcode_audio_channels']}ch)</strong>
% else:
Audio &nbsp;<strong>Direct Play (${data['audio_codec']}) (${data['audio_channels']}ch)</strong>
% endif
% endif
</span>
</div>
</div>
% if data['media_type'] != 'photo':
<div class="dashboard-activity-poster-info-bar">
<div class="dashboard-activity-poster-info-ip-address">
% if data['ip_address']:
<span>IP: ${data['ip_address']}</span>
% else:
<span>IP: N/A</span>
% endif
<br />
ETA:
<span id="stream-eta-${data['session_key']}">
<script>
$("#stream-eta-${data['session_key']}").html(moment().add(parseInt("${data['duration']}") - parseInt("${data['view_offset']}"), 'milliseconds').format(time_format));
</script>
</span>
</div>
<div class="dashboard-activity-poster-info-time">
<span class="progress_time" id="stream-view-offset-${data['session_key']}">
<script>
$("#stream-view-offset-${data['session_key']}").html(millisecondsToMinutes(parseInt("${data['view_offset']}"), false));
</script>
</span>/<span class="progress_time" id="stream-duration-${data['session_key']}">
<script>
$("#stream-duration-${data['session_key']}").html(millisecondsToMinutes(parseInt("${data['duration']}"), false));
</script>
</span>
</div>
</div>
% endif
</div>
% if (data['media_type'] == 'movie' or data['media_type'] == 'episode' or data['media_type'] == 'track') and data['rating_key']:
</a>
% else:
</a>
% endif
<div class="dashboard-activity-progress">
<div class="dashboard-activity-progress-bar">
<div id="bufferbar-${data['session_key']}" class="bufferbar" style="width: ${data['transcode_progress']}%" data-toggle="tooltip" title="Transcoder Progress ${data['transcode_progress']}%">${data['transcode_progress']}%</div>
<div id="bar-${data['session_key']}" class="bar" style="width: ${data['progress_percent']}%" data-toggle="tooltip" title="Stream Progress ${data['progress_percent']}%">${data['progress_percent']}%</div>
</div>
</div>
</div>
<div class="dashboard-activity-metadata-wrapper">
% if data['user_id']:
<a href="user?user_id=${data['user_id']}">
<div class="dashboard-activity-metadata-user-thumb" style="background-image: url(${data['user_thumb']});"></div>
</a>
% else:
<div class="dashboard-activity-metadata-user-thumb" style="background-image: url(${data['user_thumb']});"></div>
% endif
<div class="dashboard-activity-metadata-title">
<span id="play-state-${data['session_key']}">
% 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
</span>
% if data['rating_key']:
% if data['media_type'] == 'episode':
<a href="info?rating_key=${data['grandparent_rating_key']}" title="${data['grandparent_title']}">${data['grandparent_title']}</a>
- <a href="info?rating_key=${data['rating_key']}" title="${data['title']}">${data['title']}</a>
% elif data['media_type'] == 'movie':
<a href="info?rating_key=${data['rating_key']}" title="${data['title']}">${data['title']}</a>
% elif data['media_type'] == 'clip':
<span title="${data['title']}">${data['title']}</span>
% elif data['media_type'] == 'track':
<a href="info?rating_key=${data['grandparent_rating_key']}" title="${data['grandparent_title']}">${data['grandparent_title']}</a>
- <a href="info?rating_key=${data['rating_key']}" title="${data['title']}">${data['title']}</a>
% elif data['media_type'] == 'photo':
<span title="${data['parent_title']}">${data['parent_title']}</span>
% else:
<span title="${data['title']}">${data['title']}</span>
% endif
% else:
${data['title']}
% endif
</div>
<div class="dashboard-activity-metadata-subtitle">
% if data['rating_key']:
% if data['media_type'] == 'episode':
<a href="info?rating_key=${data['parent_rating_key']}" title="Season ${data['parent_media_index']}" class="text-muted">S${data['parent_media_index']}</a>
&middot; <a href="info?rating_key=${data['rating_key']}" title="Episode ${data['media_index']}" class="text-muted">E${data['media_index']}</a>
% elif data['media_type'] == 'movie':
<span title="${data['year']}">${data['year']}</span>
% elif data['media_type'] == 'track':
<a href="info?rating_key=${data['parent_rating_key']}" title="${data['parent_title']}">${data['parent_title']}</a>
% elif data['media_type'] == 'photo':
<span title="${data['title']}">${data['title']}</span>
% else:
<span title="${data['year']}">${data['year']}</span>
% endif
% endif
</div>
<div class="dashboard-activity-metadata-user">
% if data['user_id']:
<a href="user?user_id=${data['user_id']}" title="${data['friendly_name']}">${data['friendly_name']}</a>
% else:
${data['friendly_name']}
% endif
</div>
</div>
</div>
% endif

View File

@@ -0,0 +1,179 @@
<%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: edit_library.html
Version: 0.1
Variable names: data [list]
data :: Usable parameters
== Global keys ==
section_id Returns the library id of the library.
section_name Returns the name of the library.
section_type Returns the type of the library.
library_thumb Returns the thumbnail for the library.
custom_thumb Returns the custom thumbnail for the library.
library_art Returns the artwork for the library.
count Returns the item count for the library.
parent_count Returns the parent item count for the library.
child_count Returns the child item count for the library.
do_notify Returns bool value for whether to send notifications for the library.
keep_history Returns bool value for whether to keep history for the library.
DOCUMENTATION :: END
</%doc>
<%!
from plexpy import helpers
%>
% if data != None:
<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">Edit library <strong>${data['section_name']}</strong></h4>
</div>
<div class="modal-body" id="modal-text">
<fieldset>
<div class="form-group">
<label for="profile_url">Library Picture URL</label>
<div class="row">
<div class="col-md-8">
<input type="text" class="form-control" id="custom_thumb_url" name="custom_thumb_url" value="${data['library_thumb']}">
</div>
</div>
<p class="help-block">Change the library's picture in PlexPy. 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 class="checkbox">
<label>
<input type="checkbox" id="keep_history" name="keep_history" value="1" ${helpers.checked(data['keep_history'])}> Keep history
</label>
<p class="help-block">Uncheck this if you do not want to keep any history on this library's activity.</p>
</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']:
<div class="form-group">
<button class="btn btn-danger" id="delete-all-history">Purge</button>
<p class="help-block">DANGER ZONE! Click the purge button to remove all history logged for this library. This is permanent!</p>
</div>
% endif
</fieldset>
</div>
<div class="modal-footer">
<div>
<span id="edit-library-status-message"></span>
<input type="button" id="save_library" class="btn btn-bright" value="Save">
</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>
// Save library options
$("#save_library").on('click', function () {
var custom_thumb = $("#custom_thumb_url").val();
var do_notify = 0;
var do_notify_created = 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")) {
keep_history = 1;
}
$.ajax({
url: 'edit_library',
data: {
section_id: '${data["section_id"]}',
custom_thumb: custom_thumb,
do_notify: do_notify,
do_notify_created: do_notify_created,
keep_history: keep_history
},
cache: false,
async: true,
success: function (data) {
location.reload();
}
});
});
$("#delete-all-history").on('click', function() {
$('#confirm-modal-purge').modal();
$('#confirm-modal-purge').one('click', '#confirm-purge', function () {
$.ajax({
url: 'delete_all_library_history',
data: { section_id: '${data["section_id"]}' },
cache: false,
async: true,
success: function(data) {
location.reload();
}
});
});
});
$(document).ready(function() {
// Move #confirm-modal to parent container
if (!($('#edit-library-modal').next().is('#confirm-modal-purge'))) {
$('#confirm-modal-purge').appendTo($('#edit-library-modal').parent());
}
$('#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>
% endif

View File

@@ -10,21 +10,31 @@ Variable names: data [list]
data :: Usable parameters
== Global keys ==
user Return the real Plex username
user_id Return the Plex user_id
friendly_name Returns the friendly edited Plex username
do_notify Returns bool value for whether the user should trigger notifications
keep_history Returns bool value for whether the user's activity should be logged
user_id Returns the user id of the user.
username Returns the user's username.
friendly_name Returns the friendly name of the user.
email Returns the user's email address.
user_thumb Returns the thumbnail for the user.
is_home_user Returns bool value for whether the user is part of a Plex Home.
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.
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.
allow_guest Returns bool value for whether to allow guest access for the user.
DOCUMENTATION :: END
</%doc>
% if data is not None:
<%!
from plexpy import helpers
%>
% if data != None:
<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">Edit user <strong>${data['user']}</strong></h4>
<h4 class="modal-title">Edit user <strong>${data['username']}</strong></h4>
</div>
<div class="modal-body" id="modal-text">
<fieldset>
@@ -35,28 +45,34 @@ DOCUMENTATION :: END
<input type="text" class="form-control" id="friendly_name" name="friendly_name" value="${data['friendly_name']}" size="30">
</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 class="form-group">
<label for="profile_url">Profile Picture URL</label>
<div class="row">
<div class="col-md-8">
<input type="text" class="form-control" id="profile_url" name="profile_url" value="${data['thumb']}">
<input type="text" class="form-control" id="custom_avatar_url" name="custom_avatar_url" value="${data['user_thumb']}">
</div>
</div>
<p class="help-block">Change the users profile picture in PlexPy. To reset to default, leave this field empty and save then perform a user refresh.</p>
<p class="help-block">Change the users profile picture in PlexPy. 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" ${data['do_notify']}> Enable notifications
<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 class="checkbox">
<label>
<input type="checkbox" id="keep_history" name="keep_history" value="1" ${data['keep_history']}> Keep history
<input type="checkbox" id="keep_history" name="keep_history" value="1" ${helpers.checked(data['keep_history'])}> Keep history
</label>
<p class="help-block">Uncheck this if you do not want this 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 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 PlexPy.</p>
</div>
% if data['user_id']:
<div class="form-group">
@@ -69,12 +85,12 @@ DOCUMENTATION :: END
<div class="modal-footer">
<div>
<span id="edit-user-status-message"></span>
<input type="button" id="save_user_name" class="btn btn-bright" value="Save">
<input type="button" id="save_user" class="btn btn-bright" value="Save">
</div>
</div>
</div>
</div>
<div id="confirm-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="confirm-modal">
<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">
@@ -93,56 +109,47 @@ DOCUMENTATION :: END
</div>
</div>
<script>
// Set new friendly name
$("#save_user_name").click(function() {
// Set user options
$("#save_user").on('click', function () {
var friendly_name = $("#friendly_name").val();
var thumb = $("#profile_url").val();
var custom_thumb = $("#custom_avatar_url").val();
var do_notify = 0;
var keep_history = 0;
var allow_guest = 0;
if ($("#do_notify").is(":checked")) {
do_notify = 1;
}
if ($("#keep_history").is(":checked")) {
keep_history = 1;
}
if ($("#allow_guest").is(":checked")) {
allow_guest = 1;
}
% if data['user_id']:
$.ajax({
url: 'edit_user',
data: {user_id: '${data['user_id']}', friendly_name: friendly_name, do_notify: do_notify, keep_history: keep_history, thumb: thumb},
cache: false,
async: true,
success: function(data) {
$("#edit-user-status-message").html(data);
if ($.trim(friendly_name) !== '') {
$(".set-username").html(friendly_name);
}
$("#user-profile-thumb").attr('src', thumb);
}
});
% else:
$.ajax({
url: 'edit_user',
data: {user: '${data['user']}', friendly_name: friendly_name, do_notify: do_notify, keep_history: keep_history, thumb: thumb},
cache: false,
async: true,
success: function(data) {
$("#edit-user-status-message").html(data);
if ($.trim(friendly_name) !== '') {
$(".set-username").html(friendly_name);
}
$("#user-profile-thumb").attr('src', thumb);
}
});
% endif
$.ajax({
url: 'edit_user',
data: {
user_id: '${data["user_id"]}',
friendly_name: friendly_name,
custom_thumb: custom_thumb,
do_notify: do_notify,
keep_history: keep_history,
allow_guest: allow_guest
},
cache: false,
async: true,
success: function(data) {
location.reload();
}
});
});
$("#delete-all-history").on('click', function() {
$('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-purge', function () {
$('#confirm-modal-purge').modal();
$('#confirm-modal-purge').one('click', '#confirm-purge', function () {
$.ajax({
url: 'delete_all_user_history',
data: {user_id: '${data['user_id']}'},
data: { user_id: '${data["user_id"]}' },
cache: false,
async: true,
success: function(data) {
@@ -153,31 +160,31 @@ DOCUMENTATION :: END
});
$(document).ready(function() {
// Move #confirm-modal to parent container
if(!($('#edit-user-modal').next().is('#confirm-modal'))) {
$('#confirm-modal').appendTo($('#edit-user-modal').parent()); }
$('#edit-user-modal > #confirm-modal').remove();
// Move #confirm-modal-purge to parent container
if (!($('#edit-user-modal').next().is('#confirm-modal-purge'))) {
$('#confirm-modal-purge').appendTo($('#edit-user-modal').parent());
}
$('#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 () {
$('#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-user-modal').css('overflow-y', 'hidden');
});
$('#confirm-modal').on('shown.bs.modal', function () {
$('#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').on('hidden.bs.modal', function() {
$('#confirm-modal-purge').on('hidden.bs.modal', function () {
$('body').addClass('modal-open');
$('#edit-user-modal').css('overflow-y', 'auto');
});
});
</script>
% 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"/>
<%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css">
<link rel="stylesheet" href="${http_root}css/dataTables.bootstrap.css">
<link rel="stylesheet" href="${http_root}css/plexpy-dataTables.css">
</%def>
<%def name="body()">
@@ -12,111 +12,146 @@
<span><i class="fa fa-bar-chart"></i> Graphs</span>
</div>
<div class="button-bar hidden-xs">
<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" data-toggle="buttons" id="yaxis-selection">
% if config['graph_type'] == 'duration':
<label class="btn btn-dark">
<input type="radio" name="yaxis-options" id="yaxis-count" value="plays" autocomplete="off"> Play Count
</label>
<label class="btn btn-dark active">
<input type="radio" name="yaxis-options" id="yaxis-duration" value="duration" autocomplete="off" checked> Play Duration
</label>
% else:
<label class="btn btn-dark active">
<input type="radio" name="yaxis-options" id="yaxis-count" value="plays" autocomplete="off" checked> Play Count
</label>
<label class="btn btn-dark">
<input type="radio" name="yaxis-options" id="yaxis-duration" value="duration" autocomplete="off"> Play Duration
</label>
% endif
</div>
<div class="btn-group" data-toggle="buttons" id="days-selection">
<label class="btn btn-dark">
<input type="radio" name="date-options" id="graph-7" value="7" autocomplete="off"> 7 days
</label>
<label class="btn btn-dark active">
<input type="radio" name="date-options" id="graph-30" value="30" autocomplete="off" checked> 30 days
</label>
<label class="btn btn-dark">
<input type="radio" name="date-options" id="graph-90" value="90" autocomplete="off"> 90 days
</label>
<label class="btn btn-dark">
<input type="radio" name="date-options" id="graph-365" value="365" autocomplete="off"> 1 year
<div class="btn-group" id="days-selection">
<label>
<input type="number" name="graph-days" id="graph-days" value="${config['graph_days']}" min="1" /> days
</label>
</div>
<div class="btn-group" id="months-selection">
<label>
<input type="number" name="graph-months" id="graph-months" value="${config['graph_months']}" min="1" /> months
</label>
</div>
</div>
</div>
<div class='table-card-back'>
<ul class="nav nav-pills" role="tablist" id="graph-tabs">
% if config['graph_tab'] == 'tabs-3':
<li role="presentation"><a href="#tabs-1" aria-controls="tabs-1" data-toggle="tab" role="tab">Plays by period</a></li>
<li role="presentation"><a href="#tabs-2" aria-controls="tabs-2" data-toggle="tab" role="tab">Stream Info</a></li>
<li role="presentation" class="active"><a href="#tabs-3" aria-controls="tabs-3" data-toggle="tab" role="tab">Play Totals</a></li>
% elif config['graph_tab'] == 'tabs-2':
<li role="presentation"><a href="#tabs-1" aria-controls="tabs-1" data-toggle="tab" role="tab">Plays by period</a></li>
<li role="presentation" class="active"><a href="#tabs-2" aria-controls="tabs-2" data-toggle="tab" role="tab">Stream Info</a></li>
<li role="presentation"><a href="#tabs-3" aria-controls="tabs-3" data-toggle="tab" role="tab">Play Totals</a></li>
% else:
<li role="presentation" class="active"><a href="#tabs-1" aria-controls="tabs-1" data-toggle="tab" role="tab">Plays by period</a></li>
<li role="presentation"><a href="#tabs-2" aria-controls="tabs-2" data-toggle="tab" role="tab">Stream Info</a></li>
<li role="presentation"><a href="#tabs-3" aria-controls="tabs-3" data-toggle="tab" role="tab">Play Totals</a></li>
% endif
</ul>
<div class="tab-content">
% if config['graph_tab'] != 'tabs-2' and config['graph_tab'] != 'tabs-3':
<div role="tabpanel" class="tab-pane active" id="tabs-1">
<div class="row">
<div class="col-md-12">
<h4><i class="fa fa-history"></i> Daily <span class="yaxis-text">Play count</span> <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The total play count or duration of tv, movies, and music played per day. Click a graph point to open up a list of items played for that specific date.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_day">
<div class="graphs-load"><i class="fa fa-refresh fa-spin"></i> Loading chart...</div>
<br>
% else:
<div role="tabpanel" class="tab-pane" id="tabs-1">
% endif
<div class="row">
<div class="col-md-12">
<h4><i class="fa fa-history"></i> Daily <span class="yaxis-text">Play count</span> <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The total play count or duration of tv, movies, and music played per day. Click a graph point to open up a list of items played for that specific date.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_day">
<div class="graphs-load"><i class="fa fa-refresh fa-spin"></i> Loading chart...</div>
<br>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<h4><i class="fa fa-calendar"></i> <span class="yaxis-text">Play count</span> by day of week <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The combined total of tv, movies, and music played per day of the week.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_dayofweek" style="float: left;">
<div class="graphs-load">
<i class="fa fa-refresh fa-spin"></i> Loading chart...
</div>
<br>
</div>
</div>
</div>
<div class="col-md-6">
<h4><i class="fa fa-clock-o"></i> <span class="yaxis-text">Play count</span> by hour of day <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The combined total of tv, movies, and music played per hour of the day.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_hourofday">
<div class="graphs-load">
<i class="fa fa-refresh fa-spin"></i> Loading chart...
</div>
<br>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<h4><i class="fa fa-television"></i> <span class="yaxis-text">Play count</span> by top 10 platforms <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The combined total of tv, movies, and music played by top 10 most active platforms.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_platform" style="float: left;">
<div class="graphs-load">
<i class="fa fa-refresh fa-spin"></i> Loading chart...
</div>
<br>
</div>
</div>
</div>
<div class="col-md-6">
<h4><i class="fa fa-user"></i> <span class="yaxis-text">Play count</span> by top 10 users <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The combined total of tv, movies, and music played by top 10 most active users.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_user">
<div class="graphs-load">
<i class="fa fa-refresh fa-spin"></i> Loading chart...
</div>
<br>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<h4><i class="fa fa-calendar"></i> <span class="yaxis-text">Play count</span> by day of week <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The combined total of tv, movies, and music played per day of the week.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_dayofweek" style="float: left;">
<div class="graphs-load"><i class="fa fa-refresh fa-spin"></i> Loading chart...
</div>
<br>
</div>
</div>
</div>
<div class="col-md-6">
<h4><i class="fa fa-clock-o"></i> <span class="yaxis-text">Play count</span> by hour of day <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The combined total of tv, movies, and music played per hour of the day.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_hourofday">
<div class="graphs-load"><i class="fa fa-refresh fa-spin"></i> Loading chart...
</div>
<br>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<h4><i class="fa fa-television"></i> <span class="yaxis-text">Play count</span> by top 10 platforms <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The combined total of tv, movies, and music played by top 10 most active platforms.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_platform" style="float: left;">
<div class="graphs-load"><i class="fa fa-refresh fa-spin"></i> Loading chart...
</div>
<br>
</div>
</div>
</div>
<div class="col-md-6">
<h4><i class="fa fa-user"></i> <span class="yaxis-text">Play count</span> by top 10 users <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The combined total of tv, movies, and music played by top 10 most active users.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_user">
<div class="graphs-load"><i class="fa fa-refresh fa-spin"></i> Loading chart...
</div>
<br>
</div>
</div>
</div>
</div>
</div>
% if config['graph_tab'] == 'tabs-2':
<div role="tabpanel" class="tab-pane active" id="tabs-2">
% else:
<div role="tabpanel" class="tab-pane" id="tabs-2">
% endif
<div class="row">
<div class="col-md-12">
<h4><i class="fa fa-video-camera"></i> Daily Stream type breakdown <small>Last <span class="days">30</span> days</small></h4>
@@ -189,10 +224,14 @@
</div>
</div>
% if config['graph_tab'] == 'tabs-3':
<div role="tabpanel" class="tab-pane active" id="tabs-3">
% else:
<div role="tabpanel" class="tab-pane" id="tabs-3">
% endif
<div class="row">
<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">
The combined total of tv, movies, and music by month.
</p>
@@ -214,16 +253,18 @@
</%def>
<%def name="javascriptIncludes()">
<script src="interfaces/default/js/moment-with-locale.js"></script>
<script src="interfaces/default/js/moment-duration-format.js"></script>
<script src="interfaces/default/js/highcharts/js/highcharts.js"></script>
<script src="interfaces/default/js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script>
<script src="${http_root}js/moment-with-locale.js"></script>
<script src="${http_root}js/moment-duration-format.js"></script>
<script src="${http_root}js/highcharts/js/highcharts.js"></script>
<script src="${http_root}js/jquery.dataTables.min.js"></script>
<script src="${http_root}js/dataTables.bootstrap.min.js"></script>
<script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
<script>
var selected_user_id = null
// Modal popup dialog
function selectHandler(selectedDate) {
function selectHandler(selectedDate, selectedSeries) {
try
{
@@ -233,10 +274,26 @@
var y = dateValue.getFullYear();
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({
"url": "history_table_modal",
url: "history_table_modal",
type: 'post',
data: { 'start_date': dateString },
data: {
user_id: selected_user_id,
start_date: dateString,
media_type: media_type,
transcode_decision: transcode_decision
},
complete: function(xhr, status) {
$('#history-modal').modal('show');
$("#history-modal").html(xhr.responseText);
@@ -245,79 +302,87 @@
}
catch(err)
{
console.log("Failed to retrieve data");
console.log("Failed to retrieve history modal data.");
}
}
</script>
<script src="interfaces/default/js/graphs/plays_by_day.js"></script>
<script src="interfaces/default/js/graphs/plays_by_dayofweek.js"></script>
<script src="interfaces/default/js/graphs/plays_by_hourofday.js"></script>
<script src="interfaces/default/js/graphs/plays_by_platform.js"></script>
<script src="interfaces/default/js/graphs/plays_by_user.js"></script>
<script src="interfaces/default/js/graphs/plays_by_stream_type.js"></script>
<script src="interfaces/default/js/graphs/plays_by_source_resolution.js"></script>
<script src="interfaces/default/js/graphs/plays_by_stream_resolution.js"></script>
<script src="interfaces/default/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="interfaces/default/js/graphs/plays_by_month.js"></script>
<script src="${http_root}js/graphs/plays_by_day.js"></script>
<script src="${http_root}js/graphs/plays_by_dayofweek.js"></script>
<script src="${http_root}js/graphs/plays_by_hourofday.js"></script>
<script src="${http_root}js/graphs/plays_by_platform.js"></script>
<script src="${http_root}js/graphs/plays_by_user.js"></script>
<script src="${http_root}js/graphs/plays_by_stream_type.js"></script>
<script src="${http_root}js/graphs/plays_by_source_resolution.js"></script>
<script src="${http_root}js/graphs/plays_by_stream_resolution.js"></script>
<script src="${http_root}js/graphs/plays_by_platform_by_stream_type.js"></script>
<script src="${http_root}js/graphs/plays_by_user_by_stream_type.js"></script>
<script src="${http_root}js/graphs/plays_by_month.js"></script>
<script>
$(document).ready(function () {
// Save graph state to cookies
$('input[name=yaxis-options]').change(function() {
setCookie('graphType', $(this).val(), 365, '/');
});
$('input[name=date-options]').change(function() {
setCookie('graphDate', $(this).val(), 365, '/');
});
$('a[data-toggle=tab]').click(function() {
setCookie('graphTab', $(this).attr('href'), 365, '/');
});
// Initial values for graph from config
var yaxis = "${config['graph_type']}";
var current_day_range = ${config['graph_days']};
var current_month_range = ${config['graph_months']};
var current_tab = "${'#' + config['graph_tab']}";
// Initial values for graph if no saved state
var yaxis = 'plays';
var current_range = 30;
var current_tab = '#tabs-1';
// Read saved graph state from cookies and set initial values
if(getCookie('graphType')) {
var yaxis = getCookie('graphType');
$('input[name=yaxis-options][value=' + yaxis + ']').prop('checked', true).trigger('click');
}
if(getCookie('graphDate')) {
var current_range = getCookie('graphDate');
$('input[name=date-options][value=' + current_range + ']').prop('checked', true).trigger('click');
$('.days').html(current_range);
}
if(getCookie('graphTab')) {
var current_tab = getCookie('graphTab');
$('a[data-toggle=tab][href=' + current_tab + ']').trigger('click');
}
$('.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);
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) {
$('#days-selection').show();
$('#months-selection').hide();
setGraphFormat(yaxis);
$.ajax({
url: "get_plays_by_date",
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",
success: function(data) {
var dateArray = [];
for (var i = 0; i < data.categories.length; i++) {
dateArray.push(moment(data.categories[i], 'YYYY-MM-DD').valueOf());
$.each(data.categories, function (i, day) {
dateArray.push(moment(day, 'YYYY-MM-DD').valueOf());
// Highlight the weekend
if ((moment(data.categories[i], 'YYYY-MM-DD').format('ddd') == 'Sat') ||
(moment(data.categories[i], 'YYYY-MM-DD').format('ddd') == 'Sun')) {
if ((moment(day, 'YYYY-MM-DD').format('ddd') == 'Sat') ||
(moment(day, 'YYYY-MM-DD').format('ddd') == 'Sun')) {
hc_plays_by_day_options.xAxis.plotBands.push({
from: i-0.5,
to: i+0.5,
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.xAxis.categories = dateArray;
hc_plays_by_day_options.series = data.series;
@@ -329,9 +394,10 @@
$.ajax({
url: "get_plays_by_dayofweek",
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",
success: function(data) {
if (yaxis === 'duration') { dataSecondsToHours(data); }
hc_plays_by_dayofweek_options.xAxis.categories = data.categories;
hc_plays_by_dayofweek_options.series = data.series;
hc_plays_by_dayofweek_options.series[2].visible = music_visible;
@@ -342,9 +408,10 @@
$.ajax({
url: "get_plays_by_hourofday",
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",
success: function(data) {
if (yaxis === 'duration') { dataSecondsToHours(data); }
hc_plays_by_hourofday_options.xAxis.categories = data.categories;
hc_plays_by_hourofday_options.series = data.series;
hc_plays_by_hourofday_options.series[2].visible = music_visible;
@@ -355,9 +422,10 @@
$.ajax({
url: "get_plays_by_top_10_platforms",
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",
success: function(data) {
if (yaxis === 'duration') { dataSecondsToHours(data); }
hc_plays_by_platform_options.xAxis.categories = data.categories;
hc_plays_by_platform_options.series = data.series;
hc_plays_by_platform_options.series[2].visible = music_visible;
@@ -368,9 +436,10 @@
$.ajax({
url: "get_plays_by_top_10_users",
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",
success: function(data) {
if (yaxis === 'duration') { dataSecondsToHours(data); }
hc_plays_by_user_options.xAxis.categories = data.categories;
hc_plays_by_user_options.series = data.series;
hc_plays_by_user_options.series[2].visible = music_visible;
@@ -380,27 +449,31 @@
}
function loadGraphsTab2(time_range, yaxis) {
$('#days-selection').show();
$('#months-selection').hide();
setGraphFormat(yaxis);
$.ajax({
url: "get_plays_by_stream_type",
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",
success: function(data) {
var dateArray = [];
for (var i = 0; i < data.categories.length; i++) {
dateArray.push(moment(data.categories[i], 'YYYY-MM-DD').valueOf());
$.each(data.categories, function (i, day) {
dateArray.push(moment(day, 'YYYY-MM-DD').valueOf());
// Highlight the weekend
if ((moment(data.categories[i], 'YYYY-MM-DD').format('ddd') == 'Sat') ||
(moment(data.categories[i], 'YYYY-MM-DD').format('ddd') == 'Sun')) {
hc_plays_by_stream_type_options.xAxis.plotBands.push({
if ((moment(day, 'YYYY-MM-DD').format('ddd') == 'Sat') ||
(moment(day, 'YYYY-MM-DD').format('ddd') == 'Sun')) {
hc_plays_by_day_options.xAxis.plotBands.push({
from: i-0.5,
to: i+0.5,
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.xAxis.categories = dateArray;
hc_plays_by_stream_type_options.series = data.series;
@@ -411,9 +484,10 @@
$.ajax({
url: "get_plays_by_source_resolution",
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",
success: function(data) {
if (yaxis === 'duration') { dataSecondsToHours(data); }
hc_plays_by_source_resolution_options.xAxis.categories = data.categories;
hc_plays_by_source_resolution_options.series = data.series;
var hc_plays_by_source_resolution = new Highcharts.Chart(hc_plays_by_source_resolution_options);
@@ -423,9 +497,10 @@
$.ajax({
url: "get_plays_by_stream_resolution",
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",
success: function(data) {
if (yaxis === 'duration') { dataSecondsToHours(data); }
hc_plays_by_stream_resolution_options.xAxis.categories = data.categories;
hc_plays_by_stream_resolution_options.series = data.series;
var hc_plays_by_stream_resolution = new Highcharts.Chart(hc_plays_by_stream_resolution_options);
@@ -435,9 +510,10 @@
$.ajax({
url: "get_stream_type_by_top_10_platforms",
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",
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.series = data.series;
var hc_plays_by_platform_by_stream_type = new Highcharts.Chart(hc_plays_by_platform_by_stream_type_options);
@@ -447,9 +523,10 @@
$.ajax({
url: "get_stream_type_by_top_10_users",
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",
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.series = data.series;
var hc_plays_by_user_by_stream_type = new Highcharts.Chart(hc_plays_by_user_by_stream_type_options);
@@ -457,15 +534,19 @@
});
}
function loadGraphsTab3(yaxis) {
function loadGraphsTab3(time_range, yaxis) {
$('#days-selection').hide();
$('#months-selection').show();
setGraphFormat(yaxis);
$.ajax({
url: "get_plays_per_month",
type: 'get',
data: { y_axis: yaxis },
data: { time_range: time_range, y_axis: yaxis, user_id: selected_user_id },
dataType: "json",
success: function(data) {
if (yaxis === 'duration') { dataSecondsToHours(data); }
hc_plays_by_month_options.yAxis.min = 0;
hc_plays_by_month_options.xAxis.categories = data.categories;
hc_plays_by_month_options.series = data.series;
@@ -476,104 +557,155 @@
}
// Set initial state
loadGraphsTab1(current_range, yaxis);
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); }
// Tab1 opened
$('#graph-tabs a[href="#tabs-1"]').on('shown.bs.tab', function (e) {
e.preventDefault();
current_tab = $(this).attr('href');
$('#days-selection').show();
loadGraphsTab1(current_range, yaxis);
loadGraphsTab1(current_day_range, yaxis);
$.ajax({
url: 'set_graph_config',
data: { graph_tab: current_tab.replace('#','') },
async: true
});
})
// Tab2 opened
$('#graph-tabs a[href="#tabs-2"]').on('shown.bs.tab', function (e) {
e.preventDefault();
current_tab = $(this).attr('href');
$('#days-selection').show();
loadGraphsTab2(current_range, yaxis);
loadGraphsTab2(current_day_range, yaxis);
$.ajax({
url: 'set_graph_config',
data: { graph_tab: current_tab.replace('#','') },
async: true
});
})
// Tab3 opened
$('#graph-tabs a[href="#tabs-3"]').on('shown.bs.tab', function (e) {
e.preventDefault();
current_tab = $(this).attr('href');
$('#days-selection').hide();
console.log('loading....');
loadGraphsTab3(yaxis);
loadGraphsTab3(current_month_range, yaxis);
$.ajax({
url: 'set_graph_config',
data: { graph_tab: current_tab.replace('#','') },
async: true
});
})
// Date range changed
$('#days-selection').on('change', function() {
current_range = $('input[name=date-options]:checked', '#days-selection').val();
if (current_tab == '#tabs-1') { loadGraphsTab1(current_range, yaxis); }
if (current_tab == '#tabs-2') { loadGraphsTab2(current_range, yaxis); }
$('.days').html(current_range);
$('#graph-days').on('change', function() {
current_day_range = Math.round($(this).val());
$(this).val(current_day_range);
if (current_day_range < 1) {
$(this).val(7);
current_day_range = 7;
}
if (current_tab == '#tabs-1') { loadGraphsTab1(current_day_range, yaxis); }
if (current_tab == '#tabs-2') { loadGraphsTab2(current_day_range, yaxis); }
$('.days').html(current_day_range);
$.ajax({
url: 'set_graph_config',
data: { graph_days: current_day_range},
async: true
});
});
// Month range changed
$('#graph-months').on('change', function() {
current_month_range = Math.round($(this).val());
$(this).val(current_month_range);
if (current_month_range < 1) {
$(this).val(12);
current_month_range = 12;
}
if (current_tab == '#tabs-3') { loadGraphsTab3(current_month_range, yaxis); }
$('.months').html(current_month_range);
$.ajax({
url: 'set_graph_config',
data: { graph_months: current_month_range},
async: true
});
});
// 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
$('#yaxis-selection').on('change', function() {
yaxis = $('input[name=yaxis-options]:checked', '#yaxis-selection').val();
if (current_tab == '#tabs-1') { loadGraphsTab1(current_range, yaxis); }
if (current_tab == '#tabs-2') { loadGraphsTab2(current_range, yaxis); }
if (current_tab == '#tabs-3') { loadGraphsTab3(yaxis); }
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); }
$.ajax({
url: 'set_graph_config',
data: { graph_type: yaxis},
async: true
});
});
function setGraphFormat(type) {
if (type === 'plays') {
yaxis_format = function() { return this.value; };
tooltip_format = function() {
if (moment(this.x, 'X').isValid() && (this.x > 946684800)) {
var s = '<b>'+ moment(this.x).format("ddd MMM D") +'</b>';
} else {
var s = '<b>'+ this.x +'</b>';
}
if (this.points.length > 1) {
var total = 0;
$.each(this.points, function(i, point) {
s += '<br/>'+point.series.name+': '+point.y;
total += point.y;
});
s += '<br><b>Total: '+total+'</b>';
} else {
$.each(this.points, function(i, point) {
s += '<br/>'+point.series.name+': '+point.y;
});
}
return s;
}
if (moment(this.x, 'X').isValid() && (this.x > 946684800)) {
var s = '<b>'+ moment(this.x).format('ddd MMM D') +'</b>';
} else {
var s = '<b>'+ this.x +'</b>';
}
if (this.points.length > 1) {
var total = 0;
$.each(this.points, function(i, point) {
s += '<br/>'+point.series.name+': '+point.y;
total += point.y;
});
s += '<br><b>Total: '+total+'</b>';
} else {
$.each(this.points, function(i, point) {
s += '<br/>'+point.series.name+': '+point.y;
});
}
return s;
}
stack_labels_format = function() {
return this.total;
}
return this.total;
}
$('.yaxis-text').html('Play count');
} 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() {
if (moment(this.x, 'X').isValid() && (this.x > 946684800)) {
var s = '<b>'+ moment(this.x).format("ddd MMM D") +'</b>';
} else {
var s = '<b>'+ this.x +'</b>';
}
if (this.points.length > 1) {
var total = 0;
$.each(this.points, function(i, point) {
s += '<br/>'+point.series.name+': '+moment.duration(point.y, 'seconds').format('D [days] H [hrs] m [mins]');
total += point.y;
});
s += '<br/><b>Total: '+moment.duration(total, 'seconds').format('D [days] H [hrs] m [mins]')+'</b>';
} else {
$.each(this.points, function(i, point) {
s += '<br/>'+point.series.name+': '+moment.duration(point.y, 'seconds').format('D [days] H [hrs] m [mins]');
});
}
return s;
}
if (moment(this.x, 'X').isValid() && (this.x > 946684800)) {
var s = '<b>'+ moment(this.x).format('ddd MMM D') +'</b>';
} else {
var s = '<b>'+ this.x +'</b>';
}
if (this.points.length > 1) {
var total = 0;
$.each(this.points, function(i, point) {
s += '<br/>'+point.series.name+': '+moment.duration(point.y, 'hours').format('D [days] H [hrs] m [mins]');
total += point.y;
});
s += '<br/><b>Total: '+moment.duration(total, 'hours').format('D [days] H [hrs] m [mins]')+'</b>';
} else {
$.each(this.points, function(i, point) {
s += '<br/>'+point.series.name+': '+moment.duration(point.y, 'hours').format('D [days] H [hrs] m [mins]');
});
}
return s;
}
stack_labels_format = function() {
var s = moment.duration(this.total, 'seconds').format("H [hrs] m [mins]");
return s;
}
var s = moment.duration(this.total, 'hours').format('H [h] m [m]');
return s;
}
$('.yaxis-text').html('Play duration');
}

View File

@@ -1,41 +1,69 @@
<%inherit file="base.html"/>
<%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.colVis.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css">
<link rel="stylesheet" href="${http_root}css/dataTables.bootstrap.css">
<link rel="stylesheet" href="${http_root}css/dataTables.colVis.css">
<link rel="stylesheet" href="${http_root}css/plexpy-dataTables.css">
</%def>
<%def name="body()">
<div class='container-fluid'>
<div class='table-card-header'>
<div class="header-bar">
<span><i class="fa fa-history"></i> History</span>
</div>
<div class="button-bar">
<div class="colvis-button-bar hidden-xs"></div>
<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>
% if _session['user_group'] == 'admin':
<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 colvis-button-bar"></div>
</div>
</div>
<div class='table-card-back'>
<table class="display" id="history_table" width="100%">
<div class="table-card-back">
<table class="display history_table" id="history_table" width="100%">
<thead>
<tr>
<th align='left' id="delete_row">Delete</th>
<th align='left' id="time">Time</th>
<th align='left' id="friendly_name">User</th>
<th align='left' id="ip_address">IP Address</th>
<th align='left' id="platform">Platform</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>
<th align="left" id="delete_row">Delete</th>
<th align="left" id="time">Time</th>
<th align="left" id="friendly_name">User</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="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>
</thead>
<tbody>
@@ -45,7 +73,7 @@
</div>
<div class="modal fade" id="ip-info-modal" tabindex="-1" role="dialog" aria-labelledby="ip-info-modal">
</div>
<div class="modal fade" id="confirm-modal" tabindex="-1" role="dialog" aria-labelledby="confirm-modal">
<div class="modal fade" id="confirm-modal-delete" tabindex="-1" role="dialog" aria-labelledby="confirm-modal-delete">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
@@ -68,35 +96,76 @@
</%def>
<%def name="javascriptIncludes()">
<script src="interfaces/default/js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.colVis.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script>
<script src="interfaces/default/js/moment-with-locale.js"></script>
<script src="interfaces/default/js/tables/history_table.js"></script>
<script src="${http_root}js/jquery.dataTables.min.js"></script>
<script src="${http_root}js/dataTables.colVis.js"></script>
<script src="${http_root}js/dataTables.bootstrap.min.js"></script>
<script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
<script src="${http_root}js/moment-with-locale.js"></script>
<script src="${http_root}js/tables/history_table.js"></script>
<script>
$(document).ready(function() {
history_table_options.ajax = {
"url": "get_history",
type: "post",
data: function ( d ) {
return { 'json_data': JSON.stringify( d ) };
$(document).ready(function () {
// 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 = {
url: 'get_history',
type: 'post',
data: function (d) {
return {
json_data: JSON.stringify(d),
media_type: media_type,
user_id: selected_user_id
};
}
}
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] });
$(colvis.button()).appendTo('div.colvis-button-bar');
clearSearchButton('history_table', history_table);
$('#media_type-selection').on('change', function () {
$('#media_type-selection > label').removeClass('active');
selected_filter = $('input[name=media_type-filter]:checked', '#media_type-selection');
$(selected_filter).closest('label').addClass('active');
media_type = $(selected_filter).val();
history_table.draw();
});
$('#history-user').on('change', function () {
selected_user_id = $(this).val() || null;
history_table.draw();
});
}
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, 10] });
$(colvis.button()).appendTo('div.colvis-button-bar');
clearSearchButton('history_table', history_table);
var media_type = null;
var selected_user_id = "${_session['user_id']}" == "None" ? null : "${_session['user_id']}"
loadHistoryTable(media_type, selected_user_id);
% if _session['user_group'] == 'admin':
$('#row-edit-mode').on('click', function() {
$('#row-edit-mode-alert').fadeIn(200);
if ($(this).hasClass('active')) {
if (history_to_delete.length > 0) {
$('#deleteCount').text(history_to_delete.length);
$('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-delete', function () {
$('#confirm-modal-delete').modal();
$('#confirm-modal-delete').one('click', '#confirm-delete', function () {
for (var i = 0; i < history_to_delete.length; i++) {
$.ajax({
url: 'delete_history_rows',
@@ -125,6 +194,7 @@
});
}
});
% endif
});
</script>
</%def>

View File

@@ -5,19 +5,19 @@
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
<h4 class="modal-title" id="myModalLabel">
<strong><span id="modal_header_ip_address">
<i class="fa fa-history"></i> History for <span id="date-header">${data}</span>
<i class="fa fa-history"></i> History for <span id="date-header">${data['start_date']}</span>
</span></strong>
</h4>
</div>
<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>
<tr>
<th align='left' id="started">Started</th>
<th align='left' id="stopped">Stopped</th>
<th align='left' id="friendly_name">User</th>
<th align='left' id="platform">Platform</th>
<th align='left' id="title">Title</th>
<th align="left" id="started">Started</th>
<th align="left" id="stopped">Stopped</th>
<th align="left" id="friendly_name">User</th>
<th align="left" id="player">Player</th>
<th align="left" id="title">Title</th>
</tr>
</thead>
<tbody>
@@ -29,24 +29,28 @@
</div>
<div class="modal fade" id="info-modal" tabindex="-1" role="dialog" aria-labelledby="info-modal">
</div>
<script src="interfaces/default/js/tables/history_table_modal.js"></script>
<script src="${http_root}js/tables/history_table_modal.js"></script>
<script>
$(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 = {
"url": "get_history",
type: "post",
url: 'get_history',
type: 'post',
data: function ( d ) {
return { 'json_data': JSON.stringify( d ),
'grouping': false,
'start_date': '${data}'
};
return {
json_data: JSON.stringify(d),
grouping: false,
user_id: "${data['user_id']}",
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_modal_options);
clearSearchButton('history_table', history_table);
clearSearchButton('history_table_modal', history_table);
// Move #info-modal to parent container
if (!($('#history-modal').next().is('#info-modal'))) {

View File

@@ -39,11 +39,16 @@ user_id Returns the user id for the associated stat.
friendly_name Returns the friendly name of the user for the associated stat.
== Only if 'stat_id' is 'top_platform' or 'last_watched' ==
platform_type Returns the platform name for the associated stat.
player Returns the player name for the associated stat.
== Only if 'stat_id' is 'last_watched' ==
last_watch Returns the time the media item was last watched.
== Only if 'stat_id' is 'most_concurrent' ==
count Returns the count of the most concurrent streams.
started Returns the start time of the most concurrent streams.
stopped Returns the stop time of the most concurrent streams.
DOCUMENTATION :: END
</%doc>
@@ -65,8 +70,8 @@ DOCUMENTATION :: END
%>
% if data:
% if data[0]['rows'] or data[1]['rows'] or data[2]['rows'] or data[3]['rows'] or data[4]['rows'] or data[5]['rows']:
<ul class="list-unstyled">
% if any(top_stat['rows'] for top_stat in data):
% for top_stat in data:
% if top_stat['stat_id'] == 'top_tv' and top_stat['rows']:
<div class="home-platforms-instance">
@@ -77,9 +82,13 @@ DOCUMENTATION :: END
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['rating_key']:
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
${top_stat['rows'][0]['title']}
</a>
% else:
${top_stat['rows'][0]['title']}
% endif
</h4>
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][0]['total_plays']}</h3>
@@ -89,31 +98,44 @@ DOCUMENTATION :: END
% endif
</div>
</div>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['rating_key']:
<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>
% if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif
</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 class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
% else:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
% 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:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
<a href="info?item_id=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['rating_key']:
<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>
% else:
${top_stat['rows'][loop.index]['title']}
% endif
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
@@ -125,17 +147,26 @@ DOCUMENTATION :: END
% endif
</div>
</div>
<a href="info?item_id=${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>
% if top_stat['rows'][loop.index]['rating_key']:
<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>
% if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif
</div>
% else:
<div class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
</a>
% 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 class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
</a>
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
@@ -157,39 +188,56 @@ DOCUMENTATION :: END
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['rating_key']:
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
${top_stat['rows'][0]['title']}
</a>
% else:
${top_stat['rows'][0]['title']}
% endif
</h4>
<h3>${top_stat['rows'][0]['users_watched']}</h3>
<p> users</p>
</div>
</div>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['rating_key']:
<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>
% if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif
</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 class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
% else:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
% 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:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
<a href="info?item_id=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['rating_key']:
<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>
% else:
${top_stat['rows'][loop.index]['title']}
% endif
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
@@ -197,17 +245,26 @@ DOCUMENTATION :: END
<p> users</p>
</div>
</div>
<a href="info?item_id=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['rating_key']:
<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>
% if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif
</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 class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
</a>
% else:
<div class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
@@ -229,9 +286,13 @@ DOCUMENTATION :: END
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['rating_key']:
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
${top_stat['rows'][0]['title']}
</a>
% else:
${top_stat['rows'][0]['title']}
% endif
</h4>
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][0]['total_plays']}</h3>
@@ -241,31 +302,44 @@ DOCUMENTATION :: END
% endif
</div>
</div>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['rating_key']:
<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>
% if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif
</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 class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
% else:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
% 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:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
<a href="info?item_id=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['rating_key']:
<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>
% else:
${top_stat['rows'][loop.index]['title']}
% endif
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
@@ -277,17 +351,26 @@ DOCUMENTATION :: END
% endif
</div>
</div>
<a href="info?item_id=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['rating_key']:
<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>
% if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif
</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 class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
</a>
% else:
<div class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
@@ -309,39 +392,56 @@ DOCUMENTATION :: END
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['rating_key']:
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
${top_stat['rows'][0]['title']}
</a>
% else:
${top_stat['rows'][0]['title']}
% endif
</h4>
<h3>${top_stat['rows'][0]['users_watched']}</h3>
<p> users</p>
</div>
</div>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['rating_key']:
<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>
% if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif
</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 class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
% else:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
% 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:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
<a href="info?item_id=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['rating_key']:
<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>
% else:
${top_stat['rows'][loop.index]['title']}
% endif
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
@@ -349,17 +449,26 @@ DOCUMENTATION :: END
<p> users</p>
</div>
</div>
<a href="info?item_id=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['rating_key']:
<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>
% if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif
</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 class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
</a>
% else:
<div class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
@@ -381,9 +490,13 @@ DOCUMENTATION :: END
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['rating_key']:
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
${top_stat['rows'][0]['title']}
</a>
% else:
${top_stat['rows'][0]['title']}
% endif
</h4>
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][0]['total_plays']}</h3>
@@ -393,31 +506,44 @@ DOCUMENTATION :: END
% endif
</div>
</div>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['rating_key']:
<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 class="home-platforms-instance-cover">
<div class="home-platforms-cover-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=300&fallback=cover);"></div>
% if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif
</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 class="home-platforms-instance-cover">
<div class="home-platforms-cover-face" style="background-image: url(${http_root}images/cover.png);"></div>
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
% else:
<div class="home-platforms-instance-cover">
<div class="home-platforms-cover-face" style="background-image: url(${http_root}images/cover.png);"></div>
</div>
% endif
% 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:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
<a href="info?item_id=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['rating_key']:
<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>
% else:
${top_stat['rows'][loop.index]['title']}
% endif
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
@@ -429,17 +555,26 @@ DOCUMENTATION :: END
% endif
</div>
</div>
<a href="info?item_id=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['rating_key']:
<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 class="home-platforms-instance-list-cover">
<div class="home-platforms-list-cover-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=300&fallback=cover);"></div>
% if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif
</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 class="home-platforms-instance-list-cover">
<div class="home-platforms-list-cover-face" style="background-image: url(${http_root}images/cover.png);"></div>
</div>
% endif
</a>
% else:
<div class="home-platforms-instance-list-cover">
<div class="home-platforms-list-cover-face" style="background-image: url(${http_root}images/cover.png);"></div>
</div>
% endif
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
@@ -461,39 +596,56 @@ DOCUMENTATION :: END
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['rating_key']:
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
${top_stat['rows'][0]['title']}
</a>
% else:
${top_stat['rows'][0]['title']}
% endif
</h4>
<h3>${top_stat['rows'][0]['users_watched']}</h3>
<p> users</p>
</div>
</div>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['rating_key']:
<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 class="home-platforms-instance-cover">
<div class="home-platforms-cover-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=300&fallback=cover);"></div>
% if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif
</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 class="home-platforms-instance-cover">
<div class="home-platforms-cover-face" style="background-image: url(${http_root}images/cover.png);"></div>
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
% else:
<div class="home-platforms-instance-cover">
<div class="home-platforms-cover-face" style="background-image: url(${http_root}images/cover.png);"></div>
</div>
% endif
% 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:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
<a href="info?item_id=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['rating_key']:
<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>
% else:
${top_stat['rows'][loop.index]['title']}
% endif
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
@@ -501,17 +653,26 @@ DOCUMENTATION :: END
<p> users</p>
</div>
</div>
<a href="info?item_id=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['rating_key']:
<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 class="home-platforms-instance-list-cover">
<div class="home-platforms-list-cover-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=300&fallback=cover);"></div>
% if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif
</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 class="home-platforms-instance-list-cover">
<div class="home-platforms-list-cover-face" style="background-image: url(${http_root}images/cover.png);"></div>
</div>
% endif
</a>
% else:
<div class="home-platforms-instance-list-cover">
<div class="home-platforms-list-cover-face" style="background-image: url(${http_root}images/cover.png);"></div>
</div>
% endif
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
@@ -535,11 +696,11 @@ DOCUMENTATION :: END
<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>
% else:
${top_stat['rows'][0]['friendly_name']}
% endif
</h4>
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][0]['total_plays']}</h3>
@@ -551,8 +712,6 @@ DOCUMENTATION :: END
</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">
@@ -560,28 +719,30 @@ DOCUMENTATION :: END
</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 class="home-platforms-instance-oval" style="background-image: url(${http_root}images/gravatar-default.png);"></div>
</div>
% endif
% if top_stat['rows'][0]['user_id']:
</a>
%if len(top_stat['rows']) > 1:
% endif
% 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:
% 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>
% else:
${top_stat['rows'][loop.index]['friendly_name']}
% endif
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
@@ -595,8 +756,6 @@ DOCUMENTATION :: END
</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">
@@ -604,10 +763,12 @@ DOCUMENTATION :: END
</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 class="home-platforms-instance-list-oval" style="background-image: url(${http_root}images/gravatar-default.png);"></div>
</div>
% endif
</a>
% if top_stat['rows'][loop.index]['user_id']:
</a>
% endif
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
@@ -639,16 +800,16 @@ DOCUMENTATION :: END
</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']}') + ");'>");
$("#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:
% 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:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
@@ -667,7 +828,7 @@ DOCUMENTATION :: END
</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']}') + ");'>");
$("#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">
@@ -691,85 +852,111 @@ DOCUMENTATION :: END
</div>
<div class="home-platforms-instance-last-user">
<h4>
<a href="info?source=history&item_id=${top_stat['rows'][0]['row_id']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['rating_key']:
<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>
% else:
${top_stat['rows'][0]['title']}
% endif
</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>
% else:
${top_stat['rows'][0]['friendly_name']}
% endif
</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]['platform_type']}
</span> - ${top_stat['rows'][0]['player']}
</p>
</div>
</div>
<a href="info?source=history&item_id=${top_stat['rows'][0]['row_id']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['rating_key']:
<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>
% if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif
</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 class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
% else:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
% 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:
% 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&item_id=${top_stat['rows'][loop.index]['row_id']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['rating_key']:
<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>
% else:
${top_stat['rows'][loop.index]['title']}
% endif
</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>
% else:
${top_stat['rows'][loop.index]['friendly_name']}
% endif
</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]['platform_type']}
</span> - ${top_stat['rows'][loop.index]['player']}
</p>
</div>
</div>
<a href="info?source=history&item_id=${top_stat['rows'][loop.index]['row_id']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['rating_key']:
<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>
% if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif
</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 class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
</a>
% else:
<div class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div>
% endif
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
@@ -782,8 +969,74 @@ DOCUMENTATION :: END
% 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(${http_root}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(${http_root}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>
var topZIndex = 2;
@@ -799,9 +1052,5 @@ DOCUMENTATION :: END
});
</script>
% else:
<div class="text-muted">No stats for selected period.</div><br>
% endif
% else:
<div class="text-muted">Unable to retrieve data from database. Please check your <a href="settings">settings</a>.
</div><br>
<div class="text-muted">No stats to show for the selected period.</div><br>
% endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 873 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 757 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 778 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 928 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 931 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1017 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 990 B

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