def dicsoverProviderLocally(handle, options): dialog = xbmcgui.Dialog() baseUrl = dialog.input(localise(32051)) if not baseUrl: return None plexServer = PlexServer(baseUrl, timeout=plex.constants.REQUEST_TIMEOUT) if not plexServer: return None providerId = Server.BuildProviderId(plexServer.machineIdentifier) providerIconUrl = Server.BuildIconUrl(baseUrl) provider = xbmcmediaimport.MediaProvider(providerId,baseUrl, plexServer.friendlyName, providerIconUrl, plex.constants.SUPPORTED_MEDIA_TYPES, handle=handle) # store local authentication in settings providerSettings = provider.prepareSettings() if not providerSettings: return None providerSettings.setInt(plex.constants.SETTINGS_PROVIDER_AUTHENTICATION, plex.constants.SETTINGS_PROVIDER_AUTHENTICATION_OPTION_LOCAL) providerSettings.save() return provider
def discoverProviderLocally(handle, options): baseUrl = xbmcgui.Dialog().input(localise(32050), 'http://') if not baseUrl: return None log('trying to discover an Emby server at {}...'.format(baseUrl)) try: serverInfo = emby.api.server.Server.GetInfo(baseUrl) if not serverInfo: return None except: return None providerId = Server.BuildProviderId(serverInfo.id) providerIconUrl = Server.BuildIconUrl(baseUrl) provider = xbmcmediaimport.MediaProvider( providerId, baseUrl, serverInfo.name, providerIconUrl, emby.constants.SUPPORTED_MEDIA_TYPES) provider.setIconUrl(kodi.Api.downloadIcon(provider)) # store local authentication in settings providerSettings = provider.prepareSettings() if not providerSettings: return None providerSettings.setString( emby.constants.SETTING_PROVIDER_AUTHENTICATION, emby.constants.SETTING_PROVIDER_AUTHENTICATION_OPTION_LOCAL) providerSettings.save() log('Local Emby server {} successfully discovered at {}'.format( mediaProvider2str(provider), baseUrl)) return provider
def linkMyPlexAccount(handle, options): # retrieve the media provider mediaProvider = xbmcmediaimport.getProvider(handle) if not mediaProvider: log('cannot retrieve media provider', xbmc.LOGERROR) return # get the media provider settings providerSettings = mediaProvider.prepareSettings() if not providerSettings: return plexAccount = linkToMyPlexAccount() if not plexAccount: return username = plexAccount.username if not username: log('no valid username available for the linked MyPlex account', xbmc.LOGWARNING) return # make sure the configured Plex Media Server is still accessible serverUrl = mediaProvider.getBasePath() matchingServer = None serverId = getServerId(mediaProvider.getIdentifier()) # get all connected server resources serverResources = getServerResources(plexAccount) for server in serverResources: if server.clientIdentifier == serverId: matchingServer = server break if not matchingServer: log('no Plex Media Server matching {} found'.format(serverUrl), xbmc.LOGWARNING) xbmcgui.Dialog().ok(localise(32015), localise(32058)) return xbmcgui.Dialog().ok(localise(32015), localise(32059).format(username)) # change the settings providerSettings.setString(plex.constants.SETTINGS_PROVIDER_USERNAME, username) providerSettings.setString(plex.constants.SETTINGS_PROVIDER_TOKEN, matchingServer.accessToken)
def changeUrl(handle, _): # retrieve the media provider mediaProvider = xbmcmediaimport.getProvider(handle) if not mediaProvider: log('cannot retrieve media provider', xbmc.LOGERROR) return # get the media provider settings providerSettings = mediaProvider.prepareSettings() if not providerSettings: return urlCurrent = ProviderSettings.GetUrl(providerSettings) if not urlCurrent: log("cannot retrieve current URL from provider settings", xbmc.LOGERROR) return # ask the user for a new URL urlNew = xbmcgui.Dialog().input(localise(32045), urlCurrent) if not urlNew: return # store the new URL in the settings ProviderSettings.SetUrl(providerSettings, urlNew) # try to connect and authenticate with the new URL success = False try: success = Server(mediaProvider).Authenticate(force=True) except: pass dialog = xbmcgui.Dialog() title = mediaProvider.getFriendlyName() if success: dialog.ok(title, localise(32017)) else: # ask the user whether to change the URL anyway changeUrlAnyway = dialog.yesno(title, localise(32066)) if not changeUrlAnyway: # revert the settings to the previous / old URL ProviderSettings.SetUrl(providerSettings, urlCurrent)
def discoverProvider(handle, options): dialog = xbmcgui.Dialog() authenticationChoices = [ localise(32036), # local localise(32037) # Emby Connect ] authenticationChoice = dialog.select(localise(32053), authenticationChoices) if authenticationChoice == 0: # local provider = discoverProviderLocally(handle, options) elif authenticationChoice == 1: # Emby Connect provider = discoverProviderWithEmbyConnect(handle, options) else: return if not provider: return xbmcmediaimport.setDiscoveredProvider(handle, True, provider)
def forceSync(handle, options): # ask the user whether he is sure force = xbmcgui.Dialog().yesno(localise(32042), localise(32053)) if not force: return # retrieve the media import mediaImport = xbmcmediaimport.getImport(handle) if not mediaImport: log('cannot retrieve media import', xbmc.LOGERROR) return # prepare the media provider settings importSettings = mediaImport.prepareSettings() if not importSettings: log('cannot prepare media import settings', xbmc.LOGERROR) return # reset the synchronization hash setting to force a full synchronization SynchronizationSettings.ResetHash(importSettings, save=False)
def discoverProvider(handle, options): dialog = xbmcgui.Dialog() authenticationChoices = [ localise(32013), # local only localise(32014) # MyPlex ] authenticationChoice = dialog.select(localise(32050), authenticationChoices) if authenticationChoice == 0: # local only provider = dicsoverProviderLocally(handle, options) elif authenticationChoice == 1: # MyPlex provider = dicsoverProviderWithMyPlex(handle, options) else: return if not provider: return xbmcmediaimport.setDiscoveredProvider(handle, True, provider)
def linkToEmbyConnect(deviceId): dialog = xbmcgui.Dialog() pinLogin = EmbyConnect.PinLogin(deviceId=deviceId) if not pinLogin.pin: dialog.ok(localise(32038), localise(32054)) log('failed to get PIN to link to Emby Connect', xbmc.LOGWARNING) return None # show the user the pin dialog.ok(localise(32038), localise(32055), '[COLOR FF52B54B]{}[/COLOR]'.format(pinLogin.pin)) # check the status of the authentication while not pinLogin.finished: if pinLogin.checkLogin(): break time.sleep(0.25) if pinLogin.expired: dialog.ok(localise(32038), localise(32056)) log('linking to Emby Connect has expiried', xbmc.LOGWARNING) return None authResult = pinLogin.exchange() if not authResult: log( 'no valid access token received from the linked Emby Connect account', xbmc.LOGWARNING) return None return authResult
def linkEmbyConnect(handle, _): # retrieve the media provider mediaProvider = xbmcmediaimport.getProvider(handle) if not mediaProvider: log('cannot retrieve media provider', xbmc.LOGERROR) return # get the media provider settings providerSettings = mediaProvider.prepareSettings() if not providerSettings: return # make sure we have a valid device ID deviceId = providerSettings.getString(emby.constants.SETTING_PROVIDER_DEVICEID) if not deviceId: deviceId = Request.GenerateDeviceId() providerSettings.setString(emby.constants.SETTING_PROVIDER_DEVICEID, deviceId) embyConnect = linkToEmbyConnect(deviceId) if not embyConnect: return # make sure the configured Emby server is still accessible serverUrl = ProviderSettings.GetUrl(providerSettings) matchingServer = None serverId = Server.GetServerId(mediaProvider.getIdentifier()) # get all connected servers servers = EmbyConnect.GetServers(embyConnect.accessToken, embyConnect.userId) if not servers: log('no servers available for Emby Connect user id {}'.format(embyConnect.userId), xbmc.LOGWARNING) return for server in servers: if server.systemId == serverId: matchingServer = server break if not matchingServer: log('no Emby server matching {} found'.format(serverUrl), xbmc.LOGWARNING) xbmcgui.Dialog().ok(localise(32038), localise(32061)) return # change the settings providerSettings.setString(emby.constants.SETTING_PROVIDER_EMBY_CONNECT_USER_ID, embyConnect.userId) providerSettings.setString(emby.constants.SETTING_PROVIDER_EMBY_CONNECT_ACCESS_KEY, matchingServer.accessKey) success = False try: success = Server(mediaProvider).Authenticate(force=True) except: pass if success: xbmcgui.Dialog().ok(localise(32038), localise(32062)) log('successfully linked to Emby Connect server {} ({}) {}'.format(matchingServer.name, serverId, serverUrl)) else: xbmcgui.Dialog().ok(localise(32038), localise(32061)) log('failed to link to Emby Connect server {} ({}) {}'.format(matchingServer.name, serverId, serverUrl), xbmc.LOGWARNING)
def _ProcessMessageServer(self, messageType, data): if not self._settings.getBool( SETTING_PROVIDER_INTERFACE_SHOW_SERVER_MESSAGES): return if messageType == WS_MESSAGE_TYPE_SERVER_SHUTTING_DOWN: message = 32051 elif messageType == WS_MESSAGE_TYPE_SERVER_RESTARTING: message = 32052 else: return xbmcgui.Dialog().notification( 'Emby Media Importer', localise(message).format(self._mediaProvider.getFriendlyName()), self._mediaProvider.getIconUrl())
def settingOptionsFillerUsers(handle, _): # retrieve the media provider mediaProvider = xbmcmediaimport.getProvider(handle) if not mediaProvider: log('cannot retrieve media provider', xbmc.LOGERROR) return # get the provider's settings settings = mediaProvider.getSettings() users = [(localise(32015), emby.constants.SETTING_PROVIDER_USER_OPTION_MANUAL)] publicUsers = User.GetPublicUsers(ProviderSettings.GetUrl(settings), deviceId=settings.getString(emby.constants.SETTING_PROVIDER_DEVICEID)) users.extend([(user.name, user.id) for user in publicUsers]) # pass the list of users back to Kodi settings.setStringOptions(emby.constants.SETTING_PROVIDER_USER, users)
def resetDeviceId(handle, _): # retrieve the media provider mediaProvider = xbmcmediaimport.getProvider(handle) if not mediaProvider: log('cannot retrieve media provider', xbmc.LOGERROR) return # get the media provider settings providerSettings = mediaProvider.prepareSettings() if not providerSettings: return deviceId = Request.GenerateDeviceId() log('created a new device identifier for {}: {}'.format(mediaProvider2str(mediaProvider), deviceId)) providerSettings.setString(emby.constants.SETTING_PROVIDER_DEVICEID, deviceId) xbmcgui.Dialog().ok(mediaProvider.getFriendlyName(), localise(32063))
def testConnection(handle, options): # retrieve the media provider mediaProvider = xbmcmediaimport.getProvider(handle) if not mediaProvider: log('cannot retrieve media provider', xbmc.LOGERROR) return success = False try: success = Server(mediaProvider).Authenticate() except: pass title = mediaProvider.getFriendlyName() line = 32019 if success: line = 32018 xbmcgui.Dialog().ok(title, localise(line))
def testAuthentication(handle, _): # retrieve the media provider mediaProvider = xbmcmediaimport.getProvider(handle) if not mediaProvider: log('cannot retrieve media provider', xbmc.LOGERROR) return log('testing authentication with {}...'.format(mediaProvider2str(mediaProvider))) success = False try: success = Server(mediaProvider).Authenticate(force=True) except: pass line = 32018 if success: line = 32017 xbmcgui.Dialog().ok(mediaProvider.getFriendlyName(), localise(line))
def discoverProvider(handle, options): baseUrl = xbmcgui.Dialog().input(localise(32050), 'http://') if not baseUrl: return log('trying to discover an Emby server at {}...'.format(baseUrl)) try: serverInfo = emby.api.server.Server.GetInfo(baseUrl) if not serverInfo: return except: return providerId = Server.BuildProviderId(serverInfo.id) providerIconUrl = Server.BuildIconUrl(baseUrl) mediaProvider = xbmcmediaimport.MediaProvider(providerId, baseUrl, serverInfo.name, providerIconUrl, emby.constants.SUPPORTED_MEDIA_TYPES) mediaProvider.setIconUrl(kodi.Api.downloadIcon(mediaProvider)) log('Emby server {} successfully discovered at {}'.format(mediaProvider2str(mediaProvider), baseUrl)) xbmcmediaimport.setDiscoveredProvider(handle, True, mediaProvider)
def linkToMyPlexAccount(): dialog = xbmcgui.Dialog() pinLogin = MyPlexPinLogin() if not pinLogin.pin: dialog.ok(localise(32015), localise(32052)) log('failed to get PIN to link MyPlex account', xbmc.LOGWARNING) return None # show the user the pin dialog.ok(localise(32015), localise(32053), '[COLOR FFE5A00D]{}[/COLOR]'.format(pinLogin.pin)) # check the status of the authentication while not pinLogin.finished: if pinLogin.checkLogin(): break if pinLogin.expired: dialog.ok(localise(32015), localise(32054)) log('linking the MyPlex account has expiried', xbmc.LOGWARNING) return None if not pinLogin.token: log('no valid token received from the linked MyPlex account', xbmc.LOGWARNING) return None # login to MyPlex try: plexAccount = MyPlexAccount(token=pinLogin.token, timeout=plex.constants.REQUEST_TIMEOUT) except Exception as e: log('failed to connect to the linked MyPlex account: {}'.format(e), xbmc.LOGWARNING) return None if not plexAccount: log('failed to connect to the linked MyPlex account', xbmc.LOGWARNING) return None return plexAccount
def dicsoverProviderWithMyPlex(handle, options): plexAccount = linkToMyPlexAccount() if not plexAccount: return None username = plexAccount.username if not username: log('no valid username available for the linked MyPlex account', xbmc.LOGWARNING) return None dialog = xbmcgui.Dialog() # get all connected server resources serverResources = getServerResources(plexAccount) if not serverResources: log('no servers available for MyPlex account {}'.format(username), xbmc.LOGWARNING) return None if len(serverResources) == 1: server = serverResources[0] else: # ask the user which server to use servers = [ resource.name for resource in serverResources ] serversChoice = dialog.select(localise(32055), servers) if serversChoice < 0 or serversChoice >= len(servers): return None server = serverResources[serversChoice] if not server: return None if not server.connections: # try to connect to the server plexServer = server.connect(timeout=plex.constants.REQUEST_TIMEOUT) if not plexServer: log('failed to connect to the Plex Media Server "{}"'.format(server.name), xbmc.LOGWARNING) return None baseUrl = plexServer.url('', includeToken=False) else: isLocal = False localConnections = [ connection for connection in server.connections if connection.local ] remoteConnections = [ connection for connection in server.connections if not connection.local and not connection.relay ] remoteRelayConnections = [ connection for connection in server.connections if not connection.local and connection.relay ] if localConnections: # ask the user whether to use a local or remote connection isLocal = dialog.yesno(localise(32056), localise(32057).format(server.name)) urls = [] if isLocal: urls.append(localConnections[0].httpuri) else: urls.extend([(conn.uri, False) for conn in remoteConnections]) urls.extend([(conn.uri, True) for conn in remoteRelayConnections]) urls.extend([(conn.uri, False) for conn in localConnections]) baseUrl = None connectViaRelay = True # find a working connection / base URL for (url, isRelay) in urls: try: # don't try to connect via relay if the user has already declined it before if isRelay and not connectViaRelay: log('ignoring relay connection to the Plex Media Server "{}" at {}'.format(server.name, url), xbmc.LOGDEBUG) continue # try to connect to the server plexServer = PlexServer(baseurl=url, token=server.accessToken, timeout=plex.constants.REQUEST_TIMEOUT) # if this is a relay ask the user if using it is ok if isRelay: connectViaRelay = dialog.yesno(localise(32056), localise(32061).format(server.name)) if not connectViaRelay: log('ignoring relay connection to the Plex Media Server "{}" at {}'.format(server.name, url), xbmc.LOGDEBUG) continue baseUrl = url break except: log('failed to connect to "{}" at {}'.format(server.name, url), xbmc.LOGDEBUG) continue if not baseUrl: dialog.ok(localise(32056), localise(32060).format(server.name)) log('failed to connect to the Plex Media Server "{}" for MyPlex account {}'.format(server.name, username), xbmc.LOGWARNING) return None if not baseUrl: log('failed to determine the URL to access the Plex Media Server "{}" for MyPlex account {}'.format(server.name, username), xbmc.LOGWARNING) return None log('successfully connected to Plex Media Server "{}" for MyPlex account {} at {}'.format(server.name, username, baseUrl)) providerId = plex.server.Server.BuildProviderId(server.clientIdentifier) providerIconUrl = plex.server.Server.BuildIconUrl(baseUrl) provider = xbmcmediaimport.MediaProvider(providerId, baseUrl, server.name, providerIconUrl, plex.constants.SUPPORTED_MEDIA_TYPES, handle=handle) # store MyPlex account details and token in settings providerSettings = provider.prepareSettings() if not providerSettings: return None providerSettings.setInt(plex.constants.SETTINGS_PROVIDER_AUTHENTICATION, plex.constants.SETTINGS_PROVIDER_AUTHENTICATION_OPTION_MYPLEX) providerSettings.setString(plex.constants.SETTINGS_PROVIDER_USERNAME, username) providerSettings.setString(plex.constants.SETTINGS_PROVIDER_TOKEN, server.accessToken) providerSettings.save() return provider
def discoverProviderWithEmbyConnect(handle, options): deviceId = Request.GenerateDeviceId() embyConnect = linkToEmbyConnect(deviceId) if not embyConnect: return None dialog = xbmcgui.Dialog() # get all connected servers servers = EmbyConnect.GetServers(embyConnect.accessToken, embyConnect.userId) if not servers: log( 'no servers available for Emby Connect user id {}'.format( embyConnect.userId), xbmc.LOGWARNING) return None if len(servers) == 1: server = servers[0] else: # ask the user which server to use serverChoices = [server.name for server in servers] serverChoice = dialog.select(localise(32057), serverChoices) if serverChoice < 0 or serverChoice >= len(serverChoices): return None server = server[serverChoice] if not server: return None urls = [] if server.localUrl: # ask the user whether to use a local or remote connection isLocal = dialog.yesno(localise(32058), localise(32059).format(server.name)) if isLocal: urls.append(server.localUrl) if server.remoteUrl: urls.append(server.remoteUrl) baseUrl = None # find a working connection / base URL for url in urls: try: _ = emby.api.server.Server.GetInfo(url) except: log('failed to connect to "{}" at {}'.format(server.name, url), xbmc.LOGDEBUG) continue baseUrl = url break if not baseUrl: dialog.ok(localise(32058), localise(32060).format(server.name)) log( 'failed to connect to Emby server "{}" with Emby Connect user ID {}' .format(server.name, embyConnect.userId), xbmc.LOGWARNING) return None providerId = Server.BuildProviderId(server.systemId) providerIconUrl = Server.BuildIconUrl(baseUrl) provider = xbmcmediaimport.MediaProvider( providerId, baseUrl, server.name, providerIconUrl, emby.constants.SUPPORTED_MEDIA_TYPES) provider.setIconUrl(kodi.Api.downloadIcon(provider)) # store Emby connect authentication in settings providerSettings = provider.prepareSettings() if not providerSettings: return None providerSettings.setString( emby.constants.SETTING_PROVIDER_AUTHENTICATION, emby.constants.SETTING_PROVIDER_AUTHENTICATION_OPTION_EMBY_CONNECT) providerSettings.setString( emby.constants.SETTING_PROVIDER_EMBY_CONNECT_USER_ID, embyConnect.userId) providerSettings.setString( emby.constants.SETTING_PROVIDER_EMBY_CONNECT_ACCESS_KEY, server.accessKey) providerSettings.setString(emby.constants.SETTING_PROVIDER_DEVICEID, deviceId) providerSettings.save() log('Emby Connect server {} successfully discovered at {}'.format( mediaProvider2str(provider), baseUrl)) return provider
def execImport(handle, options): # parse all necessary options mediaTypes = mediaTypesFromOptions(options) if not mediaTypes: log('cannot execute "import" without media types', xbmc.LOGERROR) return # retrieve the media import mediaImport = xbmcmediaimport.getImport(handle) if not mediaImport: log('cannot retrieve media import', xbmc.LOGERROR) return # prepare and get the media import settings importSettings = mediaImport.prepareSettings() if not importSettings: log('cannot prepare media import settings', xbmc.LOGERROR) return # retrieve the media provider mediaProvider = mediaImport.getProvider() if not mediaProvider: log('cannot retrieve media provider', xbmc.LOGERROR) return log('importing {} items from {}...'.format(mediaTypes, mediaProvider2str(mediaProvider))) # prepare the media provider settings mediaProviderSettings = mediaProvider.prepareSettings() if not mediaProviderSettings: log('cannot prepare media provider settings', xbmc.LOGERROR) return # create an Emby server instance embyServer = Server(mediaProvider) # build the base URL to retrieve items baseUrl = embyServer.BuildUserUrl(emby.constants.URL_ITEMS) baseUrlOptions = { emby.constants.URL_QUERY_ITEMS_RECURSIVE: 'true', emby.constants.URL_QUERY_ITEMS_FIELDS: ','.join(EMBY_ITEM_FIELDS), emby.constants.URL_QUERY_ITEMS_EXCLUDE_LOCATION_TYPES: 'Virtual,Offline' } baseUrl = Url.addOptions(baseUrl, baseUrlOptions) # get all (matching) library views selectedViews = ImportSettings.GetLibraryViews(importSettings) views = getMatchingLibraryViews(embyServer, mediaTypes, selectedViews) if not views: log('cannot retrieve items without any library views', xbmc.LOGERROR) return # determine whether Direct Play is allowed allowDirectPlay = mediaProviderSettings.getBool(emby.constants.SETTING_PROVIDER_PLAYBACK_ALLOW_DIRECT_PLAY) # determine whether to import collections importCollections = importSettings.getBool(emby.constants.SETTING_IMPORT_IMPORT_COLLECTIONS) # determine the last sync time and whether we should perform a fast sync fastSync = False syncUrlOptions = {} # check if synchronization related settings have changed; if yes we have to perform a full synchronization if SynchronizationSettings.HaveChanged(mediaTypes, mediaProviderSettings, importSettings, save=True): log('forcing a full synchronization to import {} items from {} because some related settings have changed' .format(mediaTypes, mediaProvider2str(mediaProvider))) else: # check if we # have already performed a (full) synchronization before # should use the Kodi Companion Emby server plugin lastSync = mediaImport.getLastSynced() if lastSync and \ mediaProviderSettings.getBool(emby.constants.SETTING_PROVIDER_SYNCHRONIZATION_USE_KODI_COMPANION): if KodiCompanion.IsInstalled(embyServer): fastSync = True # convert the last sync datetime string to ISO 8601 lastSync = parser.parse(lastSync).astimezone(timezone.utc).isoformat(timespec='seconds') syncUrlOptions.update({ # only set MinDateLastSavedForUser because it already covers DateLastSaved, RatingLastModified # and PlaystateLastModified. Setting both MinDateLastSaved and MinDateLastSavedForUser will # cause issues, see # https://emby.media/community/index.php?/topic/82258-retrieving-changeset-when-client-returns-online-mediaimport/ emby.constants.URL_QUERY_ITEMS_MIN_DATE_LAST_SAVED_FOR_USER: lastSync }) log('using fast synchronization to import {} items from {} with Kodi companion plugin' .format(mediaTypes, mediaProvider2str(mediaProvider)), xbmc.LOGDEBUG) # retrieving the sync queue from Kodi companion syncQueue = KodiCompanion.SyncQueue.GetItems(embyServer, lastSync) else: log('Kodi companion usage is enabled to import {} items from {} but the server plugin is not installed' .format(mediaTypes, mediaProvider2str(mediaProvider)), xbmc.LOGWARNING) # loop over all media types to be imported for mediaType in mediaTypes: if shouldCancel(handle, showProgress=False): return if mediaType == xbmcmediaimport.MediaTypeVideoCollection and not importCollections: log('importing {} items from {} is disabled'.format(mediaType, mediaProvider2str(mediaProvider)), xbmc.LOGDEBUG) continue log('importing {} items from {}...'.format(mediaType, mediaProvider2str(mediaProvider))) mappedMediaType = kodi.Api.getEmbyMediaType(mediaType) if not mappedMediaType: log('cannot import unsupported media type "{}"'.format(mediaType), xbmc.LOGERROR) continue (_, embyMediaType, _, localizedMediaType) = mappedMediaType xbmcmediaimport.setProgressStatus( handle, localise(32001).format(localise(localizedMediaType))) urlOptions = syncUrlOptions.copy() urlOptions.update({ emby.constants.URL_QUERY_ITEMS_INCLUDE_ITEM_TYPES: embyMediaType }) url = Url.addOptions(baseUrl, urlOptions) boxsetUrlOptions = { emby.constants.URL_QUERY_ITEMS_INCLUDE_ITEM_TYPES: kodi.EMBY_MEDIATYPE_BOXSET } boxsetUrl = Url.addOptions(baseUrl, boxsetUrlOptions) totalItems = 0 # handle library views for view in views: # retrieve BoxSets if configured boxsetMapping = {} if importCollections and mediaType == xbmcmediaimport.MediaTypeMovie: # get the number of media items in the view totalItemCount = getTotalItems(embyServer, url, mediaType, view.id) # only load BoxSets from views with media items if totalItemCount: # retrieve all BoxSets / collections matching the current media type boxsetObjs = importItems(handle, embyServer, boxsetUrl, mediaType, view.id, raw=True, showProgress=False, allowDirectPlay=allowDirectPlay) for boxsetObj in boxsetObjs: if emby.constants.PROPERTY_ITEM_ID not in boxsetObj or \ emby.constants.PROPERTY_ITEM_NAME not in boxsetObj: continue boxsetId = boxsetObj[emby.constants.PROPERTY_ITEM_ID] boxsetName = boxsetObj[emby.constants.PROPERTY_ITEM_NAME] # get all items belonging to the BoxSet boxsetItems = importItems(handle, embyServer, url, mediaType, boxsetId, embyMediaType=embyMediaType, viewName=boxsetName, showProgress=False, allowDirectPlay=allowDirectPlay) for boxsetItem in boxsetItems: # reorder to map item paths to BoxSet names boxsetMapping[boxsetItem.getPath()] = boxsetName # retrieve the actual media items log('importing {} items from "{}" view from {}...' .format(mediaType, view.name, mediaProvider2str(mediaProvider))) importItemsGen = importItemsGenerator(handle, embyServer, url, mediaType, view.id, embyMediaType=embyMediaType, viewName=view.name, allowDirectPlay=allowDirectPlay) for importedItems in importItemsGen: totalItems += len(importedItems) # assign BoxSets / collections to the retrieved items if boxsetMapping: for index, item in enumerate(importedItems): boxsetName = boxsetMapping.get(item.getPath(), None) if boxsetName: # set the BoxSet / collection kodi.Api.setCollection(item, boxsetName) importedItems[index] = item # pass the imported items back to Kodi xbmcmediaimport.addImportItems(handle, importedItems, mediaType) # in a fast sync we need to get the removed items from Kodi companion if fastSync: if totalItems: log('{} changed {} items imported from {}' .format(totalItems, mediaType, mediaProvider2str(mediaProvider))) # handle removed items through Kodi companion's sync queue if syncQueue.itemsRemoved: # retrieve all local items matching the current media type from the current import localItems = xbmcmediaimport.getImportedItems(handle, mediaType) # match the local items against the changed items removedItems, = kodi.Api.matchImportedItemIdsToLocalItems( # noqa: E501 # pylint: disable=unbalanced-tuple-unpacking localItems, syncQueue.itemsRemoved) # erase all removed items matching the current media type from the sync queue syncQueue.itemsRemoved = \ [removedItem for removedItem in syncQueue.itemsRemoved if removedItem in removedItems] if removedItems: log('{} previously imported {} items removed from {}' .format(len(removedItems), mediaType, mediaProvider2str(mediaProvider))) xbmcmediaimport.addImportItems(handle, removedItems, mediaType, xbmcmediaimport.MediaImportChangesetTypeRemoved) else: log('{} {} items imported from {}'.format(totalItems, mediaType, mediaProvider2str(mediaProvider))) xbmcmediaimport.finishImport(handle, fastSync)
def play(item, itemId, mediaProvider): if item.isFolder(): log( '[context/play] cannot play folder item {}'.format( listItem2str(item, itemId)), xbmc.LOGERROR) return # create an Emby server instance embyServer = Server(mediaProvider) # retrieve all details of the item itemObj = Library.GetItem(embyServer, itemId) if not itemObj: log( '[context/play] cannot retrieve the details of {} from {}'.format( listItem2str(item, itemId), mediaProvider2str(mediaProvider)), xbmc.LOGERROR) return # cannot play folders if itemObj.get(emby.constants.PROPERTY_ITEM_IS_FOLDER): log( '[context/play] cannot play folder item {}'.format( listItem2str(item, itemId)), xbmc.LOGERROR) return playChoices = [] playChoicesUrl = [] # determine whether Direct Play is allowed mediaProviderSettings = mediaProvider.getSettings() allowDirectPlay = mediaProviderSettings.getBool( emby.constants.SETTING_PROVIDER_PLAYBACK_ALLOW_DIRECT_PLAY) # check if the item supports Direct Play and / or Direct Stream canDirectPlay = None directPlayUrl = None if allowDirectPlay: (canDirectPlay, directPlayUrl) = kodi.Api.getDirectPlayUrl(itemObj) if canDirectPlay and directPlayUrl: playChoices.append(localise(32101)) playChoicesUrl.append(directPlayUrl) (canDirectStream, directStreamUrl) = kodi.Api.getDirectStreamUrl(embyServer, itemId, itemObj) if canDirectStream: playChoices.append(localise(32102)) playChoicesUrl.append(directStreamUrl) # if there are no options something went wrong if not playChoices: log( '[context/play] cannot play {} from {}'.format( listItem2str(item, itemId), mediaProvider2str(mediaProvider)), xbmc.LOGERROR) return # ask the user how to play playChoice = Dialog().contextmenu(playChoices) if playChoice < 0 or playChoice >= len(playChoices): return playUrl = playChoicesUrl[playChoice] # play the item log('[context/play] playing {} using "{}" ({}) from {}'.format( listItem2str(item, itemId), playChoices[playChoice], playUrl, mediaProvider2str(mediaProvider))) # overwrite the dynamic path of the ListItem item.setDynamicPath(playUrl) xbmc.Player().play(playUrl, item)
def execImport(handle, options): if not 'path' in options: log('cannot execute "import" without path', xbmc.LOGERROR) return # parse all necessary options mediaTypes = mediaTypesFromOptions(options) if not mediaTypes: log('cannot execute "import" without media types', xbmc.LOGERROR) return # retrieve the media import mediaImport = xbmcmediaimport.getImport(handle) if not mediaImport: log('cannot retrieve media import', xbmc.LOGERROR) return # prepare and get the media import settings importSettings = mediaImport.prepareSettings() if not importSettings: log('cannot prepare media import settings', xbmc.LOGERROR) return # retrieve the media provider mediaProvider = mediaImport.getProvider() if not mediaProvider: log('cannot retrieve media provider', xbmc.LOGERROR) return # prepare the media provider settings if not mediaProvider.prepareSettings(): log('cannot prepare media provider settings', xbmc.LOGERROR) return # create a Plex Media Server instance server = Server(mediaProvider) plexServer = server.PlexServer() plexLibrary = plexServer.library # get all (matching) library sections selectedLibrarySections = getLibrarySectionsFromSettings(importSettings) librarySections = getMatchingLibrarySections(plexServer, mediaTypes, selectedLibrarySections) if not librarySections: log('cannot retrieve {} items without any library section'.format(mediaTypes), xbmc.LOGERROR) return # loop over all media types to be imported progressTotal = len(mediaTypes) for progress, mediaType in enumerate(mediaTypes): if xbmcmediaimport.shouldCancel(handle, progress, progressTotal): return mappedMediaType = Api.getPlexMediaType(mediaType) if not mappedMediaType: log('cannot import unsupported media type "{}"'.format(mediaType), xbmc.LOGERROR) continue plexLibType = mappedMediaType['libtype'] localizedMediaType = localise(mappedMediaType['label']) xbmcmediaimport.setProgressStatus(handle, localise(32001).format(localizedMediaType)) log('importing {} items from {}'.format(mediaType, mediaProvider2str(mediaProvider))) # handle library sections plexItems = [] sectionsProgressTotal = len(librarySections) for sectionsProgress, librarySection in enumerate(librarySections): if xbmcmediaimport.shouldCancel(handle, sectionsProgress, sectionsProgressTotal): return # get the library section from the Plex Media Server section = plexLibrary.sectionByID(librarySection['key']) if not section: log('cannot import {} items from unknown library section {}'.format(mediaType, librarySection), xbmc.LOGWARNING) continue # get all matching items from the library section try: plexSectionItems = section.search(libtype=plexLibType) plexItems.extend(plexSectionItems) except plexapi.exceptions.BadRequest as err: log('failed to retrieve {} items from {}: {}'.format(mediaType, mediaProvider2str(mediaProvider), err)) return # parse all items items = [] itemsProgressTotal = len(plexItems) for itemsProgress, plexItem in enumerate(plexItems): if xbmcmediaimport.shouldCancel(handle, itemsProgress, itemsProgressTotal): return item = Api.toFileItem(plexServer, plexItem, mediaType, plexLibType) if not item: continue items.append(item) if items: log('{} {} items imported from {}'.format(len(items), mediaType, mediaProvider2str(mediaProvider))) xbmcmediaimport.addImportItems(handle, items, mediaType) xbmcmediaimport.finishImport(handle)