omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    NAS Access

    Pythonista
    pythonista nas
    6
    30
    17173
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • unad13
      unad13 last edited by

      I have a collection of mp3 files on a NAS on my local network. I'd like to read the mp3 tags of some of these files using Pythonista. Can I access a file using its UNC path (e.g. "\NAS\Media\Music\Artist\Album\Song.mp3")? When I try to open that path, I get a "No such file or directory" exception.

      It's a huge library and I don't want to put it in Dropbox.

      1 Reply Last reply Reply Quote 0
      • dgelessus
        dgelessus last edited by

        Non-Windows systems generally don't support UNC paths (or any sort of path with backslashes as separators). On macOS you can use a smb: URL instead, in your case that would be smb://NAS/Media/Music/Artist/Album/Song.mp3. However iOS doesn't support network shares natively like macOS does, so opening a file from a SMB share isn't as straightforward as on macOS.

        You could search on PyPI and see if you can find a library for accessing SMB shares. If it's written in pure Python, you can probably install it in Pythonista using Stash's pip command.

        1 Reply Last reply Reply Quote 0
        • cvp
          cvp last edited by

          Personally, I use FTP to access my NAS

          1 Reply Last reply Reply Quote 0
          • brumm
            brumm last edited by

            SMBclient

            cvp 1 Reply Last reply Reply Quote 1
            • cvp
              cvp @brumm last edited by cvp

              @brumm Hello, I want to use your smbclient but I see it needs to run in Python 2.
              Would it be possible to run it in Python 3?
              Or more generally, can I run a Python 3 script and call functions of a Python 2 imported module?

              Edit: I see that two days ago, the needed impacket does not yet support Python 3

              1 Reply Last reply Reply Quote 0
              • brumm
                brumm last edited by

                @cvp: My first library was pysmb, but then I switched to impacket, because of this issue. However it is fixed and pysmb is Python 3 ready. Of course you have to change the smb calls... Do you like to try it?

                cvp 2 Replies Last reply Reply Quote 0
                • cvp
                  cvp @brumm last edited by

                  @brumm Yes, I would try in a few days. Thanks

                  1 Reply Last reply Reply Quote 0
                  • cvp
                    cvp @brumm last edited by cvp

                    @brumm do yo want to say I could use this

                    And is pysmb from here

                    1 Reply Last reply Reply Quote 0
                    • brumm
                      brumm last edited by

                      @cvp oh yes, this is my first try. I think it should be a good start. Let me know when I can support you. And I saw there's another dependency - pyasn1, but it is also python3 ready.

                      cvp 2 Replies Last reply Reply Quote 0
                      • cvp
                        cvp @brumm last edited by

                        @brumm Thanks for your future help, I'm sure I'll need it but not before some days.

                        1 Reply Last reply Reply Quote 0
                        • cvp
                          cvp @brumm last edited by cvp

                          @brumm I want to thank you one more time. I'm more than happy with your marvelous little test script. I have

                          • installed your smb-test.py
                          • installed python 3 version of smb and nmb
                          • from https://github.com/miketeo/pysmb/tree/master/python3
                          • installed pyasn1 (supporting python 3)
                          • from https://github.com/etingof/pyasn1
                          • tested getRemoteDir => ok
                          • tested download => errors
                          •   modified to use BytesIO instead of StringIo
                            
                          •   				 to open local file as 'wb'
                            
                          • tested upload => ok
                          •   after same modif (open local file as 'rb')
                            
                          • tested delete_remote_file => ok
                          • tested getServiceName => ok
                          • tested getBIOSName => ok (ip -> name)
                          • tested createRemoteDir => ok
                            #- tested removeRemoteDir => ok (after correction, see here-under)
                          • original code of smb-test.py did contain two removeRemoteDir
                          •   second one should be renameRemoteFileOrDir
                            
                          • tested renameRemoteFileOrDir => ok (for a dir)
                          • tested renameRemoteFileOrDir => ok (for a file)
                          • as my ip is dynamic, I created a new def getIP from fixed remote name
                          • tested getIP => ok (name -> ip)

                          This has been a lot easier than I thought...
                          Now, I'll integrate that in my script, without connecting and closing the SMBconnection at each access.

                          def getIP(remote_name, timeout=5):
                            try:
                              bios = NetBIOS()
                              ip = bios.queryName(remote_name)
                            except Exception as e:
                              print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
                            finally:
                              bios.close()
                              return ip[0]
                          
                          1 Reply Last reply Reply Quote 0
                          • cvp
                            cvp last edited by cvp

                            And I put this in site-packages

                            # -*- coding: utf-8 -*-
                            # based   on   https://github.com/humberry/smb-example/blob/master/smb-test.py
                            # smb+nmb from https://github.com/miketeo/pysmb/tree/master/python3
                            # pyasn1  from https://github.com/etingof/pyasn1
                            from io import BytesIO
                            from smb.SMBConnection import SMBConnection
                            from smb import smb_structs
                            from nmb.NetBIOS import NetBIOS
                            import os
                            import sys
                            from socket import gethostname
                            
                            class SMB_client():
                            	def __init__(self,username=None,password=None,smb_name=None):
                            		self.username     = username
                            		self.password     = password
                            		self.smb_name     = smb_name
                            		self.smb_ip       = None
                            		self.conn         = None
                            		self.service_name = None
                            		self.my_name      = None
                            		self.tree         = []
                            
                            	def getBIOSName(self, remote_smb_ip, timeout=5):			# unused if dynamic IP
                            		# ip -> smb name
                            		try:
                            			bios = NetBIOS()
                            			srv_name = bios.queryIPForName(remote_smb_ip, timeout=timeout)
                            			return srv_name[0]
                            		except Exception as e:
                            			print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
                            			return None
                            			
                            	def getIP(self):
                            		# smb name -> ip
                            		try:
                            			bios = NetBIOS()
                            			ip = bios.queryName(self.smb_name)
                            			return ip[0]
                            		except Exception as e:
                            			print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
                            			return None
                            			
                            	def connect(self):
                            		try:
                            			self.my_name = gethostname()				# iDevice name
                            			self.smb_ip = self.getIP()
                            			smb_structs.SUPPORT_SMB2 = True
                            			self.conn = SMBConnection(self.username, self.password, self.my_name, self.smb_name, use_ntlm_v2 = True)
                            			self.conn.connect(self.smb_ip, 139)		#139=NetBIOS / 445=TCP
                            			if self.conn:
                            				shares = self.conn.listShares()
                            				for share in shares:
                            					if share.type == 0:		# 0 = DISK_TREE
                            						self.service_name = share.name  
                            		except Exception as e:
                            			print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
                            			
                            	def close(self):
                            		try:
                            			self.conn.close()
                            		except Exception as e:
                            			print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)			
                             
                            	def getRemoteDir(self, path, pattern):
                            		try:
                            			files = self.conn.listPath(self.service_name, path, pattern=pattern)
                            			return files
                            		except Exception as e:
                            			print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
                            			return None
                            				
                            	def getRemoteTree(self,path=''):
                            		try:
                            			if path == '':
                            				w = ''
                            			else:
                            				w = path+'/'
                            			files = self.getRemoteDir(path, '*')
                            			if files:
                            				for file in files:
                            					if file.filename[0] == '.':
                            						continue
                            					self.tree.append({'name':w+file.filename, 'isdir':file.isDirectory, 'size':file.file_size})
                            					if file.isDirectory:
                            						self.getRemoteTree(path=w+file.filename)
                            			return self.tree
                            		except Exception as e:
                            			print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
                            			return None
                            
                            	def download(self, path, filename):
                            		try:
                            			print('Download = ' + path + filename)
                            			attr = self.conn.getAttributes(self.service_name, path+filename)
                            			print('Size = %.1f kB' % (attr.file_size / 1024.0))
                            			print('start download')
                            			file_obj = BytesIO()
                            			file_attributes, filesize = self.conn.retrieveFile(self.service_name, path+filename, file_obj)
                            			fw = open(filename, 'wb')
                            			file_obj.seek(0)
                            			for line in file_obj:
                            				fw.write(line)
                            			fw.close()
                            			print('download finished')
                            		except Exception as e:
                            			print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
                            
                            	def upload(self, path, filename):
                            		try:
                            			print('Upload = ' + path + filename)
                            			print('Size = %.1f kB' % (os.path.getsize(filename) / 1024.0))
                            			print('start upload')
                            			with open(filename, 'rb') as file_obj:
                            				filesize = self.conn.storeFile(self.service_name, path+filename, file_obj)
                            			print('upload finished')
                            		except Exception as e:
                            			print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
                            
                            	def delete_remote_file(self,path, filename):
                            		try:
                            			self.conn.deleteFiles(self.service_name, path+filename)
                            			print('Remotefile ' + path + filename + ' deleted')
                            		except Exception as e:
                            			print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
                            
                            	def createRemoteDir(self, path):
                            		try:
                            			self.conn.createDirectory(self.service_name, path)
                            		except Exception as e:
                            			print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
                              
                            	def removeRemoteDir(self,path):
                            		try:
                            			self.conn.deleteDirectory(self.service_name, path)
                            		except Exception as e:
                            			print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
                            
                            	def renameRemoteFileOrDir(self,old_path, new_path):
                            		try:
                            			self.conn.rename(self.service_name, old_path, new_path)
                            		except Exception as e:
                            			print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
                            

                            Use like

                            from SMB_client import SMB_client
                            
                            my_smb = SMB_client(username='xxxxx',password='yuyy',smb_name='zzzzzz')
                            my_smb.connect()
                            
                            tree = my_smb.getRemoteTree()
                            for elem in tree:
                            	print(elem)
                            		
                            #my_smb.download(path, filename)
                            #my_smb.upload(path, filename)
                            #my_smb.delete_remote_file(path, filename)
                            #my_smb.createRemoteDir(path)
                            #my_smb.removeRemoteDir(path)
                            #my_smb.renameRemoteFileOrDir(path, new_path)
                            
                            my_smb.close()
                            
                            1 Reply Last reply Reply Quote 1
                            • brumm
                              brumm last edited by

                              I'm very happy that the code was useable.

                              cvp 2 Replies Last reply Reply Quote 0
                              • cvp
                                cvp @brumm last edited by

                                @brumm Without your code, I never could get this smb working. Sincerely, thanks a lot

                                1 Reply Last reply Reply Quote 0
                                • cvp
                                  cvp @brumm last edited by

                                  @brumm If you want to add some callback to upload and download...

                                  	def download(self, path, filename,buffersize=None,callback=None):
                                  		try:
                                  			#print('Download = ' + path + filename)
                                  			attr = self.conn.getAttributes(self.service_name, path+filename)
                                  			#print('Size = %.1f kB' % (attr.file_size / 1024.0))
                                  			#print('start download')
                                  			file_obj = BytesIO()
                                  			fw = open(filename, 'wb')
                                  			offset = 0
                                  			transmit =0
                                  			while True:
                                  				if not buffersize:
                                  					file_attributes, filesize = self.conn.retrieveFile(self.service_name, path+filename, file_obj)
                                  				else:
                                  					file_attributes, filesize = self.conn.retrieveFileFromOffset(self.service_name, path+filename, file_obj,offset=offset,max_length=buffersize)
                                  					if callback:
                                  						transmit = transmit + filesize
                                  						callback(transmit)
                                  				file_obj.seek(offset)
                                  				for line in file_obj:
                                  					fw.write(line)
                                  				offset = offset + filesize
                                  				if (not buffersize) or (filesize == 0):
                                  					break
                                  			fw.close()
                                  			#print('download finished')
                                  		except Exception as e:
                                  			print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
                                  			
                                  	def upload(self, path, filename,buffersize=None,callback=None):
                                  		try:
                                  			#print('Upload = ' + path + filename)
                                  			#print('Size = %.1f kB' % (os.path.getsize(filename) / 1024.0))
                                  			#print('start upload')
                                  			file_obj = open(filename, 'rb')
                                  			offset = 0
                                  			while True:
                                  				if not buffersize:
                                  					filesize = self.conn.storeFile(self.service_name, path+filename, file_obj)
                                  					break
                                  				else:	
                                  					buffer_obj = file_obj.read(buffersize)			
                                  					if buffer_obj:
                                  						buffer_fileobj = BytesIO()
                                  						buffer_fileobj.write(buffer_obj)
                                  						buffer_fileobj.seek(0)
                                  						offset_new = self.conn.storeFileFromOffset(self.service_name, path+filename, buffer_fileobj, offset=offset, truncate=False)
                                  						#return the file position where the next byte will be written.
                                  						offset = offset_new
                                  						if callback:
                                  							callback(offset)
                                  					else:
                                  						break
                                  			file_obj.close()
                                  			#print('upload finished')
                                  		except Exception as e:
                                  			print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)```
                                  1 Reply Last reply Reply Quote 0
                                  • brumm
                                    brumm last edited by

                                    @cvp Please feel free to upload it to your own github site, if you like. It's okay for me.

                                    cvp 2 Replies Last reply Reply Quote 0
                                    • cvp
                                      cvp @brumm last edited by cvp

                                      @brumm ok, Thanks, I'll do it

                                      Edit: done at https://github.com/cvpe/Pythonista-scripts

                                      1 Reply Last reply Reply Quote 0
                                      • cvp
                                        cvp @brumm last edited by

                                        @brumm As you have deeply studied SMB, I have a little question .
                                        I use it to access (read and write) an USB key connected to an USB slot of my internet router.
                                        Do you think I can remove safely the USB key as soon I have closed the smb connection?

                                        1 Reply Last reply Reply Quote 0
                                        • brumm
                                          brumm last edited by brumm

                                          @cvp I guess that your internet router has no (or a small) read/write buffer. Before you lose data I would recommend to use a USB key with a LED, to get sure that your router has enough time to write all data.

                                          cvp 1 Reply Last reply Reply Quote 0
                                          • cvp
                                            cvp @brumm last edited by

                                            @brumm Thanks for the advice. But do you think that all buffers are flushed when the smb connection is closed?

                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            Powered by NodeBB Forums | Contributors