| 1 |  |  | from plugin.core.constants import GUID_SERVICES | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  | from plugin.managers.core.base import Get, Update | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | from plugin.modules.core.manager import ModuleManager | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  | from plugin.scrobbler.core.session_prefix import SessionPrefix | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | from oem.media.show import EpisodeIdentifier, EpisodeMatch | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  | from plex_metadata import Metadata, Guid | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  | import logging | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | import math | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  | log = logging.getLogger(__name__) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  | class Base(object): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |     def build_session_key(cls, session_key): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |         if type(session_key) is str: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |             return session_key | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |         # Prepend session prefix | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |         session_prefix = SessionPrefix.get() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |         return '%s:%s' % ( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |             session_prefix, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |             session_key | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |         ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  | class GetSession(Get, Base): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  |     pass | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  | class UpdateSession(Update, Base): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |     def get_account(result): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |         # Try retrieve account from client | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |         client = result.get('client') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |         try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |             client_account_id = client.account_id if client else None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |         except KeyError: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |             client_account_id = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |         if client_account_id: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |             # Valid account found | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |             return client_account_id | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |         # Try retrieve account from user | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |         user = result.get('user') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |         try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |             user_account_id = user.account_id if user else None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |         except KeyError: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |             user_account_id = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |         if user_account_id: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |             # Valid account found | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |             return user_account_id | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |         return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |     def get_metadata(rating_key): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |         # Retrieve metadata for `rating_key` | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |         try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |             metadata = Metadata.get(rating_key) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |         except NotImplementedError, e: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |             log.debug('%r, ignoring session', e.message) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |             return None, None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |         # Ensure metadata was returned | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |         if not metadata: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |             return None, None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |         # Validate metadata | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |         if metadata.type not in ['movie', 'episode']: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |             log.info('Ignoring metadata with type %r for rating_key %r', metadata.type, rating_key) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |             return metadata, None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |         # Parse guid | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |         guid = Guid.parse(metadata.guid, strict=True) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |         return metadata, guid | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 84 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 85 |  |  |     @classmethod | 
            
                                                                        
                            
            
                                    
            
            
                | 86 |  |  |     def match_parts(cls, p_metadata, guid, view_offset): | 
            
                                                                        
                            
            
                                    
            
            
                | 87 |  |  |         if p_metadata.type != 'episode': | 
            
                                                                        
                            
            
                                    
            
            
                | 88 |  |  |             # TODO support multi-part movies | 
            
                                                                        
                            
            
                                    
            
            
                | 89 |  |  |             return 1, 1, p_metadata.duration | 
            
                                                                        
                            
            
                                    
            
            
                | 90 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 91 |  |  |         # Retrieve number of parts | 
            
                                                                        
                            
            
                                    
            
            
                | 92 |  |  |         if guid.service in GUID_SERVICES: | 
            
                                                                        
                            
            
                                    
            
            
                | 93 |  |  |             # Parse parts from filename | 
            
                                                                        
                            
            
                                    
            
            
                | 94 |  |  |             _, episodes = ModuleManager['matcher'].process(p_metadata) | 
            
                                                                        
                            
            
                                    
            
            
                | 95 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 96 |  |  |             part_count = len(episodes) | 
            
                                                                        
                            
            
                                    
            
            
                | 97 |  |  |         else: | 
            
                                                                        
                            
            
                                    
            
            
                | 98 |  |  |             season_num = p_metadata.season.index | 
            
                                                                        
                            
            
                                    
            
            
                | 99 |  |  |             episode_num = p_metadata.index | 
            
                                                                        
                            
            
                                    
            
            
                | 100 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 101 |  |  |             # Process guid episode identifier overrides | 
            
                                                                        
                            
            
                                    
            
            
                | 102 |  |  |             if guid.season is not None: | 
            
                                                                        
                            
            
                                    
            
            
                | 103 |  |  |                 season_num = guid.season | 
            
                                                                        
                            
            
                                    
            
            
                | 104 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 105 |  |  |             # Retrieve episode mappings from OEM | 
            
                                                                        
                            
            
                                    
            
            
                | 106 |  |  |             supported, match = ModuleManager['mapper'].map( | 
            
                                                                        
                            
            
                                    
            
            
                | 107 |  |  |                 guid.service, guid.id, | 
            
                                                                        
                            
            
                                    
            
            
                | 108 |  |  |                 EpisodeIdentifier(season_num, episode_num), | 
            
                                                                        
                            
            
                                    
            
            
                | 109 |  |  |                 resolve_mappings=False | 
            
                                                                        
                            
            
                                    
            
            
                | 110 |  |  |             ) | 
            
                                                                        
                            
            
                                    
            
            
                | 111 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 112 |  |  |             if not supported or not match: | 
            
                                                                        
                            
            
                                    
            
            
                | 113 |  |  |                 return 1, 1, p_metadata.duration | 
            
                                                                        
                            
            
                                    
            
            
                | 114 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 115 |  |  |             if not isinstance(match, EpisodeMatch): | 
            
                                                                        
                            
            
                                    
            
            
                | 116 |  |  |                 log.info('Movie mappings are not supported') | 
            
                                                                        
                            
            
                                    
            
            
                | 117 |  |  |                 return 1, 1, p_metadata.duration | 
            
                                                                        
                            
            
                                    
            
            
                | 118 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 119 |  |  |             part_count = len(match.mappings) or 1 | 
            
                                                                        
                            
            
                                    
            
            
                | 120 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 121 |  |  |         # Determine the current part number | 
            
                                                                        
                            
            
                                    
            
            
                | 122 |  |  |         part, part_duration = cls.get_part( | 
            
                                                                        
                            
            
                                    
            
            
                | 123 |  |  |             p_metadata.duration, | 
            
                                                                        
                            
            
                                    
            
            
                | 124 |  |  |             view_offset, | 
            
                                                                        
                            
            
                                    
            
            
                | 125 |  |  |             part_count | 
            
                                                                        
                            
            
                                    
            
            
                | 126 |  |  |         ) | 
            
                                                                        
                            
            
                                    
            
            
                | 127 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 128 |  |  |         return part, part_count, part_duration | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 |  |  |     def get_part(duration, view_offset, part_count): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 |  |  |         if duration is None or part_count is None or part_count < 1: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |             return 1, duration | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 |  |  |         part_duration = int(math.floor( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 |  |  |             float(duration) / part_count | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 |  |  |         )) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 |  |  |         # Calculate current part number | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  |         part = int(math.floor( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |             float(view_offset) / part_duration | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 |  |  |         )) + 1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  |         # Clamp `part` to: 0 - `total_parts` | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 |  |  |         return max(0, min(part, part_count)), part_duration | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 |  |  |     def get_progress(duration, view_offset, part=1, part_count=1, part_duration=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 |  |  |         if duration is None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 150 |  |  |             return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 151 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 152 |  |  |         if part_count > 1 and part_duration is not None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 153 |  |  |             # Update attributes for part progress calculations | 
            
                                                                                                            
                            
            
                                    
            
            
                | 154 |  |  |             duration = part_duration | 
            
                                                                                                            
                            
            
                                    
            
            
                | 155 |  |  |             view_offset -= (part_duration * (part - 1)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 156 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 157 |  |  |         # Calculate progress (0 - 100) | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 158 |  |  |         return round((float(view_offset) / duration) * 100, 2) | 
            
                                                        
            
                                    
            
            
                | 159 |  |  |  |