mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-06 21:21:15 -07:00
Update cloudinary==1.28.0
This commit is contained in:
parent
0325e9327f
commit
dcfd8abddd
7 changed files with 196 additions and 21 deletions
|
@ -38,7 +38,7 @@ CL_BLANK = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAA
|
||||||
URI_SCHEME = "cloudinary"
|
URI_SCHEME = "cloudinary"
|
||||||
API_VERSION = "v1_1"
|
API_VERSION = "v1_1"
|
||||||
|
|
||||||
VERSION = "1.26.0"
|
VERSION = "1.28.0"
|
||||||
|
|
||||||
USER_AGENT = "CloudinaryPython/{} (Python {})".format(VERSION, python_version())
|
USER_AGENT = "CloudinaryPython/{} (Python {})".format(VERSION, python_version())
|
||||||
""" :const: USER_AGENT """
|
""" :const: USER_AGENT """
|
||||||
|
|
|
@ -93,6 +93,25 @@ def resources_by_ids(public_ids, **options):
|
||||||
return call_api("get", uri, params, **options)
|
return call_api("get", uri, params, **options)
|
||||||
|
|
||||||
|
|
||||||
|
def resources_by_asset_ids(asset_ids, **options):
|
||||||
|
"""Retrieves the resources (assets) indicated in the asset IDs.
|
||||||
|
This method does not return deleted assets even if they have been backed up.
|
||||||
|
|
||||||
|
See: `Get resources by context API reference
|
||||||
|
<https://cloudinary.com/documentation/admin_api#get_resources>`_
|
||||||
|
|
||||||
|
:param asset_ids: The requested asset IDs.
|
||||||
|
:type asset_ids: list[str]
|
||||||
|
:param options: Additional options
|
||||||
|
:type options: dict, optional
|
||||||
|
:return: Resources (assets) as indicated in the asset IDs
|
||||||
|
:rtype: Response
|
||||||
|
"""
|
||||||
|
uri = ["resources", 'by_asset_ids']
|
||||||
|
params = dict(only(options, "tags", "moderations", "context"), asset_ids=asset_ids)
|
||||||
|
return call_api("get", uri, params, **options)
|
||||||
|
|
||||||
|
|
||||||
def resources_by_context(key, value=None, **options):
|
def resources_by_context(key, value=None, **options):
|
||||||
"""Retrieves resources (assets) with a specified context key.
|
"""Retrieves resources (assets) with a specified context key.
|
||||||
This method does not return deleted assets even if they have been backed up.
|
This method does not return deleted assets even if they have been backed up.
|
||||||
|
@ -123,10 +142,38 @@ def resource(public_id, **options):
|
||||||
resource_type = options.pop("resource_type", "image")
|
resource_type = options.pop("resource_type", "image")
|
||||||
upload_type = options.pop("type", "upload")
|
upload_type = options.pop("type", "upload")
|
||||||
uri = ["resources", resource_type, upload_type, public_id]
|
uri = ["resources", resource_type, upload_type, public_id]
|
||||||
params = only(options, "exif", "faces", "colors", "image_metadata", "cinemagraph_analysis",
|
params = _prepare_asset_details_params(**options)
|
||||||
|
return call_api("get", uri, params, **options)
|
||||||
|
|
||||||
|
|
||||||
|
def resource_by_asset_id(asset_id, **options):
|
||||||
|
"""
|
||||||
|
Returns the details of the specified asset and all its derived assets by asset id.
|
||||||
|
|
||||||
|
:param asset_id: The Asset ID of the asset
|
||||||
|
:type asset_id: string
|
||||||
|
:param options: Additional options
|
||||||
|
:type options: dict, optional
|
||||||
|
:return: Resource (asset) of a specific asset_id
|
||||||
|
:rtype: Response
|
||||||
|
"""
|
||||||
|
uri = ["resources", asset_id]
|
||||||
|
params = _prepare_asset_details_params(**options)
|
||||||
|
return call_api("get", uri, params, **options)
|
||||||
|
|
||||||
|
|
||||||
|
def _prepare_asset_details_params(**options):
|
||||||
|
"""
|
||||||
|
Prepares optional parameters for resource_by_asset_id API calls.
|
||||||
|
|
||||||
|
:param options: Additional options
|
||||||
|
:return: Optional parameters
|
||||||
|
|
||||||
|
:internal
|
||||||
|
"""
|
||||||
|
return only(options, "exif", "faces", "colors", "image_metadata", "cinemagraph_analysis",
|
||||||
"pages", "phash", "coordinates", "max_results", "quality_analysis", "derived_next_cursor",
|
"pages", "phash", "coordinates", "max_results", "quality_analysis", "derived_next_cursor",
|
||||||
"accessibility_analysis", "versions")
|
"accessibility_analysis", "versions")
|
||||||
return call_api("get", uri, params, **options)
|
|
||||||
|
|
||||||
|
|
||||||
def update(public_id, **options):
|
def update(public_id, **options):
|
||||||
|
@ -595,3 +642,32 @@ def restore_metadata_field_datasource(field_external_id, entries_external_ids, *
|
||||||
uri = [field_external_id, 'datasource_restore']
|
uri = [field_external_id, 'datasource_restore']
|
||||||
params = {"external_ids": entries_external_ids}
|
params = {"external_ids": entries_external_ids}
|
||||||
return call_metadata_api("post", uri, params, **options)
|
return call_metadata_api("post", uri, params, **options)
|
||||||
|
|
||||||
|
|
||||||
|
def reorder_metadata_field_datasource(field_external_id, order_by, direction=None, **options):
|
||||||
|
"""Reorders metadata field datasource. Currently, supports only value.
|
||||||
|
|
||||||
|
:param field_external_id: The ID of the metadata field.
|
||||||
|
:param order_by: Criteria for the order. Currently, supports only value.
|
||||||
|
:param direction: Optional (gets either asc or desc).
|
||||||
|
:param options: Additional options.
|
||||||
|
|
||||||
|
:rtype: Response
|
||||||
|
"""
|
||||||
|
uri = [field_external_id, 'datasource', 'order']
|
||||||
|
params = {'order_by': order_by, 'direction': direction}
|
||||||
|
return call_metadata_api('post', uri, params, **options)
|
||||||
|
|
||||||
|
|
||||||
|
def reorder_metadata_fields(order_by, direction=None, **options):
|
||||||
|
"""Reorders metadata fields.
|
||||||
|
|
||||||
|
:param order_by: Criteria for the order (one of the fields 'label', 'external_id', 'created_at').
|
||||||
|
:param direction: Optional (gets either asc or desc).
|
||||||
|
:param options: Additional options.
|
||||||
|
|
||||||
|
:rtype: Response
|
||||||
|
"""
|
||||||
|
uri = ['order']
|
||||||
|
params = {'order_by': order_by, 'direction': direction}
|
||||||
|
return call_metadata_api('put', uri, params, **options)
|
||||||
|
|
|
@ -97,9 +97,7 @@ def sub_account(sub_account_id, **options):
|
||||||
return _call_account_api("get", uri, {}, **options)
|
return _call_account_api("get", uri, {}, **options)
|
||||||
|
|
||||||
|
|
||||||
def update_sub_account(sub_account_id, name=None, cloud_name=None, custom_attributes=None,
|
def update_sub_account(sub_account_id, name=None, cloud_name=None, custom_attributes=None, enabled=None, **options):
|
||||||
enabled=None, base_account=None,
|
|
||||||
**options):
|
|
||||||
"""
|
"""
|
||||||
Update a sub account
|
Update a sub account
|
||||||
:param sub_account_id: The id of the sub account
|
:param sub_account_id: The id of the sub account
|
||||||
|
@ -112,8 +110,6 @@ def update_sub_account(sub_account_id, name=None, cloud_name=None, custom_attrib
|
||||||
:type custom_attributes: dict, optional
|
:type custom_attributes: dict, optional
|
||||||
:param enabled: Whether to create the account as enabled (default is enabled).
|
:param enabled: Whether to create the account as enabled (default is enabled).
|
||||||
:type enabled: bool, optional
|
:type enabled: bool, optional
|
||||||
:param base_account: ID of sub-account from which to copy settings
|
|
||||||
:type base_account: str, optional
|
|
||||||
:param options: Generic advanced options dict, see online documentation
|
:param options: Generic advanced options dict, see online documentation
|
||||||
:type options: dict, optional
|
:type options: dict, optional
|
||||||
:return: Updated sub account
|
:return: Updated sub account
|
||||||
|
@ -123,8 +119,7 @@ def update_sub_account(sub_account_id, name=None, cloud_name=None, custom_attrib
|
||||||
params = {"name": name,
|
params = {"name": name,
|
||||||
"cloud_name": cloud_name,
|
"cloud_name": cloud_name,
|
||||||
"custom_attributes": custom_attributes,
|
"custom_attributes": custom_attributes,
|
||||||
"enabled": enabled,
|
"enabled": enabled}
|
||||||
"base_account": base_account}
|
|
||||||
return _call_account_api("put", uri, params=params, **options)
|
return _call_account_api("put", uri, params=params, **options)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
import json
|
import json
|
||||||
from copy import deepcopy
|
|
||||||
|
|
||||||
from cloudinary.api_client.call_api import call_json_api
|
from cloudinary.api_client.call_api import call_json_api
|
||||||
|
from cloudinary.utils import unique
|
||||||
|
|
||||||
|
|
||||||
class Search:
|
class Search:
|
||||||
|
_KEYS_WITH_UNIQUE_VALUES = {
|
||||||
|
'sort_by': lambda x: next(iter(x)),
|
||||||
|
'aggregate': None,
|
||||||
|
'with_field': None,
|
||||||
|
}
|
||||||
|
|
||||||
"""Build and execute a search query."""
|
"""Build and execute a search query."""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.query = {}
|
self.query = {}
|
||||||
|
@ -42,7 +48,7 @@ class Search:
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
return json.dumps(self.query)
|
return json.dumps(self.as_dict())
|
||||||
|
|
||||||
def execute(self, **options):
|
def execute(self, **options):
|
||||||
"""Execute the search and return results."""
|
"""Execute the search and return results."""
|
||||||
|
@ -57,4 +63,12 @@ class Search:
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def as_dict(self):
|
def as_dict(self):
|
||||||
return deepcopy(self.query)
|
to_return = {}
|
||||||
|
|
||||||
|
for key, value in self.query.items():
|
||||||
|
if key in self._KEYS_WITH_UNIQUE_VALUES:
|
||||||
|
value = unique(value, self._KEYS_WITH_UNIQUE_VALUES[key])
|
||||||
|
|
||||||
|
to_return[key] = value
|
||||||
|
|
||||||
|
return to_return
|
||||||
|
|
|
@ -802,7 +802,7 @@ var slice = [].slice,
|
||||||
function TextLayer(options) {
|
function TextLayer(options) {
|
||||||
var keys;
|
var keys;
|
||||||
TextLayer.__super__.constructor.call(this, options);
|
TextLayer.__super__.constructor.call(this, options);
|
||||||
keys = ["resourceType", "resourceType", "fontFamily", "fontSize", "fontWeight", "fontStyle", "textDecoration", "textAlign", "stroke", "letterSpacing", "lineSpacing", "fontHinting", "fontAntialiasing", "text"];
|
keys = ["resourceType", "resourceType", "fontFamily", "fontSize", "fontWeight", "fontStyle", "textDecoration", "textAlign", "stroke", "letterSpacing", "lineSpacing", "fontHinting", "fontAntialiasing", "text", "textStyle"];
|
||||||
if (options != null) {
|
if (options != null) {
|
||||||
keys.forEach((function(_this) {
|
keys.forEach((function(_this) {
|
||||||
return function(key) {
|
return function(key) {
|
||||||
|
@ -886,6 +886,11 @@ var slice = [].slice,
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TextLayer.prototype.textStyle = function(textStyle) {
|
||||||
|
this.options.textStyle = textStyle;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* generate the string representation of the layer
|
* generate the string representation of the layer
|
||||||
|
@ -921,6 +926,10 @@ var slice = [].slice,
|
||||||
};
|
};
|
||||||
|
|
||||||
TextLayer.prototype.textStyleIdentifier = function() {
|
TextLayer.prototype.textStyleIdentifier = function() {
|
||||||
|
// Note: if a text-style argument is provided as a whole, it overrides everything else, no mix and match.
|
||||||
|
if (!Util.isEmpty(this.options.textStyle)) {
|
||||||
|
return this.options.textStyle;
|
||||||
|
}
|
||||||
var components;
|
var components;
|
||||||
components = [];
|
components = [];
|
||||||
if (this.options.fontWeight !== "normal") {
|
if (this.options.fontWeight !== "normal") {
|
||||||
|
|
|
@ -3,15 +3,14 @@ import json
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
import certifi
|
|
||||||
from six import string_types
|
from six import string_types
|
||||||
from urllib3 import PoolManager, ProxyManager
|
|
||||||
from urllib3.exceptions import HTTPError
|
from urllib3.exceptions import HTTPError
|
||||||
|
|
||||||
import cloudinary
|
import cloudinary
|
||||||
from cloudinary import utils
|
from cloudinary import utils
|
||||||
from cloudinary.exceptions import Error
|
|
||||||
from cloudinary.cache.responsive_breakpoints_cache import instance as responsive_breakpoints_cache_instance
|
from cloudinary.cache.responsive_breakpoints_cache import instance as responsive_breakpoints_cache_instance
|
||||||
|
from cloudinary.exceptions import Error
|
||||||
|
from cloudinary.utils import build_eager
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from urllib3.contrib.appengine import AppEngineManager, is_appengine_sandbox
|
from urllib3.contrib.appengine import AppEngineManager, is_appengine_sandbox
|
||||||
|
@ -24,6 +23,11 @@ try: # Python 2.7+
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from urllib3.packages.ordered_dict import OrderedDict
|
from urllib3.packages.ordered_dict import OrderedDict
|
||||||
|
|
||||||
|
try: # Python 3.4+
|
||||||
|
from pathlib import Path as PathLibPathType
|
||||||
|
except ImportError:
|
||||||
|
PathLibPathType = None
|
||||||
|
|
||||||
if is_appengine_sandbox():
|
if is_appengine_sandbox():
|
||||||
# AppEngineManager uses AppEngine's URLFetch API behind the scenes
|
# AppEngineManager uses AppEngine's URLFetch API behind the scenes
|
||||||
_http = AppEngineManager()
|
_http = AppEngineManager()
|
||||||
|
@ -58,7 +62,12 @@ def upload_image(file, **options):
|
||||||
|
|
||||||
|
|
||||||
def upload_resource(file, **options):
|
def upload_resource(file, **options):
|
||||||
result = upload_large(file, **options)
|
upload_func = upload
|
||||||
|
if hasattr(file, 'size') and file.size > UPLOAD_LARGE_CHUNK_SIZE:
|
||||||
|
upload_func = upload_large
|
||||||
|
|
||||||
|
result = upload_func(file, **options)
|
||||||
|
|
||||||
return cloudinary.CloudinaryResource(
|
return cloudinary.CloudinaryResource(
|
||||||
result["public_id"], version=str(result["version"]),
|
result["public_id"], version=str(result["version"]),
|
||||||
format=result.get("format"), type=result["type"],
|
format=result.get("format"), type=result["type"],
|
||||||
|
@ -363,6 +372,39 @@ def text(text, **options):
|
||||||
return call_api("text", params, **options)
|
return call_api("text", params, **options)
|
||||||
|
|
||||||
|
|
||||||
|
_SLIDESHOW_PARAMS = [
|
||||||
|
"notification_url",
|
||||||
|
"public_id",
|
||||||
|
"overwrite",
|
||||||
|
"upload_preset",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def create_slideshow(**options):
|
||||||
|
"""
|
||||||
|
Creates auto-generated video slideshows.
|
||||||
|
|
||||||
|
:param options: The optional parameters. See the upload API documentation.
|
||||||
|
|
||||||
|
:return: a dictionary with details about created slideshow
|
||||||
|
"""
|
||||||
|
options["resource_type"] = options.get("resource_type", "video")
|
||||||
|
|
||||||
|
params = {param_name: options.get(param_name) for param_name in _SLIDESHOW_PARAMS}
|
||||||
|
|
||||||
|
serialized_params = {
|
||||||
|
"timestamp": utils.now(),
|
||||||
|
"transformation": build_eager(options.get("transformation")),
|
||||||
|
"manifest_transformation": build_eager(options.get("manifest_transformation")),
|
||||||
|
"manifest_json": options.get("manifest_json") and utils.json_encode(options.get("manifest_json")),
|
||||||
|
"tags": options.get("tags") and utils.encode_list(utils.build_array(options["tags"])),
|
||||||
|
}
|
||||||
|
|
||||||
|
params.update(serialized_params)
|
||||||
|
|
||||||
|
return call_api("create_slideshow", params, **options)
|
||||||
|
|
||||||
|
|
||||||
def _save_responsive_breakpoints_to_cache(result):
|
def _save_responsive_breakpoints_to_cache(result):
|
||||||
"""
|
"""
|
||||||
Saves responsive breakpoints parsed from upload result to cache
|
Saves responsive breakpoints parsed from upload result to cache
|
||||||
|
@ -427,7 +469,10 @@ def call_api(action, params, http_headers=None, return_error=False, unsigned=Fal
|
||||||
if file:
|
if file:
|
||||||
filename = options.get("filename") # Custom filename provided by user (relevant only for streams and files)
|
filename = options.get("filename") # Custom filename provided by user (relevant only for streams and files)
|
||||||
|
|
||||||
if isinstance(file, string_types):
|
if PathLibPathType and isinstance(file, PathLibPathType):
|
||||||
|
name = filename or file.name
|
||||||
|
data = file.read_bytes()
|
||||||
|
elif isinstance(file, string_types):
|
||||||
if utils.is_remote_url(file):
|
if utils.is_remote_url(file):
|
||||||
# URL
|
# URL
|
||||||
name = None
|
name = None
|
||||||
|
|
|
@ -70,6 +70,7 @@ __URL_KEYS = [
|
||||||
|
|
||||||
__SIMPLE_UPLOAD_PARAMS = [
|
__SIMPLE_UPLOAD_PARAMS = [
|
||||||
"public_id",
|
"public_id",
|
||||||
|
"public_id_prefix",
|
||||||
"callback",
|
"callback",
|
||||||
"format",
|
"format",
|
||||||
"type",
|
"type",
|
||||||
|
@ -80,6 +81,8 @@ __SIMPLE_UPLOAD_PARAMS = [
|
||||||
"colors",
|
"colors",
|
||||||
"use_filename",
|
"use_filename",
|
||||||
"unique_filename",
|
"unique_filename",
|
||||||
|
"display_name",
|
||||||
|
"use_filename_as_display_name",
|
||||||
"discard_original_filename",
|
"discard_original_filename",
|
||||||
"filename_override",
|
"filename_override",
|
||||||
"invalidate",
|
"invalidate",
|
||||||
|
@ -89,6 +92,7 @@ __SIMPLE_UPLOAD_PARAMS = [
|
||||||
"eval",
|
"eval",
|
||||||
"proxy",
|
"proxy",
|
||||||
"folder",
|
"folder",
|
||||||
|
"asset_folder",
|
||||||
"overwrite",
|
"overwrite",
|
||||||
"moderation",
|
"moderation",
|
||||||
"raw_convert",
|
"raw_convert",
|
||||||
|
@ -526,6 +530,9 @@ def process_video_codec_param(param):
|
||||||
out_param = out_param + ':' + param['profile']
|
out_param = out_param + ':' + param['profile']
|
||||||
if 'level' in param:
|
if 'level' in param:
|
||||||
out_param = out_param + ':' + param['level']
|
out_param = out_param + ':' + param['level']
|
||||||
|
if param.get('b_frames') is False:
|
||||||
|
out_param = out_param + ':' + 'bframes_no'
|
||||||
|
|
||||||
return out_param
|
return out_param
|
||||||
|
|
||||||
|
|
||||||
|
@ -1089,6 +1096,10 @@ def build_multi_and_sprite_params(**options):
|
||||||
|
|
||||||
|
|
||||||
def __process_text_options(layer, layer_parameter):
|
def __process_text_options(layer, layer_parameter):
|
||||||
|
text_style = str(layer.get("text_style", ""))
|
||||||
|
if text_style and not text_style.isspace():
|
||||||
|
return text_style
|
||||||
|
|
||||||
font_family = layer.get("font_family")
|
font_family = layer.get("font_family")
|
||||||
font_size = layer.get("font_size")
|
font_size = layer.get("font_size")
|
||||||
keywords = []
|
keywords = []
|
||||||
|
@ -1247,7 +1258,7 @@ PREDEFINED_VARS = {
|
||||||
"context": "ctx"
|
"context": "ctx"
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceRE = "((\\|\\||>=|<=|&&|!=|>|=|<|/|-|\\+|\\*|\\^)(?=[ _])|(\\$_*[^_ ]+)|(?<!\\$)(" + \
|
replaceRE = "((\\|\\||>=|<=|&&|!=|>|=|<|/|-|\\+|\\*|\\^)(?=[ _])|(\\$_*[^_ ]+)|(?<![\\$:])(" + \
|
||||||
'|'.join(PREDEFINED_VARS.keys()) + "))"
|
'|'.join(PREDEFINED_VARS.keys()) + "))"
|
||||||
|
|
||||||
|
|
||||||
|
@ -1531,3 +1542,28 @@ def safe_cast(val, casting_fn, default=None):
|
||||||
return casting_fn(val)
|
return casting_fn(val)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
def __id(x):
|
||||||
|
"""
|
||||||
|
Identity function. Returns the passed in values.
|
||||||
|
"""
|
||||||
|
return x
|
||||||
|
|
||||||
|
|
||||||
|
def unique(collection, key=None):
|
||||||
|
"""
|
||||||
|
Removes duplicates from collection using key function
|
||||||
|
|
||||||
|
:param collection: The collection to remove duplicates from
|
||||||
|
:param key: The function to generate key from each element. If not passed, identity function is used
|
||||||
|
"""
|
||||||
|
if key is None:
|
||||||
|
key = __id
|
||||||
|
|
||||||
|
to_return = OrderedDict()
|
||||||
|
|
||||||
|
for element in collection:
|
||||||
|
to_return[key(element)] = element
|
||||||
|
|
||||||
|
return list(to_return.values())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue