uSync-Legacy icon indicating copy to clipboard operation
uSync-Legacy copied to clipboard

Unsupported not default Media File System

Open sebafelis opened this issue 7 years ago • 2 comments

Media files import/export doesn't work if project using other media file system (e.i. UmbracoFileSystemProviders.Azure).

I did modify "\uSync\Jumoo.uSync.Core\Helpers\uSyncMediaFileMover.cs" file to fix it. Here is complited solution:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Newtonsoft.Json;
using Jumoo.uSync.Core.Interfaces;

using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
using Umbraco.Core.Logging;

using System.Xml.Linq;

namespace Jumoo.uSync.Core.Helpers
{
    public class uSyncMediaFileMover : ISyncFileHander2<IMedia>
    {
        public IFileSystem FileSystem { get; set; } = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();

        [Obsolete("use ImportFileValue(XElement, IMedia, string")]
        public bool ImportFile(IMedia item, string folder)
        {
            return false;
        }

        public bool ImportFileValue(XElement node, IMedia item, string folder)
        {
            // 
            // if we have move media = false, we don't actually move 
            // the media file, we just let the user move the Media folder
            // so the internal umbracoFile values will be fine ?
            //
            if (!uSyncCoreContext.Instance.Configuration.Settings.MoveMedia)
            {
                LogHelper.Debug<uSyncMediaFileMover>("Media moving is off - media file not being moved");
                return true;
            }

            LogHelper.Debug<uSyncMediaFileMover>("\n--------------------- FILE MOVE ---------------");



            bool changes = false;
            Guid guid = item.Key;

            if (!Directory.Exists(folder))
                return false;

            if (!item.HasProperty(Umbraco.Core.Constants.Conventions.Media.File))
                return false;

            var filePath = item.GetValue<string>(Umbraco.Core.Constants.Conventions.Media.File);

            if (!string.IsNullOrEmpty(filePath))
            {
                if (filePath.DetectIsJson())
                {
                    filePath = JsonConvert.DeserializeObject<dynamic>(filePath).src;
                }
            }

            var umbracoFileValue = string.Empty;
            if (node.Element(Umbraco.Core.Constants.Conventions.Media.File) != null)
            {
                umbracoFileValue = node.Element(Umbraco.Core.Constants.Conventions.Media.File).Value;
            }

            foreach (var file in Directory.GetFiles(folder))
            {
                if (!string.IsNullOrEmpty(filePath) && FileSystem.FileExists(filePath))
                {
                    // compare current...
                    if (!FilesAreEqual(filePath, new FileInfo(file)))
                    {
                        string sourceFile = Path.GetFileName(file);

                        using (FileStream s = new FileStream(file, FileMode.Open))
                        {
                            item.SetValue(Umbraco.Core.Constants.Conventions.Media.File, null);
                            item.SetValue(Umbraco.Core.Constants.Conventions.Media.File, sourceFile, s);
                            changes = true;
                        }

                        var dirName = Path.GetDirectoryName(filePath);

                        // if we've created a new file in umbraco, it will be in a new folder
                        // and the old current file will need to be deleted.
                        if (FileSystem.DirectoryExists(dirName))
                            FileSystem.DeleteDirectory(dirName, true);
                    }
                }
                else
                {
                    // this is a new file.
                    using (FileStream s = new FileStream(file, FileMode.Open))
                    {
                        item.SetValue(Umbraco.Core.Constants.Conventions.Media.File, null);
                        item.SetValue(Umbraco.Core.Constants.Conventions.Media.File, Path.GetFileName(file), s);
                        changes = true;
                    }

                }
            }

            if (changes)
            {
                // if we are using image cropper then umbracoFile value will have been blasted a bit by the upload
                // we need to set it back here...
                // var newUmbracoFileValue = item.GetValue<string>(Umbraco.Core.Constants.Conventions.Media.File);

                if (umbracoFileValue.DetectIsJson())
                {
                    var newUmbracoFileValue = item.GetValue<string>(Umbraco.Core.Constants.Conventions.Media.File);

                    var oldObj = JsonConvert.DeserializeObject<dynamic>(umbracoFileValue);
                    var newSrc = newUmbracoFileValue;
                    if (newUmbracoFileValue.DetectIsJson())
                    {
                        newSrc = JsonConvert.DeserializeObject<dynamic>(newUmbracoFileValue).src;
                    }
                    oldObj.src = newSrc;

                    var fileVal = JsonConvert.SerializeObject(oldObj);
                    LogHelper.Debug<uSyncMediaFileMover>("JSON Value: {0}", () => fileVal);
                    IContentBase baseItem = (IContentBase)item;
                    baseItem.SetValue(Umbraco.Core.Constants.Conventions.Media.File, fileVal);
                }

                ApplicationContext.Current.Services.MediaService.Save(item);
            }

            return changes;
        }


        public bool ExportFile(IMedia item, string folder)
        {
            if (!uSyncCoreContext.Instance.Configuration.Settings.MoveMedia)
            {
                LogHelper.Debug<uSyncMediaFileMover>("Media moving is off - media file not being moved");
                return true;
            }

            foreach (var fileProperty in item.Properties.Where(p => p.Alias == Umbraco.Core.Constants.Conventions.Media.File))
            {
                if (fileProperty == null || fileProperty.Value == null)
                    continue;

                var umbracoFile = fileProperty.Value.ToString();

                var filePath = umbracoFile;
                if (umbracoFile.DetectIsJson())
                {
                    filePath = JsonConvert.DeserializeObject<dynamic>(umbracoFile).src;
                }

                string uSyncFolder = folder;
                string uSyncFile = Path.Combine(uSyncFolder, Path.GetFileName(filePath));

                if (FileSystem.FileExists(filePath))
                {
                    if (!Directory.Exists(uSyncFolder))
                        Directory.CreateDirectory(uSyncFolder);

                    using (var sourceStream = FileSystem.OpenFile(filePath))
                    using (var uSyncFileStream = System.IO.File.Create(uSyncFile))
                    {
                        sourceStream.CopyTo(uSyncFileStream);
                    }
                }
            }
            return true;
        }

        const int BYTES_TO_READ = sizeof(Int64);

        private bool FilesAreEqual(string firstFilePath, FileInfo second)
        {
            using (Stream fs1 = FileSystem.OpenFile(firstFilePath))
            {
                if (fs1.Length != second.Length)
                    return false;

                int iterations = (int)Math.Ceiling((double)fs1.Length / BYTES_TO_READ);


                using (FileStream fs2 = second.OpenRead())
                {
                    byte[] one = new byte[BYTES_TO_READ];
                    byte[] two = new byte[BYTES_TO_READ];

                    for (int i = 0; i < iterations; i++)
                    {
                        fs1.Read(one, 0, BYTES_TO_READ);
                        fs2.Read(two, 0, BYTES_TO_READ);

                        if (BitConverter.ToInt64(one, 0) != BitConverter.ToInt64(two, 0))
                            return false;
                    }
                }
            }
            return true;
        }
    }
}

sebafelis avatar Mar 08 '18 19:03 sebafelis

I did give usync a try in earlier versions and had issues with media. Since then moved the media to Azure via UmbracoFileSystemProviders.Azure, and been wondering how the uSync will behave in such case. A lot has changed and improved with uSync since then in terms of file name/folder handling. This post is very interesting in that regards, that I am interested to try with /media being in Azure.

Which version of uSync and Umbraco build did you use this code patch on?

akeilox avatar Mar 09 '18 04:03 akeilox

thanks, i will look into adding that,

With Umbraco 7.2 (i think) I have changed would i would consider the recommended way to deal with media and uSync - from that version the way umbraco generates the folder ID has moved from the DB to the disk (it just looks for the highest number).

this means you can just copy your media folder between installations and have uSync just do the setting up of the bit inside the database - the config line for this is <MoveMedia>false</MoveMedia> and this has been the default for a while now.

Working this way the actual media doesn't go into the uSync folder, you "just" need to keep your media folders in sync. the other way does still work (well not for blob stuff yet) but i have found the movemedia = false way to be more reliable

in terms of working this way - if you are syncing content between things, then i would configure your azure storage for your sites and have them all pointing to it - and then just let usync sync the database elements - as everyone will share the media folder you don't even need to copy it around.

KevinJump avatar Mar 09 '18 13:03 KevinJump