Compare commits

...

20 Commits

Author SHA1 Message Date
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
21 changed files with 256 additions and 166 deletions

View File

@@ -1,9 +1,31 @@
# Changelog
## 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.
* Add: Unique identifier to notification options.
* Remove: Media type toggles for recently added notifications.
* Remove: Built in Twitter key and secret.
* Remove: 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
* Fix: 'datestamp' and 'timestamp' for server notifications.
* Change: New method for updating library data in database.
## v1.3.1 (2016-01-23)
@@ -13,8 +35,8 @@
* 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
* Change: Rename "Last Watched" to "Last Played".
* Change: More descriptive libraries updating message.
## v1.3.0 (2016-01-23)

View File

@@ -22,7 +22,7 @@ history_table_options = {
"emptyTable": "No data in table"
},
"pagingType": "bootstrap",
"stateSave": true,
"stateSave": false,
"processing": false,
"serverSide": true,
"pageLength": 25,

View File

@@ -16,7 +16,7 @@ libraries_list_table_options = {
"pageLength": 10,
"order": [ 2, 'asc'],
"autoWidth": true,
"stateSave": true,
"stateSave": false,
"pagingType": "bootstrap",
"columnDefs": [
{

View File

@@ -5,7 +5,7 @@ var log_table_options = {
"pagingType": "bootstrap",
"order": [ 0, 'desc'],
"pageLength": 50,
"stateSave": true,
"stateSave": false,
"language": {
"search":"Search: ",
"lengthMenu":"Show _MENU_ lines per page",

View File

@@ -5,7 +5,7 @@ var plex_log_table_options = {
"pagingType": "bootstrap",
"order": [ 0, 'desc'],
"pageLength": 50,
"stateSave": true,
"stateSave": false,
"language": {
"search":"Search: ",
"lengthMenu":"Show _MENU_ lines per page",

View File

@@ -4,7 +4,7 @@ sync_table_options = {
"pagingType": "bootstrap",
"order": [ [ 0, 'desc'], [ 1, 'asc'], [2, 'asc'] ],
"pageLength": 25,
"stateSave": true,
"stateSave": false,
"language": {
"search":"Search: ",
"lengthMenu":"Show _MENU_ lines per page",

View File

@@ -8,7 +8,7 @@ user_ip_table_options = {
"infoFiltered":"(filtered from _MAX_ total entries)",
"emptyTable": "No data in table",
},
"stateSave": true,
"stateSave": false,
"pagingType": "bootstrap",
"processing": false,
"serverSide": true,

View File

@@ -16,7 +16,7 @@ users_list_table_options = {
"pageLength": 10,
"order": [ 2, 'asc'],
"autoWidth": true,
"stateSave": true,
"stateSave": false,
"pagingType": "bootstrap",
"columnDefs": [
{

View File

@@ -359,6 +359,10 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
</label>
<p class="help-block">Force PlexPy to connect to your Plex Server via SSL. Your server needs to have remote access enabled.</p>
</div>
<input type="hidden" id="pms_identifier" name="pms_identifier" value="${config['pms_identifier']}">
<input type="checkbox" name="server_changed" id="server_changed" value="1" style="display:none">
<div class="padded-header">
<h3>Plex Logs</h3>
</div>
@@ -374,8 +378,6 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
<a href="https://support.plex.tv/hc/en-us/articles/200250417-Plex-Media-Server-Log-Files" target="_blank">Click here</a> for help. This is required if you enable IP logging (for PMS 0.9.12 and below). </p>
</div>
<input type="hidden" id="pms_identifier" name="pms_identifier" value="${config['pms_identifier']}">
<input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully">
</div>
@@ -1072,7 +1074,7 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
<thead>
<tr>
<th>
Server Details
Global
</th>
</tr>
</thead>
@@ -1085,6 +1087,18 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
<td><strong>{server_uptime}</strong></td>
<td>The uptime (in days, hours, mins, secs) of your Plex Server.</td>
</tr>
<tr>
<td><strong>{action}</strong></td>
<td>The action that triggered the notification.</td>
</tr>
<tr>
<td><strong>{datestamp}</strong></td>
<td>The date the notification was triggered.</td>
</tr>
<tr>
<td><strong>{timestamp}</strong></td>
<td>The time the notification was triggered.</td>
</tr>
</tbody>
</table>
<table class="notification-params">
@@ -1100,18 +1114,6 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
<td><strong>{streams}</strong></td>
<td>The number of concurrent streams.</td>
</tr>
<tr>
<td><strong>{action}</strong></td>
<td>The action that triggered the notification.</td>
</tr>
<tr>
<td><strong>{datestamp}</strong></td>
<td>The date the notification was triggered.</td>
</tr>
<tr>
<td><strong>{timestamp}</strong></td>
<td>The time the notification was triggered.</td>
</tr>
<tr>
<td><strong>{user}</strong></td>
<td>The username of the person streaming.</td>
@@ -1128,10 +1130,6 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
<td><strong>{ip_address}</strong></td>
<td>The IP address of the device being used for playback. (PMS 0.9.14 and above)</td>
</tr>
<tr>
<td><strong>{media_type}</strong></td>
<td>The type of media being played (movie, episode, track).</td>
</tr>
<tr>
<td><strong>{stream_duration}</strong></td>
<td>The stream duration (in minutes) for the item.</td>
@@ -1224,6 +1222,10 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
<td><strong>{transcode_audio_channels}</strong></td>
<td>The audio channels of the transcoded media.</td>
</tr>
<tr>
<td><strong>{user_id}</strong></td>
<td>The unique identifier for the user.</td>
</tr>
</tbody>
</table>
<table class="notification-params">
@@ -1235,37 +1237,41 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
</tr>
</thead>
<tbody>
<tr>
<td><strong>{media_type}</strong></td>
<td>The type of media (movie, episode, track).</td>
</tr>
<tr>
<td><strong>{title}</strong></td>
<td>The full title of the item being played.</td>
<td>The full title of the item.</td>
</tr>
<tr>
<td><strong>{library_name}</strong></td>
<td>The library title of the item being played.</td>
<td>The library title of the media item.</td>
</tr>
<tr>
<td><strong>{show_name}</strong></td>
<td>The title of the TV series being played.</td>
<td>The title of the TV series.</td>
</tr>
<tr>
<td><strong>{episode_name}</strong></td>
<td>The title of the episode being played.</td>
<td>The title of the episode.</td>
</tr>
<tr>
<td><strong>{artist_name}</strong></td>
<td>The name of the artist being played.</td>
<td>The name of the artistd.</td>
</tr>
<tr>
<td><strong>{album_name}</strong></td>
<td>The title of the album being played.</td>
<td>The title of the album.</td>
</tr>
<tr>
<td><strong>{track_name}</strong></td>
<td>The title of the track being played.</td>
<td>The title of the track.</td>
</tr>
<tr>
<td><strong>{season_num}</strong></td>
<td>The season number for the media item if item is episode.</td>
<td>The season number for the item if item is episode.</td>
</tr>
<tr>
<td><strong>{season_num00}</strong></td>
@@ -1273,43 +1279,51 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
</tr>
<tr>
<td><strong>{episode_num}</strong></td>
<td>The episode number for the media item if item is episode.</td>
<td>The episode number for the item if item is episode.</td>
</tr>
<tr>
<td><strong>{episode_num00}</strong></td>
<td>The two digit episode number.</td>
</tr>
<tr>
<td><strong>{track_num}</strong></td>
<td>The track number for the item if item is track.</td>
</tr>
<tr>
<td><strong>{track_num00}</strong></td>
<td>The two digit track number.</td>
</tr>
<tr>
<td><strong>{year}</strong></td>
<td>The release year for the media item.</td>
<td>The release year for the item.</td>
</tr>
<tr>
<td><strong>{studio}</strong></td>
<td>The studio for the media item.</td>
<td>The studio for the item.</td>
</tr>
<tr>
<td><strong>{content_rating}</strong></td>
<td>The content rating for the media item. (e.g. TV-MA, TV-PG, etc.)</td>
<td>The content rating for the item. (e.g. TV-MA, TV-PG, etc.)</td>
</tr>
<tr>
<td><strong>{directors}</strong></td>
<td>A list of directors for the media item.</td>
<td>A list of directors for the item.</td>
</tr>
<tr>
<td><strong>{writers}</strong></td>
<td>A list of writers for the media item.</td>
<td>A list of writers for the item.</td>
</tr>
<tr>
<td><strong>{actors}</strong></td>
<td>A list of actors for the media item.</td>
<td>A list of actors for the item.</td>
</tr>
<tr>
<td><strong>{genres}</strong></td>
<td>A list of genres for the media item.</td>
<td>A list of genres for the item.</td>
</tr>
<tr>
<td><strong>{summary}</strong></td>
<td>A short plot summary for the media item.</td>
<td>A short plot summary for the item.</td>
</tr>
<tr>
<td><strong>{tagline}</strong></td>
@@ -1323,6 +1337,22 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
<td><strong>{duration}</strong></td>
<td>The duration (in minutes) for the item.</td>
</tr>
<tr>
<td><strong>{section_id}</strong></td>
<td>The unique identifier for the library.</td>
</tr>
<tr>
<td><strong>{rating_key}</strong></td>
<td>The unique identifier for the item.</td>
</tr>
<tr>
<td><strong>{parent_rating_key}</strong></td>
<td>The unique identifier for the item's parent (season or album).</td>
</tr>
<tr>
<td><strong>{grandparent_rating_key}</strong></td>
<td>The unique identifier for the item's grandparent (TV show or artist).</td>
</tr>
</tbody>
</table>
</div>
@@ -1534,6 +1564,7 @@ $(document).ready(function() {
serverChanged = true;
$("#pms_identifier").val("");
$("#pms-verify-status").html("");
$("#server_changed").prop('checked', true);
verifyServer();
});

View File

@@ -169,6 +169,7 @@ from plexpy import common
<input type="checkbox" name="launch_browser" id="launch_browser" value="1" ${config['launch_browser']}>
<input type="checkbox" name="refresh_users_on_startup" id="refresh_users_on_startup" value="1" ${config['refresh_users_on_startup']}>
<input type="checkbox" name="refresh_libraries_on_startup" id="refresh_libraries_on_startup" value="1" ${config['refresh_libraries_on_startup']}>
<input type="checkbox" name="server_changed" id="server_changed" value="1" checked>
<input type="checkbox" name="first_run_complete" id="first_run_complete" value="1" checked>
<input type="checkbox" name="check_github" id="check_github" value="1" checked>
<input type="text" name="home_stats_cards" id="home_stats_cards" value="first_run_wizard">

View File

@@ -176,7 +176,7 @@ def initialize(config_file):
plextv.refresh_users()
# Refresh the libraries list on startup
if CONFIG.PMS_TOKEN and CONFIG.REFRESH_LIBRARIES_ON_STARTUP:
if CONFIG.PMS_IP and CONFIG.PMS_TOKEN and CONFIG.REFRESH_LIBRARIES_ON_STARTUP:
pmsconnect.refresh_libraries()
# Store the original umask
@@ -282,7 +282,7 @@ def initialize_scheduler():
else:
seconds = 0
if CONFIG.PMS_IP and CONFIG.PMS_TOKEN and CONFIG.UPDATE_SECTION_IDS != -1:
if CONFIG.PMS_IP and CONFIG.PMS_TOKEN:
schedule_job(plextv.get_real_pms_url, 'Refresh Plex Server URLs',
hours=12, minutes=0, seconds=0)
schedule_job(pmsconnect.get_server_friendly_name, 'Refresh Plex Server Name',
@@ -739,7 +739,7 @@ def dbcheck():
'ALTER TABLE library_sections_temp RENAME TO library_sections'
)
except sqlite3.OperationalError:
logger.debug(u"Unable to remove section_id unique constraint from library_sections.")
logger.warn(u"Unable to remove section_id unique constraint from library_sections.")
try:
c_db.execute(
'DROP TABLE library_sections_temp'
@@ -747,6 +747,17 @@ def dbcheck():
except:
pass
# Upgrade library_sections table from earlier versions (remove duplicated libraries)
try:
result = c_db.execute('SELECT * FROM library_sections WHERE server_id = ""')
if result.rowcount > 0:
logger.debug(u"Altering database. Removing duplicate libraries from library_sections table.")
c_db.execute(
'DELETE FROM library_sections WHERE server_id = ""'
)
except sqlite3.OperationalError:
logger.warn(u"Unable to remove duplicate libraries from library_sections table.")
# Upgrade users table from earlier versions (remove UNIQUE constraint on username)
try:
result = c_db.execute('PRAGMA index_xinfo("sqlite_autoindex_users_2")')
@@ -773,7 +784,7 @@ def dbcheck():
'ALTER TABLE users_temp RENAME TO users'
)
except sqlite3.OperationalError:
logger.debug(u"Unable to remove username unique constraint from users.")
logger.warn(u"Unable to remove username unique constraint from users.")
try:
c_db.execute(
'DROP TABLE users_temp'

View File

@@ -156,8 +156,8 @@ class ActivityHandler(object):
(self.get_session_key(), buffer_last_triggered))
time_since_last_trigger = int(time.time()) - int(buffer_last_triggered)
if current_buffer_count >= plexpy.CONFIG.BUFFER_THRESHOLD and time_since_last_trigger == 0 or \
time_since_last_trigger >= plexpy.CONFIG.BUFFER_WAIT:
if plexpy.CONFIG.BUFFER_THRESHOLD > 0 and (current_buffer_count >= plexpy.CONFIG.BUFFER_THRESHOLD and \
time_since_last_trigger == 0 or time_since_last_trigger >= plexpy.CONFIG.BUFFER_WAIT):
ap.set_session_buffer_trigger_time(session_key=self.get_session_key())
threading.Thread(target=notification_handler.notify,
kwargs=dict(stream_data=db_stream, notify_action='buffer')).start()

View File

@@ -360,9 +360,10 @@ _CONFIG_DEFINITIONS = {
'TV_NOTIFY_ON_STOP': (int, 'Monitoring', 0),
'TV_NOTIFY_ON_PAUSE': (int, 'Monitoring', 0),
'TWITTER_ENABLED': (int, 'Twitter', 0),
'TWITTER_PASSWORD': (str, 'Twitter', ''),
'TWITTER_PREFIX': (str, 'Twitter', 'PlexPy'),
'TWITTER_USERNAME': (str, 'Twitter', ''),
'TWITTER_ACCESS_TOKEN': (str, 'Twitter', ''),
'TWITTER_ACCESS_TOKEN_SECRET': (str, 'Twitter', ''),
'TWITTER_CONSUMER_KEY': (str, 'Twitter', ''),
'TWITTER_CONSUMER_SECRET': (str, 'Twitter', ''),
'TWITTER_ON_PLAY': (int, 'Twitter', 0),
'TWITTER_ON_STOP': (int, 'Twitter', 0),
'TWITTER_ON_PAUSE': (int, 'Twitter', 0),

View File

@@ -14,9 +14,9 @@
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
from plexpy import logger, database, helpers, common
import plexpy
import datetime
import locale
class Graphs(object):
@@ -321,7 +321,7 @@ class Graphs(object):
dt = datetime.datetime(*month_item[:6])
date_string = dt.strftime('%Y-%m')
categories.append(dt.strftime('%b %Y').decode(locale.getlocale()[1]))
categories.append(dt.strftime('%b %Y').decode(plexpy.SYS_ENCODING, 'replace'))
series_1_value = 0
series_2_value = 0
series_3_value = 0

View File

@@ -22,8 +22,6 @@ def update_section_ids():
plexpy.CONFIG.UPDATE_SECTION_IDS = -1
logger.info(u"PlexPy Libraries :: Updating section_id's in database.")
#logger.debug(u"PlexPy Libraries :: Disabling monitoring while update in progress.")
#plexpy.schedule_job(activity_pinger.check_active_sessions, 'Check for active sessions',
# hours=0, minutes=0, seconds=0)
@@ -35,7 +33,8 @@ def update_section_ids():
monitor_db = database.MonitorDatabase()
try:
query = 'SELECT id, rating_key FROM session_history_metadata WHERE section_id IS NULL'
query = 'SELECT id, rating_key, grandparent_rating_key, media_type ' \
'FROM session_history_metadata WHERE section_id IS NULL'
history_results = monitor_db.select(query=query)
query = 'SELECT section_id, section_type FROM library_sections'
library_results = monitor_db.select(query=query)
@@ -43,13 +42,20 @@ def update_section_ids():
logger.warn(u"PlexPy Libraries :: Unable to execute database query for update_section_ids: %s." % e)
logger.warn(u"PlexPy Libraries :: Unable to update section_id's in database.")
plexpy.CONFIG.__setattr__('UPDATE_SECTION_IDS', 1)
plexpy.CONFIG.UPDATE_SECTION_IDS = 1
plexpy.CONFIG.write()
#logger.debug(u"PlexPy Libraries :: Re-enabling monitoring.")
#plexpy.initialize_scheduler()
return None
if not history_results:
plexpy.CONFIG.UPDATE_SECTION_IDS = 0
plexpy.CONFIG.write()
return None
logger.info(u"PlexPy Libraries :: Updating section_id's in database.")
# Add thread filter to the logger
#logger.debug(u"PlexPy Libraries :: Disabling logging in the current thread while update in progress.")
#thread_filter = logger.NoThreadFilter(threading.current_thread().name)
@@ -58,38 +64,35 @@ def update_section_ids():
# Get rating_key: section_id mapping pairs
key_mappings = {}
section_type_child = {'movie': 'movie',
'show': 'episode',
'artist': 'track'}
pms_connect = pmsconnect.PmsConnect()
for library in library_results:
section_id = library['section_id']
section_type = section_type_child.get(library['section_type'], None)
section_type = library['section_type']
if section_type:
if section_type != 'photo':
library_children = pms_connect.get_library_children_details(section_id=section_id,
section_type=section_type)
else:
continue
if library_children:
children_list = library_children['childern_list']
key_mappings.update({child['rating_key']:child['section_id'] for child in children_list})
else:
logger.warn(u"PlexPy Libraries :: Unable to get a list of library items for section_id %s." % section_id)
if library_children:
children_list = library_children['childern_list']
key_mappings.update({child['rating_key']:child['section_id'] for child in children_list})
else:
logger.warn(u"PlexPy Libraries :: Unable to get a list of library items for section_id %s." % section_id)
error_keys = set()
for item in history_results:
rating_key = item['rating_key']
rating_key = item['grandparent_rating_key'] if item['media_type'] != 'movie' else item['rating_key']
section_id = key_mappings.get(str(rating_key), None)
if section_id:
section_keys = {'id': item['id']}
section_values = {'section_id': section_id}
monitor_db.upsert('session_history_metadata', key_dict=section_keys, value_dict=section_values)
try:
section_keys = {'id': item['id']}
section_values = {'section_id': section_id}
monitor_db.upsert('session_history_metadata', key_dict=section_keys, value_dict=section_values)
except:
error_keys.add(item['rating_key'])
else:
error_keys.add(rating_key)
error_keys.add(item['rating_key'])
# Remove thread filter from the logger
#for handler in logger.logger.handlers:
@@ -102,7 +105,7 @@ def update_section_ids():
else:
logger.info(u"PlexPy Libraries :: Updated all section_id's in database.")
plexpy.CONFIG.__setattr__('UPDATE_SECTION_IDS', 0)
plexpy.CONFIG.UPDATE_SECTION_IDS = 0
plexpy.CONFIG.write()
#logger.debug(u"PlexPy Libraries :: Re-enabling monitoring.")
@@ -574,11 +577,10 @@ class Libraries(object):
return library_details
else:
logger.warn(u"PlexPy Libraries :: Unable to retrieve library from local database. Requesting library list refresh.")
# Let's first refresh the user list to make sure the user isn't newly added and not in the db yet
# Let's first refresh the libraries list to make sure the library isn't newly added and not in the db yet
pmsconnect.refresh_libraries()
try:
if section_id:
# Refresh libraries
pmsconnect.refresh_libraries()
query = 'SELECT section_id, section_name, section_type, count, parent_count, child_count, ' \
'thumb AS library_thumb, custom_thumb_url AS custom_thumb, art, ' \
'do_notify, do_notify_created, keep_history ' \

View File

@@ -211,23 +211,17 @@ def notify(stream_data=None, notify_action=None):
def notify_timeline(timeline_data=None, notify_action=None):
if timeline_data and notify_action:
if (timeline_data['media_type'] == 'movie' and plexpy.CONFIG.MOVIE_NOTIFY_ENABLE) \
or ((timeline_data['media_type'] == 'show' or timeline_data['media_type'] == 'episode') \
and plexpy.CONFIG.TV_NOTIFY_ENABLE) \
or ((timeline_data['media_type'] == 'artist' or timeline_data['media_type'] == 'track') \
and plexpy.CONFIG.MUSIC_NOTIFY_ENABLE):
for agent in notifiers.available_notification_agents():
if agent['on_created'] and notify_action == 'created':
# Build and send notification
notify_strings = build_notify_text(timeline=timeline_data, state=notify_action)
notifiers.send_notification(config_id=agent['id'],
subject=notify_strings[0],
body=notify_strings[1],
notify_action=notify_action,
script_args=notify_strings[2])
# Set the notification state in the db
set_notify_state(session=timeline_data, state=notify_action, agent_info=agent)
for agent in notifiers.available_notification_agents():
if agent['on_created'] and notify_action == 'created':
# Build and send notification
notify_strings = build_notify_text(timeline=timeline_data, state=notify_action)
notifiers.send_notification(config_id=agent['id'],
subject=notify_strings[0],
body=notify_strings[1],
notify_action=notify_action,
script_args=notify_strings[2])
# Set the notification state in the db
set_notify_state(session=timeline_data, state=notify_action, agent_info=agent)
elif not timeline_data and notify_action:
for agent in notifiers.available_notification_agents():
@@ -462,6 +456,7 @@ def build_notify_text(session=None, timeline=None, state=None):
transcode_video_height = ''
transcode_audio_codec = ''
transcode_audio_channels = ''
user_id = ''
# Session values
if session:
@@ -504,6 +499,7 @@ def build_notify_text(session=None, timeline=None, state=None):
transcode_video_height = session['transcode_height']
transcode_audio_codec = session['transcode_audio_codec']
transcode_audio_channels = session['transcode_audio_channels']
user_id = session['user_id']
progress_percent = helpers.get_percent(view_offset, duration)
@@ -523,10 +519,10 @@ def build_notify_text(session=None, timeline=None, state=None):
available_params = {'server_name': server_name,
'server_uptime': server_uptime,
'streams': stream_count,
'action': state,
'datestamp': arrow.now().format(plexpy.CONFIG.DATE_FORMAT.replace('Do','').replace('zz','')),
'timestamp': arrow.now().format(plexpy.CONFIG.TIME_FORMAT.replace('Do','').replace('zz','')),
'streams': stream_count,
'user': user,
'platform': platform,
'player': player,
@@ -555,6 +551,7 @@ def build_notify_text(session=None, timeline=None, state=None):
'transcode_video_height': transcode_video_height,
'transcode_audio_codec': transcode_audio_codec,
'transcode_audio_channels': transcode_audio_channels,
'user_id': user_id,
'title': full_title,
'library_name': metadata['library_name'],
'show_name': show_name,
@@ -566,6 +563,8 @@ def build_notify_text(session=None, timeline=None, state=None):
'season_num00': metadata['parent_media_index'].zfill(2),
'episode_num': metadata['media_index'].zfill(1),
'episode_num00': metadata['media_index'].zfill(2),
'track_num': metadata['media_index'].zfill(1),
'track_num00': metadata['media_index'].zfill(2),
'year': metadata['year'],
'studio': metadata['studio'],
'content_rating': metadata['content_rating'],
@@ -576,7 +575,11 @@ def build_notify_text(session=None, timeline=None, state=None):
'summary': metadata['summary'],
'tagline': metadata['tagline'],
'rating': metadata['rating'],
'duration': duration
'duration': duration,
'section_id': metadata['section_id'],
'rating_key': metadata['rating_key'],
'parent_rating_key': metadata['parent_rating_key'],
'grandparent_rating_key': metadata['grandparent_rating_key']
}
# Default subject text
@@ -585,10 +588,6 @@ def build_notify_text(session=None, timeline=None, state=None):
# Default scripts args
script_args = []
# Regex to match {param} but not "{param}"
params_to_quote = re.compile(r'(?<!\")([\{][^}]+[\}])(?!\"\})')
script_args_text = re.sub(params_to_quote, r'"\g<0>"', script_args_text)
if script_args_text:
try:
script_args = [unicode(arg).format(**available_params) for arg in script_args_text.split()]
@@ -804,10 +803,6 @@ def build_server_notify_text(state=None):
# Default scripts args
script_args = []
# Regex to match {param} but not "{param}"
params_to_quote = re.compile(r'(?<!\")([\{][^}]+[\}])(?!\"\})')
script_args_text = re.sub(params_to_quote, r'"\g<0>"', script_args_text)
if script_args_text:
try:
script_args = [unicode(arg).format(**available_params) for arg in script_args_text.split()]

View File

@@ -1165,8 +1165,10 @@ class TwitterNotifier(object):
SIGNIN_URL = 'https://api.twitter.com/oauth/authenticate'
def __init__(self):
self.consumer_key = "2LdJKXHDUwJtjYBsdwJisIOsh"
self.consumer_secret = "QWbUcZzAIiL4zbDCIhy2EdUkV8yEEav3qMdo5y3FugxCFelWrA"
self.access_token = plexpy.CONFIG.TWITTER_ACCESS_TOKEN
self.access_token_secret = plexpy.CONFIG.TWITTER_ACCESS_TOKEN_SECRET
self.consumer_key = plexpy.CONFIG.TWITTER_CONSUMER_KEY
self.consumer_secret = plexpy.CONFIG.TWITTER_CONSUMER_SECRET
def notify(self, subject, message):
if not subject or not message:
@@ -1191,16 +1193,16 @@ class TwitterNotifier(object):
else:
request_token = dict(parse_qsl(content))
plexpy.CONFIG.TWITTER_USERNAME = request_token['oauth_token']
plexpy.CONFIG.TWITTER_PASSWORD = request_token['oauth_token_secret']
plexpy.CONFIG.TWITTER_ACCESS_TOKEN = request_token['oauth_token']
plexpy.CONFIG.TWITTER_ACCESS_TOKEN_SECRET = request_token['oauth_token_secret']
return self.AUTHORIZATION_URL + "?oauth_token=" + request_token['oauth_token']
def _get_credentials(self, key):
request_token = {}
request_token['oauth_token'] = plexpy.CONFIG.TWITTER_USERNAME
request_token['oauth_token_secret'] = plexpy.CONFIG.TWITTER_PASSWORD
request_token['oauth_token'] = plexpy.CONFIG.TWITTER_ACCESS_TOKEN
request_token['oauth_token_secret'] = plexpy.CONFIG.TWITTER_ACCESS_TOKEN_SECRET
request_token['oauth_callback_confirmed'] = 'true'
token = oauth.Token(request_token['oauth_token'], request_token['oauth_token_secret'])
@@ -1225,20 +1227,20 @@ class TwitterNotifier(object):
else:
# logger.info(u"PlexPy Notifiers :: Your Twitter Access Token key: %s" % access_token['oauth_token'])
# logger.info(u"PlexPy Notifiers :: Access Token secret: %s" % access_token['oauth_token_secret'])
plexpy.CONFIG.TWITTER_USERNAME = access_token['oauth_token']
plexpy.CONFIG.TWITTER_PASSWORD = access_token['oauth_token_secret']
plexpy.CONFIG.TWITTER_ACCESS_TOKEN = access_token['oauth_token']
plexpy.CONFIG.TWITTER_ACCESS_TOKEN_SECRET = access_token['oauth_token_secret']
plexpy.CONFIG.write()
return True
def _send_tweet(self, message=None):
username = self.consumer_key
password = self.consumer_secret
access_token_key = plexpy.CONFIG.TWITTER_USERNAME
access_token_secret = plexpy.CONFIG.TWITTER_PASSWORD
consumer_key = self.consumer_key
consumer_secret = self.consumer_secret
access_token = self.access_token
access_token_secret = self.access_token_secret
# logger.info(u"PlexPy Notifiers :: Sending tweet: " + message)
api = twitter.Api(username, password, access_token_key, access_token_secret)
api = twitter.Api(consumer_key, consumer_secret, access_token, access_token_secret)
try:
api.PostUpdate(message)
@@ -1251,30 +1253,37 @@ class TwitterNotifier(object):
def return_config_options(self):
config_option = [{'label': 'Instructions',
'description': 'Step 1: Click the <strong>Request Authorization</strong> button below.<br>\
Step 2: Input the <strong>Authorization Key</strong> you received from Step 1 below.<br>\
Step 3: Click the <strong>Verify Key</strong> button below.',
'description': 'Step 1: Visit <a href="https://apps.twitter.com/" target="_blank"> \
Twitter Apps</a> to <strong>Create New App</strong>. A vaild "Website" is not required.<br>\
Step 2: Go to <strong>Keys and Access Tokens</strong> and click \
<strong>Create my access token</strong>.<br>\
Step 3: Fill in the <strong>Consumer Key</strong>, <strong>Consumer Secret</strong>, \
<strong>Access Token</strong>, and <strong>Access Token Secret</strong> below.',
'input_type': 'help'
},
{'label': 'Request Authorization',
'value': 'Request Authorization',
'name': 'twitterStep1',
'description': 'Request Twitter authorization. (Ensure you allow the browser pop-up).',
'input_type': 'button'
},
{'label': 'Authorization Key',
'value': '',
'name': 'twitter_key',
'description': 'Your Twitter authorization key.',
{'label': 'Twitter Consumer Key',
'value': self.consumer_key,
'name': 'twitter_consumer_key',
'description': 'Your Twitter consumer key.',
'input_type': 'text'
},
{'label': 'Verify Key',
'value': 'Verify Key',
'name': 'twitterStep2',
'description': 'Verify your Twitter authorization key.',
'input_type': 'button'
{'label': 'Twitter Consumer Secret',
'value': self.consumer_secret,
'name': 'twitter_consumer_secret',
'description': 'Your Twitter consumer secret.',
'input_type': 'text'
},
{'input_type': 'nosave'
{'label': 'Twitter Access Token',
'value': self.access_token,
'name': 'twitter_access_token',
'description': 'Your Twitter access token.',
'input_type': 'text'
},
{'label': 'Twitter Access Token Secret',
'value': self.access_token_secret,
'name': 'twitter_access_token_secret',
'description': 'Your Twitter access token secret.',
'input_type': 'text'
}
]
@@ -1668,10 +1677,10 @@ class TELEGRAM(object):
'description': 'Your Telegram bot token. Contact <a href="http://telegram.me/BotFather" target="_blank">@BotFather</a> on Telegram to get one.',
'input_type': 'text'
},
{'label': 'Telegram Chat ID',
{'label': 'Telegram Chat ID, Group ID, or Channel Username',
'value': self.chat_id,
'name': 'telegram_chat_id',
'description': 'Your Telegram Chat ID, Group ID, or channel username. Contact <a href="http://telegram.me/myidbot" target="_blank">@myidbot</a> on Telegram to get an ID.',
'description': 'Your Telegram Chat ID, Group ID, or @channelusername. Contact <a href="http://telegram.me/myidbot" target="_blank">@myidbot</a> on Telegram to get an ID.',
'input_type': 'text'
}
]
@@ -2088,12 +2097,16 @@ class FacebookNotifier(object):
config_option = [{'label': 'Instructions',
'description': '<strong>Facebook notifications are currently experimental!</strong><br><br> \
Step 1: Visit <a href="https://developers.facebook.com/apps/" target="_blank"> \
Facebook Developers</a> to create a new app using <strong>advanced setup</strong>.<br>\
Step 2: Go to <strong>Settings > Advanced</strong> and fill in \
Facebook Developers</a> to add a new app using <strong>basic setup</strong>.<br>\
Step 2: Go to <strong>Settings > Basic</strong> and fill in a \
<strong>Contact Email</strong>.<br>\
Step 3: Go to <strong>Settings > Advanced</strong> and fill in \
<strong>Valid OAuth redirect URIs</strong> with your PlexPy URL (i.e. http://localhost:8181).<br>\
Step 3: Fill in the <strong>PlexPy URL</strong> below with the exact same URL from Step 2.<br>\
Step 4: Fill in the <strong>App ID</strong> and <strong>App Secret</strong> below.<br>\
Step 5: Click the <strong>Request Authorization</strong> button below.',
Step 4: Go to <strong>App Review</strong> and toggle public to <strong>Yes</strong>.<br>\
Step 5: Fill in the <strong>PlexPy URL</strong> below with the exact same URL from Step 3.<br>\
Step 6: Fill in the <strong>App ID</strong> and <strong>App Secret</strong> below.<br>\
Step 7: Click the <strong>Request Authorization</strong> button below.<br> \
Step 8: Fill in the <strong>Group ID</strong> below.',
'input_type': 'help'
},
{'label': 'PlexPy URL',

View File

@@ -40,15 +40,19 @@ def get_server_friendly_name():
def refresh_libraries():
logger.info(u"PlexPy Pmsconnect :: Requesting libraries list refresh...")
library_sections = PmsConnect().get_library_details()
server_id = plexpy.CONFIG.PMS_IDENTIFIER
if not server_id:
logger.error(u"PlexPy Pmsconnect :: No PMS identifier, cannot refresh libraries. Verify server in settings.")
return
library_keys = []
library_sections = PmsConnect().get_library_details()
if library_sections:
monitor_db = database.MonitorDatabase()
library_keys = []
for section in library_sections:
section_keys = {'server_id': server_id,
'section_id': section['section_id']}
@@ -1690,8 +1694,8 @@ class PmsConnect(object):
section_id = library['section_id']
children_list = self.get_library_children_details(section_id=section_id, section_type=section_type, count='1')
if children_list and children_list['library_count'] != '0':
library_stats = {'section_id': library['section_id'],
if children_list:
library_stats = {'section_id': section_id,
'section_name': library['section_name'],
'section_type': section_type,
'thumb': library['thumb'],

View File

@@ -292,10 +292,9 @@ class Users(object):
else:
logger.warn(u"PlexPy Users :: Unable to retrieve user from local database. Requesting user list refresh.")
# Let's first refresh the user list to make sure the user isn't newly added and not in the db yet
plextv.refresh_users()
try:
if str(user_id).isdigit():
# Refresh users
plextv.refresh_users()
query = 'SELECT user_id, username, friendly_name, thumb AS user_thumb, custom_avatar_url AS custom_thumb, ' \
'email, is_home_user, is_allow_sync, is_restricted, do_notify, keep_history ' \
'FROM users ' \

View File

@@ -1,2 +1,2 @@
PLEXPY_VERSION = "master"
PLEXPY_RELEASE_VERSION = "1.3.2"
PLEXPY_RELEASE_VERSION = "1.3.4"

View File

@@ -1151,6 +1151,7 @@ class WebInterface(object):
del kwargs[use_config]
# Check if we should refresh our data
server_changed = False
refresh_libraries = False
refresh_users = False
reschedule = False
@@ -1173,11 +1174,6 @@ class WebInterface(object):
(kwargs['monitor_remote_access'] != plexpy.CONFIG.MONITOR_REMOTE_ACCESS):
reschedule = True
if 'pms_ip' in kwargs:
if kwargs['pms_ip'] != plexpy.CONFIG.PMS_IP:
refresh_libraries = True
refresh_users = True
# Remove config with 'hscard-' prefix and change home_stats_cards to list
if 'home_stats_cards' in kwargs:
for k in kwargs.keys():
@@ -1198,16 +1194,24 @@ class WebInterface(object):
if kwargs['home_library_cards'] == ['first_run_wizard']:
refresh_libraries = True
if 'server_changed' in kwargs:
del kwargs['server_changed']
server_changed = True
refresh_users = True
refresh_libraries = True
plexpy.CONFIG.process_kwargs(kwargs)
# Write the config
plexpy.CONFIG.write()
# Get new server URLs for SSL communications.
plextv.get_real_pms_url()
if server_changed:
plextv.get_real_pms_url()
# Get new server friendly name.
pmsconnect.get_server_friendly_name()
if server_changed:
pmsconnect.get_server_friendly_name()
# Reconfigure scheduler if intervals changed
if reschedule:
@@ -1378,9 +1382,16 @@ class WebInterface(object):
@cherrypy.expose
def get_server_id(self, hostname=None, port=None, identifier=None, ssl=0, remote=0, **kwargs):
from plexpy import http_handler
if not identifier:
plex_tv = plextv.PlexTV()
servers = plex_tv.discover()
if hostname and port:
for server in servers:
if server['ip'] == hostname and server['port'] == port:
identifier = server['clientIdentifier']
break
if identifier and hostname and port:
# Set PMS attributes to get the real PMS url
plexpy.CONFIG.__setattr__('PMS_IP', hostname)
plexpy.CONFIG.__setattr__('PMS_PORT', port)