Need to see if your shared folder is taking up space on your dropbox 👨💻? Find out how to check here.
Forum Discussion
Justin P.2
10 years agoCollaborator | Level 10
Key Command/Shortcut to "Copy Dropbox Link" from Mac Finder.
I copy download links all day from the Mac Finder. It would be great to assign a key command so that you can highlight a file in your Dropbox via Mac Finder, and press a key command to copy the link ...
- 5 years ago
Update (2023-01-17)
I've moved the script to a repository and expanded on the instructions.
I wanted this now, so I wrote a Python script to get the URL from the command line and created an Automator QuickAction that calls the script with the selected file(s) in Finder:
Now, ^⌘L copies the Dropbox URL of any number of files selected in the Dropbox folder.
mbiaso
4 years agoExplorer | Level 4
the thing is, I'm trying to find a way where I don't need to point my mouse at the file....only the keyboard highlight wold be enough...
Gene_Parmesan
4 years agoCollaborator | Level 8
I don't think it's possible to fix either problem, unfortunately dhermanq. If the API can't find the file to create a shared link with (presumably because it's not yet fully uploaded), then that error makes sense. As to why it works when using the contextual menu item, I have no idea. Perhaps they're using another method which is unavailable to the Dropbox Python API. And the speed thing is unfortunate, but kind of comes with the territory of Automator/AppleScript. 😞
And mbiaso you're right, I forgot that the BTT action uses the location of the cursor, not the Finder selection. You have to use Automator to get that, which means you're back using my script. So follow the setup instructions and hopefully it will work for you.
- Здравко4 years agoLegendary | Level 20
Hi Gene_Parmesan,
Migrate your code to use refresh token (together with the access one). Otherwise your script users will need access token update by hands quite often. Also cache the access token and wipe out all calls not related to the link receiving to speed up the process (every call - meaningful or not - takes time).
- Gene_Parmesan3 years agoCollaborator | Level 8
Здравко wrote:Hi Gene_Parmesan,
Migrate your code to use refresh token (together with the access one). Otherwise your script users will need access token update by hands quite often. Also cache the access token and wipe out all calls not related to the link receiving to speed up the process (every call - meaningful or not - takes time).
Thanks for the suggetions. I've moved the code into a repo and would be hppy to accept a pull request.
- Здравко3 years agoLegendary | Level 20
Hi Gene_Parmesan,
I just made some illustrative implementation just to show what I mean. It can be used in the same way you used your script and instead of continuously changing access token, register your application and the access token will becomes updated automatically (without your intervention). The only change needed is set correct application key (your application key) once - at the beginning. Don't forget to register correct redirect URL in your application.
#!/usr/bin/python3 ############################################################################### # Script receiving Dropbox links based on referred local files/folders # -------------------------------------------------------------------- # Every target file/folder is passed as argument to the script. Resulted links # are passed in the same sequence one per line to standard output (incorrect # are skipped). # Two preparation steps are needed: # 1. Register a Dropbox application and put the application key as value of # APPLICATION_KEY global variable. # 2. Register the used REDIRECT_URI in the application just created in # previous step. With host 'localhost' and port 8080, the redirect URL # that has to be registered is "http://localhost:8080/", for instance. # Next, just make it executable (if needed), using: # $ chmod a+x get_dropbox_link # ... and put it in a place visible for execution in your system (somewhere in # folders pointed by $PATH environment variable). On first run you will be # invited to link your script to your Dropbox account. To work correct local # Dropbox application and this script have to be link to the same account! # Author: Здравко # www.dropboxforum.com/t5/user/viewprofilepage/user-id/422790 ############################################################################### from dropbox import Dropbox, DropboxOAuth2Flow from dropbox.exceptions import ApiError from dropbox.oauth import NotApprovedException import json from pathlib import Path from datetime import datetime from os import sep from sys import exit import logging # Place to save current configuration CONFIG_JSON='~/.getlink_conf.json' # Take a look on your application in https://www.dropbox.com/developers/apps APPLICATION_KEY='PUT YOUR KEY HERE' URI_HOST='localhost' URI_PORT=8080 # URI should be registered in the application redirect URIs list!!! REDIRECT_URI=f"http://{URI_HOST}:{URI_PORT}/" HOST_PORT=(URI_HOST,URI_PORT) success_response = "End of authentication flow. Your can get a link!" cancel_response = "🤷 You have denied your application's work. " error_response = " You got an error: " class ApplicationConfig: def __init__(self, conf_path=CONFIG_JSON): self.conf_path=Path(conf_path).expanduser() self.conf=None self.client=None self.access_token=None self.access_token_expiresat=None self.refresh_token=None if self.conf_path.is_file(): try: with self.conf_path.open() as fconf: self.conf=json.load(fconf) self.access_token = self.conf['access_token'] self.access_token_expiresat = datetime.fromtimestamp( self.conf['access_token_expiresat']) self.refresh_token = self.conf['refresh_token'] except Exception: self.conf_path.unlink(True) self.conf=None def __del__(self): "Checks for something changed (new access token) and dumps it when there is" if (self.client is not None and self.client._oauth2_access_token_expiration > self.access_token_expiresat): self.conf['access_token'] = self.client._oauth2_access_token self.conf['access_token_expiresat'] = ( self.client._oauth2_access_token_expiration.timestamp()) self.conf['refresh_token'] = self.client._oauth2_refresh_token with self.conf_path.open(mode='w') as fconf: json.dump(self.conf, fconf) def getClient(self): "Gets Dropbox client object. Performs OAuth flow if needed." if self.conf is None: self.client=None import webbrowser from http.server import HTTPServer, BaseHTTPRequestHandler dbxAuth=DropboxOAuth2Flow(APPLICATION_KEY, REDIRECT_URI, {}, 'dropbox-auth-csrf-token', token_access_type='offline', use_pkce=True) webbrowser.open(dbxAuth.start()) conf=None conf_path = self.conf_path class Handler(BaseHTTPRequestHandler): response_success = success_response.encode() response_cancel = cancel_response.encode() response_error = error_response.encode() def do_GET(self): nonlocal dbxAuth, conf from urllib.parse import urlparse, parse_qs query = parse_qs(urlparse(self.path).query) for r in query.keys(): query[r] = query[r][0] self.send_response(200) self.send_header("content-type", "text/plain;charset=UTF-8") try: oauthRes = dbxAuth.finish(query) conf={'access_token': oauthRes.access_token, 'access_token_expiresat': oauthRes.expires_at.timestamp(), 'refresh_token': oauthRes.refresh_token} with conf_path.open(mode='w') as fconf: json.dump(conf, fconf) except NotApprovedException: conf={} self.send_header("content-length", f"{len(Handler.response_cancel)}") self.end_headers() self.wfile.write(Handler.response_cancel) self.wfile.flush() return except Exception as e: conf={} r = Handler.response_error + str(e).encode() self.send_header("content-length", f"{len(r)}") self.end_headers() self.wfile.write(r) self.wfile.flush() return self.send_header("content-length", f"{len(Handler.response_success)}") self.end_headers() self.wfile.write(Handler.response_success) self.wfile.flush() httpd=HTTPServer((URI_HOST, URI_PORT), Handler) while conf is None: httpd.handle_request() httpd.server_close() del httpd if 'refresh_token' not in conf: raise RuntimeError("Cannot process because missing authentication") self.conf = conf self.access_token = self.conf['access_token'] self.access_token_expiresat = datetime.fromtimestamp( self.conf['access_token_expiresat']) self.refresh_token = self.conf['refresh_token'] # Makes sure there is cached client object. if self.client is None: self.client=Dropbox(self.access_token, oauth2_refresh_token=self.refresh_token, oauth2_access_token_expiration=self.access_token_expiresat, app_key=APPLICATION_KEY) return self.client class PathMapper: def __init__(self): dbx_info = Path('~/.dropbox/info.json').expanduser() if not dbx_info.is_file(): raise RuntimeError("Missing Dropbox application information") with dbx_info.open() as finfo: # Only personal accounts are supported by now - group accounts need # additional namespace handling (just changing 'personal' is not enough). # Somebody else may make some exercises. self.dbx_path = json.load(finfo)['personal']['path'] def __contains__(self, path): path = str(Path(path).expanduser().absolute()) return ((len(path) == len(self.dbx_path) and path == self.dbx_path) or (len(path) > len(self.dbx_path) and path[len(self.dbx_path)] == sep and path[:len(self.dbx_path)] == self.dbx_path)) def __getitem__(self, path): path = str(Path(path).expanduser().absolute()) if ((len(path) == len(self.dbx_path) and path == self.dbx_path) or (len(path) > len(self.dbx_path) and path[len(self.dbx_path)] == sep and path[:len(self.dbx_path)] == self.dbx_path)): return path[len(self.dbx_path):] def main(): import argparse dbxPathMap = PathMapper() parser = argparse.ArgumentParser(description="Fetch Dropbox URL for path") parser.add_argument("paths", type=str, nargs="+", help="paths to files") parser.add_argument("--verbose", "-v", action="store_true", help="toggle verbose mode") args = parser.parse_args() del parser if args.verbose: logging.basicConfig(level=logging.DEBUG) conf = ApplicationConfig() dbx = conf.getClient() for path in args.paths: if path not in dbxPathMap: logging.error(f"Passed path '{path}' is not part of the Dropbox driectory tree") continue dbx_path = dbxPathMap[path] if len(dbx_path) == 0: logging.error("Dropbox folder itself cannot be pointed by link") continue logging.debug(f"Processing local file '{path}' with Dropbox path '{dbx_path}'") try: metadata = dbx.sharing_create_shared_link_with_settings(dbx_path) except ApiError as e: er = e.error if not er.is_shared_link_already_exists(): raise er = er.get_shared_link_already_exists() if not er.is_metadata(): raise metadata = er.get_metadata() print(metadata.url) if __name__ == "__main__": try: main() except Exception as e: logging.error(f"Unexpected error: {e}") exit(1)There are some imperfections mentioned in comments that you can improve. 😉 One thing that can be improved too is plain text response replace to HTML (better views in web browser).
Good luck.
About View, download, and export
Need support with viewing, downloading, and exporting files and folders from your Dropbox account? Find help from the Dropbox Community.
The Dropbox Community team is active from Monday to Friday. We try to respond to you as soon as we can, usually within 2 hours.
If you need more help you can view your support options (expected response time for an email or ticket is 24 hours), or contact us on X, Facebook or Instagram.
For more info on available support options for your Dropbox plan, see this article.
If you found the answer to your question in this Community thread, please 'like' the post to say thanks and to let us know it was useful!