gpailler / MegaApiClient

MegaApiClient is a C# .Net library to access http://mega.co.nz / http://mega.nz cloud storage and file hosting service.
https://gpailler.github.io/MegaApiClient/
MIT License
225 stars 77 forks source link

Are there any plans to support multiple file downloading ? #163

Closed mediaexplorer74 closed 3 years ago

mediaexplorer74 commented 3 years ago

Hi, Grégoire!

I'm trying to use Your great Mega.Nz lib in my own UWP app (named "Megabox", utility to store some appxbundle files for Win10Mobile in future..).

The problem : I need to do multiple files downloads from my shared folder named W10MRepo: https://mega.nz/folder/YdlWiaxD#7qcjO0mtYukRBCuDzoIwGA

Code fragment :

 public MainPage()
        {
            this.InitializeComponent();

            Contact.MegaCount = 0; // counter init 

            var client = new MegaApiClient();

            // "no login"
            client.LoginAnonymous();

            Uri folderLink = new Uri("https://mega.nz/folder/YdlWiaxD#7qcjO0mtYukRBCuDzoIwGA"); // Test
            //Uri folderLink = new Uri("https://mega.nz/#F!SYtigRjB!EhNuflDF9fefSXuolgn0Rw"); // W10M

            // FromLink(folderLink) retrieves all files/folders metadata from Mega
            // so this method can be time consuming
            IEnumerable<INode> nodes = client.GetNodesFromLink(folderLink);

            // Get Parent node
            INode parent = nodes.Single(n => n.Type == NodeType.Root);

            DisplayNodesRecursive(nodes, parent);

            client.Logout();

        }

        //
        void DisplayNodesRecursive(IEnumerable<INode> nodes, INode parent, int level = 0)
        {
            IEnumerable<INode> children = nodes.Where(x => x.ParentId == parent.Id);
            foreach (INode child in children)
            {

                //string infos = $"- {child.Name} - {child.Size} bytes - {child.CreationDate}";
                string infos = $"- {child.Name} [{child.Id}]";

                //SuperWriteLine(infos.PadLeft(infos.Length + level, '\t'));
                SuperWriteLine(infos);

                // copy Name and Id 
                Contact.MegaFName[Contact.MegaCount] = child.Name;
                Contact.MegaFKey[Contact.MegaCount] = child.Id;

                // Increase counter 
                Contact.MegaCount++;

                if (child.Type == NodeType.Directory)
                {
                    DisplayNodesRecursive(nodes, child, level + 1);
                }
            }
        }

        // TODO: renovate this procedure =)
        void SuperWriteLine(string s)
        {
            ListViewItem lvi = new ListViewItem();

            lvi.Content = s;

            // add new item into ListView
            ListView01.Items.Add(lvi);
        }
...

Scenario: in ListView I select some item, and file must be downloaded for Mega.nz storage and be autolaunched.

My unsuccessful type of code ("item changed" handler for ListView):

 private async void Click_SelectChanged(object sender, SelectionChangedEventArgs e)
        {
            // Phase 1 - "Click / Tap " handle 
            ListView l1 = sender as ListView;
            int idx = l1.SelectedIndex;

            /*
            MessageDialog msgbox = new MessageDialog
            (
                "Key down: " +
                Contact.MegaFName[idx] + " [" +
                Contact.MegaFKey[idx] + "]"
            );

            msgbox.ShowAsync();
            */

            // Phase 2 - Download to storage  
            var client = new MegaApiClient();

            //"MEGA login"
            client.LoginAnonymous();

            // This 'path hack' NOT operates ;((((((((((((((
           Uri fileLink = new Uri("https://mega.nz/folder/SYtigRjB#EhNuflDF9fefSXuolgn0Rw/file/" + Contact.MegaFKey[idx]);

            INodeInfo node = client.GetNodeFromLink(fileLink);

            string FullLSPath = client.DownloadFile(fileLink, node.Name);

            StorageFolder folder = ApplicationData.Current.LocalFolder; 
            IReadOnlyList<StorageFile> files = await folder.GetFilesAsync();

            foreach (StorageFile ffile in files)
            {
                if (ffile.Path == FullLSPath)
                {
                    StorageFolder fLibrary = await KnownFolders.GetFolderForUserAsync(null, KnownFolderId.PicturesLibrary);
                    StorageFile fileCopy = await ffile.CopyAsync(fLibrary, node.Name, NameCollisionOption.ReplaceExisting);
                }
            }

            // "Logout"
            client.Logout();

            // Phase 3 - Launch result !

            // Path to the file in the app package to launch
            string appxFile = node.Name; //"SharedFile.jpg";
            //string appxFile ="run_test.appxbundle";

            StorageFolder localFolder = ApplicationData.Current.LocalFolder;

            // merge full path 
            string FullPath = localFolder.Path + "\\" + appxFile;

            var file = await localFolder.GetFileAsync(appxFile);

            if (file != null)
            {
                // Launch the retrieved file
                var success = await Windows.System.Launcher.LaunchFileAsync(file);

                if (success)
                {
                    // File launched
                }
                else
                {
                    // File launch failed
                }
            }
            else
            {
                // Could not find file
            }
        }

Please help, if You can...

MegaApiClient Version: special reconstructed for UWP compatibility

gpailler commented 3 years ago

Hi,

Instead of storing the node Name and Id in your Contact variable, I think that you can store the INode instance directly. This way, you will not have to recreate a new URI and you can call Download(INode) or DownloadFile(INode) with the previously retrieved INode instance. A second point is that's better to instantiate a single MegaApiClient instance for your application (instead of creating a new instance on each Click_SelectChanged call)

mediaexplorer74 commented 3 years ago

Good morning! :) Thank You, I will research Download(INode) DownloadFile(INode) methods. I noticed, INode objects have interesting structure: FullKey SharedId, etc... I hope, Mega.nz accepts simple folder/file downloading without decription at my app's side... and FullKey field will not needed/used... ?

A single MegaApiClient instance is good idea (ohhh... yes, my early preview/app prototype needs many improvements))

gpailler commented 3 years ago

Yes the INode objects contain important data like the decryption key that's why my proposal was that you store the INode instances instead of only the Id and Name

mediaexplorer74 commented 3 years ago

Thank You very much. I fix the algorythm . You get me great comments + I find your code samples, and now my new pre-alpha of MegaBox can download files from Mega.nz storage =) Its a kind of magic ! I continue researching other closed issues (to find some useful data for my project)) Have a nice day!

gpailler commented 3 years ago

You are welcome!