|
2 | 2 | from plexapi import media, utils |
3 | 3 | from plexapi.exceptions import BadRequest, NotFound |
4 | 4 | from plexapi.base import Playable, PlexPartialObject |
5 | | -from plexapi.compat import quote_plus |
| 5 | +from plexapi.compat import quote_plus, quote |
6 | 6 | import os |
7 | 7 |
|
8 | 8 |
|
@@ -126,6 +126,84 @@ def posters(self): |
126 | 126 |
|
127 | 127 | return self.fetchItems('%s/posters' % self.key, cls=media.Poster) |
128 | 128 |
|
| 129 | + def optimize(self, title=None, target="", targetTagID=None, locationID=-1, policyScope='all', |
| 130 | + policyValue="", policyUnwatched=0, videoQuality=None, deviceProfile=None): |
| 131 | + """ Optimize item |
| 132 | +
|
| 133 | + locationID (int): -1 in folder with orginal items |
| 134 | + 2 library path |
| 135 | +
|
| 136 | + target (str): custom quality name. |
| 137 | + if none provided use "Custom: {deviceProfile}" |
| 138 | +
|
| 139 | + targetTagID (int): Default quality settings |
| 140 | + 1 Mobile |
| 141 | + 2 TV |
| 142 | + 3 Original Quality |
| 143 | +
|
| 144 | + deviceProfile (str): Android, IOS, Universal TV, Universal Mobile, Windows Phone, |
| 145 | + Windows, Xbox One |
| 146 | +
|
| 147 | + Example: |
| 148 | + Optimize for Mobile |
| 149 | + item.optimize(targetTagID="Mobile") or item.optimize(targetTagID=1") |
| 150 | + Optimize for Android 10 MBPS 1080p |
| 151 | + item.optimize(deviceProfile="Android", videoQuality=10) |
| 152 | + Optimize for IOS Original Quality |
| 153 | + item.optimize(deviceProfile="IOS", videoQuality=-1) |
| 154 | +
|
| 155 | + * see sync.py VIDEO_QUALITIES for additional information for using videoQuality |
| 156 | + """ |
| 157 | + tagValues = [1, 2, 3] |
| 158 | + tagKeys = ["Mobile", "TV", "Original Quality"] |
| 159 | + tagIDs = tagKeys + tagValues |
| 160 | + |
| 161 | + if targetTagID not in tagIDs and (deviceProfile == None or videoQuality == None): |
| 162 | + raise BadRequest('Unexpected or missing quality profile.') |
| 163 | + |
| 164 | + from plexapi.sync import MediaSettings |
| 165 | + |
| 166 | + if title is None: |
| 167 | + title = self.title |
| 168 | + |
| 169 | + key = '/playlists/1111/items?' |
| 170 | + itemType = '%s=42' % quote_plus('Item[type]') |
| 171 | + itemTitle = '&%s=%s' % (quote_plus('Item[title]'), quote(title)) |
| 172 | + itemTarget = '&%s=%s' % (quote_plus('Item[target]'), quote_plus(target)) |
| 173 | + if isinstance(targetTagID, str): |
| 174 | + tagIndex = tagKeys.index(targetTagID) |
| 175 | + targetTagID = tagValues[tagIndex] |
| 176 | + |
| 177 | + itemTargetTagID = '&%s=%s' % (quote_plus('Item[targetTagID]'), targetTagID if targetTagID else "") |
| 178 | + itemLocationID = '&%s=%s' % (quote_plus('Item[locationID]'), locationID) |
| 179 | + section = self._server.library.sectionByID(self.librarySectionID) |
| 180 | + location = '%s=%s%s%s' % (quote_plus('Item[Location][uri]'), quote_plus('library://'), |
| 181 | + section.uuid, quote_plus('/item/')) |
| 182 | + itemLocationUri = '&%s%s' % (location, quote_plus(quote_plus('%s' % self.key))) |
| 183 | + itemPolicyScope = '&%s=%s' % (quote_plus('Item[Policy][scope]'), quote_plus(policyScope)) |
| 184 | + itemPolicyValue = '&%s=%s' % (quote_plus('Item[Policy][value]'), quote_plus(policyValue)) |
| 185 | + itemPolicyUnwatched = '&%s=%s' % (quote_plus('Item[Policy][unwatched]'), policyUnwatched) |
| 186 | + |
| 187 | + data = key + itemType + itemTitle + itemTarget + itemTargetTagID + itemLocationID + \ |
| 188 | + itemLocationUri + '%253FincludeExternalMedia%253D1' |
| 189 | + |
| 190 | + if deviceProfile: |
| 191 | + data += '&%s=%s' % (quote_plus('Item[Device][profile]'), deviceProfile) |
| 192 | + |
| 193 | + data += itemPolicyScope + itemPolicyValue + itemPolicyUnwatched |
| 194 | + |
| 195 | + if videoQuality: |
| 196 | + mediaSettings = MediaSettings.createVideo(videoQuality) |
| 197 | + data += '&%s=%s' % (quote_plus('Item[MediaSettings][videoQuality]'), mediaSettings.videoQuality) |
| 198 | + data += '&%s=%s' % (quote_plus('Item[MediaSettings][videoResolution]'), mediaSettings.videoResolution) |
| 199 | + data += '&%s=%s' % (quote_plus('Item[MediaSettings][maxVideoBitrate]'), mediaSettings.maxVideoBitrate) |
| 200 | + data += '&%s=%s' % (quote_plus('Item[MediaSettings][audioBoost]'), '') |
| 201 | + data += '&%s=%s' % (quote_plus('Item[MediaSettings][subtitleSize]'), '') |
| 202 | + data += '&%s=%s' % (quote_plus('Item[MediaSettings][musicBitrate]'), '') |
| 203 | + data += '&%s=%s' % (quote_plus('Item[MediaSettings][photoQuality]'), '') |
| 204 | + |
| 205 | + return self._server.query(data, method=self._server._session.put, headers={'X-Plex-Client-Identifier': "jzyhufx6t98rrjpce98b6irx"}) |
| 206 | + |
129 | 207 | def sync(self, videoQuality, client=None, clientId=None, limit=None, unwatched=False, title=None): |
130 | 208 | """ Add current video (movie, tv-show, season or episode) as sync item for specified device. |
131 | 209 | See :func:`plexapi.myplex.MyPlexAccount.sync()` for possible exceptions. |
|
0 commit comments