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 instead of right clicking.
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.
@markcq wrote: This doesn't really sense to me... I downloaded the script... no idea what to do with it... I tried to do the whole automation thing, but also don't know what to do with that... so just got dead-end and dead-end and dead-end... Surely by now DropBox would have done something around this... I use Copy Dropbox link anywhere from 10–100 times per day... honestly getting tired of right clicking (on a track pad) 10–100 times per day 😓
This doesn't really sense to me... I downloaded the script... no idea what to do with it... I tried to do the whole automation thing, but also don't know what to do with that... so just got dead-end and dead-end and dead-end... Surely by now DropBox would have done something around this... I use Copy Dropbox link anywhere from 10–100 times per day... honestly getting tired of right clicking (on a track pad) 10–100 times per day 😓
Sorry it's not working for you. Happy to try to answer specific questions, but there isn't enough information here to say what's wrong. I've expanded on the instructions a bit in a new repository, have a look and see if that helps. Definitely agree that Dropbox should allow this feature out of the box, it's really annoying that we have to set up workarounds like this.
@Здравко 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).
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.
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.
With the help of a user on GitHub, I have changed the script as suggested to use a refresh token and also to save and reuse the access token. I also found an unnecessary API call which was running each time and just slowing things down. So @dhermanq, please give this new version a try and see if it speeds things up for you.
I'd suggest everyone upgrade, since this no longer requires generating OAuth2 tokens on the website every few hours. It's a pretty big quality of life improvement.
Hi @DavidW2,
If you follow the install steps in @Gene_Parmesan's answer, but use my script (see above), doesn't it works? 🤔 If so, can you post details about what error are you getting? Again, it's unlikely the scripts, posted here (not only the my one), work on team/business account - some more coding has to be done, but not added yet (in all posted scripts), by now! For private/individual account (of any subscription type), it should work though. What is your subscription? 🧐
Yes, @DavidW2, it's just a minor change to App Key from generating an App Token. You can read full instructions in the README. I don't have a business account, but a previous poster said that they were able to get my script working by changing the ACCOUNT_TYPE variable, set as part of the README instructions. If there's more to it, unfortunately I'm not able to help with that.
I haven't tried running your script, @Здравко, although I did read it to puzzle out how your caching worked. That, along with this forum thread and some ideas on config files from this post went into the new design.
@Gene_Parmesan wrote: ...I haven't tried running your script, @Здравко, although I did read it to puzzle out how your caching worked. ...
...
I haven't tried running your script, @Здравко, although I did read it to puzzle out how your caching worked. ...
To be honest, I'm not sure can understand what you ask actually. 🤔 It's as trivial as possible. I just keep the authentication data ("refresh token", "access token", and access token' expiration time), both on Initial OAuth flow and on every refresh latter. On script start, when config is available, it's used for client object initialization, otherwise asks user for authorization. 🤷 That's it - nothing more.
By the way your script will fail if pointed file has a link already! You don't check/handle such situation. Do it. 😉
Hope this sheds some light.
I have repeatedly made links to the same file with no errors, so I haven't run into this issue. If you do experience a problem, you're welcome to open an issue in the repo with reproduction steps.
@Justin P.2 great that you provided a script as a proof of concept to Dropbox!
@Dropbox Team
Correction:
@Justin P.2thanks for raising this.
@Gene_Parmesan thanks for the script to prove it's possible.
@Gene_Parmesanthis is exciting! I've finally had the chance to try out the new version, starting from scratch with your instructions on GitHub. I've gotten to Step 12 (Call the script once and follow the instructions to get a refresh token the first time), however when I run the script from Terminal I get the following result:
Traceback (most recent call last):File "/Users/dherman/bin/get_dropbox_link.py", line 37, in <module>import dropboxFile "/Users/dherman/Library/Python/3.9/lib/python/site-packages/dropbox/__init__.py", line 3, in <module>from dropbox.dropbox_client import ( # noqa: F401 # pylint: disable=unused-importFile "/Users/dherman/Library/Python/3.9/lib/python/site-packages/dropbox/dropbox_client.py", line 18, in <module>import requestsFile "/Users/dherman/Library/Python/3.9/lib/python/site-packages/requests/__init__.py", line 43, in <module>import urllib3File "/Users/dherman/Library/Python/3.9/lib/python/site-packages/urllib3/__init__.py", line 38, in <module>raise ImportError(ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with LibreSSL 2.8.3. See: https://github.com/urllib3/urllib3/issues/2168
I tried moving forward with your instructions and created an Automator workflow to run the script, then used Keyboard Maestro to trigger it. This is the result:
Shell Script” encountered an error: “Traceback (most recent call last):File "/Users/dherman/bin/get_dropbox_link.py", line 37, in <module>import dropboxFile "/Users/dherman/Library/Python/3.9/lib/python/site-packages/dropbox/__init__.py", line 3, in <module>from dropbox.dropbox_client import ( # noqa: F401 # pylint: disable=unused-importFile "/Users/dherman/Library/Python/3.9/lib/python/site-packages/dropbox/dropbox_client.py", line 18, in <module>import requestsFile "/Users/dherman/Library/Python/3.9/lib/python/site-packages/requests/__init__.py", line 43, in <module>import urllib3File "/Users/dherman/Library/Python/3.9/lib/python/site-packages/urllib3/__init__.py", line 38, in <module>raise ImportError(ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with LibreSSL 2.8.3. See: https://github.com/urllib3/urllib3/issues/2168” 2023-05-19 14:43:26 Action 441 failed: Execute an Automator Workflow failed with script error: The action “Run Shell Script” encountered an error: “Traceback (most recent call last):File "/Users/dherman/bin/get_dropbox_link.py", line 37, in <module>import dropboxFile "/Users/dherman/Library/Python/3.9/lib/python/site-packages/dropbox/__init__.py", line 3, in <module>from dropbox.dropbox_client import ( # noqa: F401 # pylint: disable=unused-importFile "/Users/dherman/Library/Python/3.9/lib/python/site-packages/dropbox/dropbox_client.py", line 18, in <module>import requestsFile "/Users/dherman/Library/Python/3.9/lib/python/site-packages/requests/__init__.py", line 43, in <module>import urllib3File "/Users/dherman/Library/Python/3.9/lib/python/site-packages/urllib3/__init__.py", line 38, in <module>raise ImportError(ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with LibreSSL 2.8.3. See: https://github.com/urllib3/urllib3/issues/2168” 2023-05-19 14:43:26 Execute an Automator Workflow failed with script error: The action “Run Shell Script” encountered an error: “Traceback (most recent call last):File "/Users/dherman/bin/get_dropbox_link.py", line 37, in <module>import dropboxFile "/Users/dherman/Library/Python/3.9/lib/python/site-packages/dropbox/__init__.py", line 3, in <module>from dropbox.dropbox_client import ( # noqa: F401 # pylint: disable=unused-importFile "/Users/dherman/Library/Python/3.9/lib/python/site-packages/dropbox/dropbox_client.py", line 18, in <module>import requestsFile "/Users/dherman/Library/Python/3.9/lib/python/site-packages/requests/__init__.py", line 43, in <module>import urllib3File "/Users/dherman/Library/Python/3.9/lib/python/site-packages/urllib3/__init__.py", line 38, in <module>raise ImportError(ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with LibreSSL 2.8.3. See: https://github.com/urllib3/urllib3/issues/2168” in macro “Copy Dropbox Link” (while executing Execute “Copy Dropbox Link” Automator Workflow).
I'm a bit out of my depth as to what this all might mean -- if you have any thoughts they would be welcome and appreciated!
Thanks for giving the updated script a try, @dhermanq, sorry it’s not working for you. 🤔 Porg is having a similar issue, so clearly the instructions could use some refinement.There are several suggestions in this Stack Overflow issue. Because I’m not able to reproduce the issue, I fear it will be up to you to do the actual troubleshooting, but do report back if you find something that works.The first thing I’d try would be to install Dropbox this way:
python3 -m pip install dropbox
Unfortunately none of the suggestions work for me, because you lose me at:
"I had initially installed pip3 install dropbox (the module) as your README.md instructed."
What does that mean for a non-programmer? To be honest, the whole story is so convoluted that I get a headache just trying to read the instructions. So I manually right click on each item and copy the dropbox link (which I have to do many times per day)... Why is it so complicated for DB to just make a keyboard shortcut?
@dbox_Why is there not an option for this in System Preferences → Keyboard → Shortcuts → Services? Then we can make our own shortcut...
I've spent a bit more time with this and I think I've resolved the Python and Automator issues. Please see the new instructions in the repo README, and let me know if there are any further problems! @dhermanq @porg Note that I have fixed a problem with duplicate links caused by an unneeded "Get Selected Finder Items" action.
I've added threading too. Now even relatively large sets of links can be generated efficiently. There are 10 workers by default, hopefully that will strike a good balance between speed and keeping on the right side of any rate limits on Dropbox's API.
@Gene_Parmesan thanks for the additional help on this! I've made some progress with the new script and instructions. I took your suggestion to pin urllib3 to version 1.26.6, and that allowed me to generate the API access code. However, now when I try running my Automator workflow I get the following error:
The action “Run Shell Script” encountered an error: “usage: get_dropbox_link.py [-h] [--verbose] paths [paths ...]get_dropbox_link.py: error: the following arguments are required: paths” in macro “Copy Dropbox Link”
Would this have something to do with the fact that either a) I use a Dropbox business account (I've changed the AccountType variable in your script accordingly), or b) I keep my Dropbox files on a removable drive, and not the standard ~/Dropbox path?
I do appreciate for all the thought and attention you've put into this thus far!
You're almost there! This output means that the script IS running successfully, but it's not receiving the list of selected paths. My guess is that you are passing input "to stdin" instead of "as arguments". Either that, or your script in the Automator action doesn't have "$0" after it. Might either of these be the culprit?
Or what about "Workflow receives current files or folders in Finder"?
@Gene_ParmesanI had used "$@ in the automator script per the instructions and the Automator workflow you posted. I tried switching that to $0" instead, but now I get a slightly different error:
2023-05-24 16:08:45 !ActionCanFail() for Action Execute “Get Dropbox Link.workflow” Automator Workflow in macro Copy Dropbox Link with failure Execute an Automator Workflow failed with script error: The action “Run Shell Script” encountered an error: “ERROR:root:'/Users/dherman/-' is not in the subpath of '/Volumes/STUDIO D DROPBOX/Good Studio Dropbox/David Herman' OR one path is relative and the other is absolute.”2023-05-24 16:08:45 Action 441 failed: Execute an Automator Workflow failed with script error: The action “Run Shell Script” encountered an error: “ERROR:root:'/Users/dherman/-' is not in the subpath of '/Volumes/STUDIO D DROPBOX/Good Studio Dropbox/David Herman' OR one path is relative and the other is absolute.”2023-05-24 16:08:45 Execute an Automator Workflow failed with script error: The action “Run Shell Script” encountered an error: “ERROR:root:'/Users/dherman/-' is not in the subpath of '/Volumes/STUDIO D DROPBOX/Good Studio Dropbox/David Herman' OR one path is relative and the other is absolute.” in macro “Copy Dropbox Link” (while executing Execute “Get Dropbox Link.workflow” Automator Workflow).
I'm attaching a screenshot of my Automator workflow below. It looks like I do have Pass inputs set to "as arguments."
My Dropbox Volume name has spaces in it — could that be part of the issue?
I should clarify, that screenshot is of my original workflow, before I changed the script to "$0"
Ack, that's my error! It should be "$@" like you had it, I'm sorry. Please change it back.
Just to be clear, when you're getting this error, are you pressing Run within Automator? If so, that won't work. You need to do the next steps to set up the Finder keyboard shortcut. That way the Workflow will be run as a Quick Action via the Services menu and thus have selected files in Finder to pass into the Quick Action.
@Gene_ParmesanSuccess! Previously I had been using a Keyboard Maestro macro to run the Automator workflow, but I've just tried triggering it from the services menu with a keyboard shortcut, and voila! It works!
I'm curious how the two methods differ. I had used KM to run your previous version of the script without any trouble. In any case, this method works great and the link seems to be generated much much quicker than before! A massive improvement -- thank you again for this!!
Huzzah! So glad we got there in the end, thanks for helping me debug the script, LOL. And I'm really pleased to hear it's faster now!
My guess is that the difference comes from this version of the workflow requiring Finder items to be passed in at the top. Previously, I was using a Get Selected Finder Items action, which was resulting in links being duplicated given the "Workflow receives files from Finder" preamble. But if you add back that Get Selected Finder Items action and then go back to using KM (and I presume set the workflow to receive "no input", since that's how you'd now be using it)… I think it would work that way as well. You can read up on this a bit on AskDifferent.
I'd be interested to hear if my hypothesis is correct. 😀 I had assumed these two approaches were completely equivalent, but perhaps using an action is actually more flexible.
That was it! When I restored "Get selected item from Finder" and changed the input to none, my Keyboard Maestro macro worked. But after a quick and dirty test, it looks like it's just a hair faster to run the workflow as a service, so I'm going to keep it that way after all.
Thanks @Gene_Parmesan !!
Great, glad we could lay that mystery to rest. Yeah, I'm not surprised that it's faster via the Services menu. As far as I understand it, having that extra Workflow step means another AppleScript invocation, and AppleScript is notoriously sluggish.
Just discovered another small issue, which I have now fixed. The recent Dropbox update changed where the folder is located. Files are now actually stored in ~/Library/CloudStorage/Dropbox, and ~/Dropbox is just s symlink. This means that passing a path to a file within ~/Dropbox will fail.
Easy enough fix, and it will only affect users trying to get links from the command line. (It looks like Finder passes the resolved path in ~/Library, so if you never plan to use this from the command line, then you should be OK without an upgrade.)
This has been working so well for me, thank you @Gene_Parmesan!!
FWIW, I wanted to report a small quirk that I've noticed, which is that a link can only be copied once the file has completed syncing. If it hasn't completed yet, I get the following error message:
Interestingly, if I right-click the file and use Dropbox's "Copy Dropbox link" action, it will work even if file hasn't completed its sync. Do you have any thoughts as to whether or not this is something that can be addressed by the script, or is this a limitation of the Dropbox API?
@Gene_Parmesan wrote: I have repeatedly made links to the same file with no errors, so I haven't run into this issue. ...
I have repeatedly made links to the same file with no errors, so I haven't run into this issue. ...
Hm... 🤦🤷😜 Good luck!
@dhermanq, It's definitely not a limitation of the Dropbox API!
Hi @dhermanq, glad the script is working well for you! I've had a look at the dropbox Python API docs for the function in question, and I found an option I hadn't noticed before:
pending_upload: If it’s okay to share a path that does not yet exist, set this to either PendingUploadMode.file or PendingUploadMode.folder to indicate whether to assume it’s a file or folder.
And indeed, when I upload a large file without this setting and request a link before the upload is complete, I get the same error as you. However, when I set this to PendingUploadMode.file, the link is generated anyway. When you use the generated link before the file is fully uploaded, you get this placeholder UI:
It's noteable that this option is available when using sharing_create_shared_link, but NOT with the alternative sharing_create_shared_link_with_settings which is used in the script posted by @Здравко. So you'd be running into this with either script. Note also that the function description for sharing_create_shared_link says: "If a shared link already exists for the given path, that link is returned." (The function without settings which I'm using, though, is marked as deprecated. If anyone knows how to enable PendingUploadMode with the new-style call, I'd be happy to accept a PR in the repo. I don't immediately see how to do this after looking through the docs and the forum.)
Anyway, now that I've found this alternative, I've pushed a fix linked to issue #10 in the repo. Let me know if that fixes the behavior for you!
It's never good idea methods, declared as deprecated, to be in use. 'sharing_create_shared_link' is such a method! The same effect has a preceding dummy upload though. My script is just an example, that's why not feature rich, but if you want to improve yours, better include preceding dummy upload as an option instead of using deprecated things that can be dropped at any time. Such methods are for back compatibility only, that let some time for developers to adapt their codes, and not supposed to be used in new code!
Add: @Gene_Parmesan, One more thing you may want to update is new links conception that's rolling out currently. Probably soon all accounts will start generate new links and the query replacement, as you have implemented it, will stop work!
@Gene_Parmesanthe update did the trick! Thank you!!