0

This is for a project where a user can download all their GitHub Gists.

This code gets the directory of the user's Download folder on their computer for files to download into. But what if the user's browser's download location is not the computer's Download folder? Maybe it's the Desktop or some random folder.

Am I supposed to check what browser the user is using and somehow get the path of where their download location is? Though a Google search says there's 200 different browsers...

Even if I was to ignore the user's browser's download location and save to the operating system's Download folder there are at least 33 according to a search.

    # Find the user's download folder
    
    # Get the operating system
    system = platform.system()

    # Set the path to save the files to the user's Download folder location
    if system == "Windows":
        save_path = os.path.join(os.environ['USERPROFILE'], 'Downloads')
    elif system == "Darwin":
        save_path = os.path.expanduser("~/Downloads")
    elif system == "Linux":
        save_path = os.path.expanduser("~/Downloads")
JAmes
  • 261
  • 1
  • 5
  • 15
  • @mkrieger1 he is trying to achieve universal way of getting download path, which is most likely undoable – sudden_appearance Jan 14 '23 at 22:43
  • 2
    The easiest way is just to ask the user with a prompt where he would like to save it – Seppe Willems Jan 14 '23 at 22:44
  • @mkrieger1 there is no problem with the code per se, the problem is that it ignores the user's browser's download location. I don't understand how when I change the download location, all downloads for me now download under that folder. What does the code look like that makes this happen? – JAmes Jan 14 '23 at 23:52
  • If he changes it through the browser settings then you can't track it, but if he changes it through windows settings or properties then the answer below is what you need, and should be used by default unless the user specifies otherwise, as all browsers will use this location by default – Ahmed AEK Jan 15 '23 at 00:37

1 Answers1

0

on windows to get the path of the Downloads folder, it should be done through win32Api, specifically through SHGetKnownFolderPath, python has access to it through ctypes, the way to access this specific function is taken from Windows Special and Known Folders from python stack overflow answer. with some modifications to read c_wchar_p.

you have to pass in the GUID for the downloads folder from KNOWNFOLDERID which is "{374DE290-123F-4565-9164-39C4925E467B}". , so you end up with the following code that works only on 64-bit python, for 32-bit you will probably have to change the argument types.

from ctypes import windll, wintypes
from ctypes import *
from uuid import UUID
from itertools import count
from functools import partial

# ctypes GUID copied from MSDN sample code
class GUID(Structure):
    _fields_ = [
        ("Data1", wintypes.DWORD),
        ("Data2", wintypes.WORD),
        ("Data3", wintypes.WORD),
        ("Data4", wintypes.BYTE * 8)
    ]

    def __init__(self, uuidstr):
        uuid = UUID(uuidstr)
        Structure.__init__(self)
        self.Data1, self.Data2, self.Data3, self.Data4[0], self.Data4[1], rest = uuid.fields
        for i in range(2, 8):
            self.Data4[i] = rest>>(8-i-1)*8 & 0xff

FOLDERID_Downloads = '{374DE290-123F-4565-9164-39C4925E467B}'

SHGetKnownFolderPath = windll.shell32.SHGetKnownFolderPath
SHGetKnownFolderPath.argtypes = [
    POINTER(GUID), wintypes.DWORD, wintypes.HANDLE, POINTER(c_char_p)]

def get_known_folder_path(uuidstr):
    pathptr = c_char_p()
    guid = GUID(uuidstr)
    if SHGetKnownFolderPath(byref(guid), 0, 0, byref(pathptr)):
        raise Exception('Whatever you want here...')
    resp = cast(pathptr,POINTER(c_wchar))
    iterator = (resp.__getitem__(i) for i in count(0))
    result = ''.join(list(iter(iterator.__next__, '\x00')))
    return result

print(get_known_folder_path(FOLDERID_Downloads))

this will return the Downloads folder location even if the user changes it through the properties, or for different languages.


on linux a similar method is to get it from $HOME/.config/user-dirs.dirs under the name of XDG_DOWNLOAD_DIR, which is changed with user settings changes.

$ grep XDG_DOWNLOAD_DIR ~/.config/user-dirs.dirs

XDG_DOWNLOAD_DIR="$HOME/Downloads"

This is obviously only the "default" location, you should allow the user to manually specify his own custom downloads path.

Using a hardcoded path is a recipe for "but it works on my machine", so just ask the OS about its path.

Ahmed AEK
  • 8,584
  • 2
  • 7
  • 23