88 "fmt"
99 "io"
1010 "net/http"
11+ "net/url"
1112 "path"
13+ "slices"
1214 "strconv"
1315 "strings"
1416 "time"
@@ -103,19 +105,39 @@ func init() {
103105 Advanced : true ,
104106 Help : "Wait N seconds for eventual consistency of the databases that support the backend operation" ,
105107 },
108+ {
109+ Name : "adjust_media_files_extensions" ,
110+ Default : true ,
111+ Advanced : true ,
112+ Help : "Cloudinary handles media formats as a file attribute and strips it from the name, which is unlike most other file systems" ,
113+ },
114+ {
115+ Name : "media_extensions" ,
116+ Default : []string {
117+ "3ds" , "3g2" , "3gp" , "ai" , "arw" , "avi" , "avif" , "bmp" , "bw" ,
118+ "cr2" , "cr3" , "djvu" , "dng" , "eps3" , "fbx" , "flif" , "flv" , "gif" ,
119+ "glb" , "gltf" , "hdp" , "heic" , "heif" , "ico" , "indd" , "jp2" , "jpe" ,
120+ "jpeg" , "jpg" , "jxl" , "jxr" , "m2ts" , "mov" , "mp4" , "mpeg" , "mts" ,
121+ "mxf" , "obj" , "ogv" , "pdf" , "ply" , "png" , "psd" , "svg" , "tga" ,
122+ "tif" , "tiff" , "ts" , "u3ma" , "usdz" , "wdp" , "webm" , "webp" , "wmv" },
123+ Advanced : true ,
124+ Help : "Cloudinary supported media extensions" ,
125+ },
106126 },
107127 })
108128}
109129
110130// Options defines the configuration for this backend
111131type Options struct {
112- CloudName string `config:"cloud_name"`
113- APIKey string `config:"api_key"`
114- APISecret string `config:"api_secret"`
115- UploadPrefix string `config:"upload_prefix"`
116- UploadPreset string `config:"upload_preset"`
117- Enc encoder.MultiEncoder `config:"encoding"`
118- EventuallyConsistentDelay fs.Duration `config:"eventually_consistent_delay"`
132+ CloudName string `config:"cloud_name"`
133+ APIKey string `config:"api_key"`
134+ APISecret string `config:"api_secret"`
135+ UploadPrefix string `config:"upload_prefix"`
136+ UploadPreset string `config:"upload_preset"`
137+ Enc encoder.MultiEncoder `config:"encoding"`
138+ EventuallyConsistentDelay fs.Duration `config:"eventually_consistent_delay"`
139+ MediaExtensions []string `config:"media_extensions"`
140+ AdjustMediaFilesExtensions bool `config:"adjust_media_files_extensions"`
119141}
120142
121143// Fs represents a remote cloudinary server
@@ -203,6 +225,18 @@ func (f *Fs) FromStandardPath(s string) string {
203225
204226// FromStandardName implementation of the api.CloudinaryEncoder
205227func (f * Fs ) FromStandardName (s string ) string {
228+ if f .opt .AdjustMediaFilesExtensions {
229+ parsedURL , err := url .Parse (s )
230+ ext := ""
231+ if err != nil {
232+ fs .Logf (nil , "Error parsing URL: %v" , err )
233+ } else {
234+ ext = path .Ext (parsedURL .Path )
235+ if slices .Contains (f .opt .MediaExtensions , strings .ToLower (strings .TrimPrefix (ext , "." ))) {
236+ s = strings .TrimSuffix (parsedURL .Path , ext )
237+ }
238+ }
239+ }
206240 return strings .ReplaceAll (f .opt .Enc .FromStandardName (s ), "&" , "\uFF06 " )
207241}
208242
@@ -212,8 +246,20 @@ func (f *Fs) ToStandardPath(s string) string {
212246}
213247
214248// ToStandardName implementation of the api.CloudinaryEncoder
215- func (f * Fs ) ToStandardName (s string ) string {
216- return strings .ReplaceAll (f .opt .Enc .ToStandardName (s ), "\uFF06 " , "&" )
249+ func (f * Fs ) ToStandardName (s string , assetUrl string ) string {
250+ ext := ""
251+ if f .opt .AdjustMediaFilesExtensions {
252+ parsedURL , err := url .Parse (assetUrl )
253+ if err != nil {
254+ fs .Logf (nil , "Error parsing URL: %v" , err )
255+ } else {
256+ ext = path .Ext (parsedURL .Path )
257+ if ! slices .Contains (f .opt .MediaExtensions , strings .ToLower (strings .TrimPrefix (ext , "." ))) {
258+ ext = ""
259+ }
260+ }
261+ }
262+ return strings .ReplaceAll (f .opt .Enc .ToStandardName (s ), "\uFF06 " , "&" ) + ext
217263}
218264
219265// FromStandardFullPath encodes a full path to Cloudinary standard
@@ -331,10 +377,7 @@ func (f *Fs) List(ctx context.Context, dir string) (fs.DirEntries, error) {
331377 }
332378
333379 for _ , asset := range results .Assets {
334- remote := api .CloudinaryEncoder .ToStandardName (f , asset .DisplayName )
335- if dir != "" {
336- remote = path .Join (dir , api .CloudinaryEncoder .ToStandardName (f , asset .DisplayName ))
337- }
380+ remote := path .Join (dir , api .CloudinaryEncoder .ToStandardName (f , asset .DisplayName , asset .SecureURL ))
338381 o := & Object {
339382 fs : f ,
340383 remote : remote ,
0 commit comments