diff --git a/plexpy/config.py b/plexpy/config.py index 7b583d8d..6f2926d9 100644 --- a/plexpy/config.py +++ b/plexpy/config.py @@ -177,6 +177,7 @@ _CONFIG_DEFINITIONS = { 'NOTIFY_RECENTLY_ADDED_UPGRADE': (int, 'Monitoring', 0), 'NOTIFY_REMOTE_ACCESS_THRESHOLD': (int, 'Monitoring', 60), 'NOTIFY_CONCURRENT_BY_IP': (int, 'Monitoring', 0), + 'NOTIFY_CONCURRENT_IPV6_CIDR': (str, 'Monitoring', '/64'), 'NOTIFY_CONCURRENT_THRESHOLD': (int, 'Monitoring', 2), 'NOTIFY_NEW_DEVICE_INITIAL_ONLY': (int, 'Monitoring', 1), 'NOTIFY_SERVER_CONNECTION_THRESHOLD': (int, 'Monitoring', 60), @@ -536,7 +537,7 @@ class Config(object): Returns something from the ini unless it is a real property of the configuration object or is not all caps. """ - if not re.match(r'[A-Z_]+$', name): + if not re.match(r'[A-Z0-9_]+$', name): return super(Config, self).__getattr__(name) else: return self.check_setting(name) diff --git a/plexpy/helpers.py b/plexpy/helpers.py index 9cfb9c45..085dfc12 100644 --- a/plexpy/helpers.py +++ b/plexpy/helpers.py @@ -33,6 +33,7 @@ from functools import reduce, wraps import hashlib import imghdr from future.moves.itertools import islice, zip_longest +from ipaddress import ip_address, ip_network, IPv4Address import ipwhois import ipwhois.exceptions import ipwhois.utils @@ -1777,3 +1778,18 @@ def check_watched(media_type, view_offset, duration, marker_credits_first=None, def pms_name(): return plexpy.CONFIG.PMS_NAME_OVERRIDE or plexpy.CONFIG.PMS_NAME + + +def ip_type(ip: str) -> str: + try: + return "IPv4" if type(ip_address(ip)) is IPv4Address else "IPv6" + except ValueError: + return "Invalid" + + +def get_ipv6_network_address(ip: str) -> str: + cidr = "/64" + cidr_pattern = re.compile(r'^/(1([0-1]\d|2[0-8]))$|^/(\d\d)$|^/[1-9]$') + if cidr_pattern.match(plexpy.CONFIG.NOTIFY_CONCURRENT_IPV6_CIDR): + cidr = plexpy.CONFIG.NOTIFY_CONCURRENT_IPV6_CIDR + return str(ip_network(ip+cidr, strict=False).network_address) diff --git a/plexpy/notification_handler.py b/plexpy/notification_handler.py index 7dd81627..8b4b8583 100644 --- a/plexpy/notification_handler.py +++ b/plexpy/notification_handler.py @@ -160,6 +160,7 @@ def add_notifier_each(notifier_id=None, notify_action=None, stream_data=None, ti def notify_conditions(notify_action=None, stream_data=None, timeline_data=None, **kwargs): logger.debug("Tautulli NotificationHandler :: Checking global notification conditions.") + evaluated = False # Activity notifications if stream_data: @@ -187,7 +188,13 @@ def notify_conditions(notify_action=None, stream_data=None, timeline_data=None, user_sessions = [s for s in result['sessions'] if s['user_id'] == stream_data['user_id']] if plexpy.CONFIG.NOTIFY_CONCURRENT_BY_IP: - evaluated = len(Counter(s['ip_address'] for s in user_sessions)) >= plexpy.CONFIG.NOTIFY_CONCURRENT_THRESHOLD + ip_addresses = set() + for s in user_sessions: + if helpers.ip_type(s['ip_address']) == 'IPv6': + ip_addresses.add(helpers.get_ipv6_network_address(s['ip_address'])) + elif helpers.ip_type(s['ip_address']) == 'IPv4': + ip_addresses.add(s['ip_address']) + evaluated = len(ip_addresses) >= plexpy.CONFIG.NOTIFY_CONCURRENT_THRESHOLD else: evaluated = len(user_sessions) >= plexpy.CONFIG.NOTIFY_CONCURRENT_THRESHOLD