How to determine the Dropbox folder location programmatically?

前端 未结 8 1109
故里飘歌
故里飘歌 2020-12-06 09:38

I have a script that is intended to be run by multiple users on multiple computers, and they don\'t all have their Dropbox folders in their respective home directories. I\'d

相关标签:
8条回答
  • 2020-12-06 10:16

    This adaptation based on J.F. Sebastian's suggestion works for me on Ubuntu:

    os.path.expanduser('~/Dropbox')
    

    And to actually set the working directory to be there:

    os.chdir(os.path.expanduser('~/Dropbox'))
    
    0 讨论(0)
  • 2020-12-06 10:17

    You could search the file system using os.walk. The Dropbox folder is probably within the home directory of the user, so to save some time you could limit your search to that. Example:

    import os
    dropbox_folder = None
    
    for dirname, dirnames, filenames in os.walk(os.path.expanduser('~')):
        for subdirname in dirnames:
            if(subdirname == 'Dropbox'):
                dropbox_folder = os.path.join(dirname, subdirname)
                break
        if dropbox_folder:
            break
    
    # dropbox_folder now contains the full path to the Dropbox folder, or
    # None if the folder wasn't found
    

    Alternatively you could prompt the user for the Dropbox folder location, or make it configurable via a config file.

    0 讨论(0)
  • 2020-12-06 10:17

    Note: requires Dropbox >= 2.8

    Dropbox now stores the paths in json format in a file called info.json. It is located in one of the two following locations:

    %APPDATA%\Dropbox\info.json
    %LOCALAPPDATA%\Dropbox\info.json
    

    I can access the %APPDATA% environment variable in Python by os.environ['APPDATA'], however I check both that and os.environ['LOCALAPPDATA']. Then I convert the JSON into a dictionary and read the 'path' value under the appropriate Dropbox (business or personal).

    Calling get_dropbox_location() from the code below will return the filepath of the business Dropbox, while get_dropbox_location('personal') will return the file path of the personal Dropbox.

    import os
    import json
    
    def get_dropbox_location(account_type='business'):
        """
        Returns a string of the filepath of the Dropbox for this user
    
        :param account_type: str, 'business' or 'personal'
        """
        info_path = _get_dropbox_info_path()
        info_dict = _get_dictionary_from_path_to_json(info_path)
        return _get_dropbox_path_from_dictionary(info_dict, account_type)
    
    def _get_dropbox_info_path():
        """
        Returns filepath of Dropbox file info.json
        """
        path = _create_dropox_info_path('APPDATA')
        if path:
            return path
        return _create_dropox_info_path('LOCALAPPDATA')
    
    def _create_dropox_info_path(appdata_str):
        r"""
        Looks up the environment variable given by appdata_str and combines with \Dropbox\info.json
    
        Then checks if the info.json exists at that path, and if so returns the filepath, otherwise
        returns False
        """
        path = os.path.join(os.environ[appdata_str], r'Dropbox\info.json')
        if os.path.exists(path):
            return path
        return False
    
    def _get_dictionary_from_path_to_json(info_path):
        """
        Loads a json file and returns as a dictionary
        """
        with open(info_path, 'r') as f:
            text = f.read()
    
        return json.loads(text)
    
    def _get_dropbox_path_from_dictionary(info_dict, account_type):
        """
        Returns the 'path' value under the account_type dictionary within the main dictionary
        """
        return info_dict[account_type]['path']
    

    This is a pure Python solution, unlike the other solution using info.json.

    0 讨论(0)
  • 2020-12-06 10:26

    This should work on Win7. The use of getEnvironmentVariable("APPDATA") instead of os.getenv('APPDATA') supports Unicode filepaths -- see question titled Problems with umlauts in python appdata environvent variable.

    import base64
    import ctypes
    import os
    
    def getEnvironmentVariable(name):
        """ read windows native unicode environment variables """
        # (could just use os.environ dict in Python 3)
        name = unicode(name) # make sure string argument is unicode
        n = ctypes.windll.kernel32.GetEnvironmentVariableW(name, None, 0)
        if not n:
            return None
        else:
            buf = ctypes.create_unicode_buffer(u'\0'*n)
            ctypes.windll.kernel32.GetEnvironmentVariableW(name, buf, n)
            return buf.value
    
    def getDropboxRoot():
        # find the path for Dropbox's root watch folder from its sqlite host.db database.
        # Dropbox stores its databases under the currently logged in user's %APPDATA% path.
        # If you have installed multiple instances of dropbox under the same login this only finds the 1st one.
        # Dropbox stores its databases under the currently logged in user's %APPDATA% path.
        # usually "C:\Documents and Settings\<login_account>\Application Data"
        sConfigFile = os.path.join(getEnvironmentVariable("APPDATA"),
                                   'Dropbox', 'host.db')
    
        # return null string if can't find or work database file.
        if not os.path.exists(sConfigFile):
            return None
    
        # Dropbox Watch Folder Location is base64 encoded as the last line of the host.db file.
        with open(sConfigFile) as dbxfile:
            for sLine in dbxfile:
                pass
    
        # decode last line, path to dropbox watch folder with no trailing slash.
        return base64.b64decode(sLine)
    
    if __name__ == '__main__':
        print getDropboxRoot()
    
    0 讨论(0)
  • 2020-12-06 10:27

    Note: answer is valid for Dropbox v2.8 and higher

    Windows

    jq -r ".personal.path" < %APPDATA%\Dropbox\info.json
    

    This needs jq - JSON parser utility to be installed. If you are happy user of Chocolatey package manager, just run choco install jq before.

    Linux

    jq -r ".personal.path" < ~/.dropbox/info.json 
    

    Just similarly to Windows install jq using package manager of your distro.

    0 讨论(0)
  • 2020-12-06 10:32

    I found the answer here. Setting s equal to the 2nd line in ~\AppData\Roaming\Dropbox\host.db and then decoding it with base64 gives the path.

    def _get_appdata_path():
        import ctypes
        from ctypes import wintypes, windll
        CSIDL_APPDATA = 26
        _SHGetFolderPath = windll.shell32.SHGetFolderPathW
        _SHGetFolderPath.argtypes = [wintypes.HWND,
                                     ctypes.c_int,
                                     wintypes.HANDLE,
                                     wintypes.DWORD,
                                     wintypes.LPCWSTR]
        path_buf = wintypes.create_unicode_buffer(wintypes.MAX_PATH)
        result = _SHGetFolderPath(0, CSIDL_APPDATA, 0, 0, path_buf)
        return path_buf.value
    
    def dropbox_home():
        from platform import system
        import base64
        import os.path
        _system = system()
        if _system in ('Windows', 'cli'):
            host_db_path = os.path.join(_get_appdata_path(),
                                        'Dropbox',
                                        'host.db')
        elif _system in ('Linux', 'Darwin'):
            host_db_path = os.path.expanduser('~'
                                              '/.dropbox'
                                              '/host.db')
        else:
            raise RuntimeError('Unknown system={}'
                               .format(_system))
        if not os.path.exists(host_db_path):
            raise RuntimeError("Config path={} doesn't exists"
                               .format(host_db_path))
        with open(host_db_path, 'r') as f:
            data = f.read().split()
    
        return base64.b64decode(data[1])
    
    0 讨论(0)
提交回复
热议问题