Jump to content

Open X Callback URL with Special Characters in Applescript


Recommended Posts

Help guys. I'm a total beginner but trying to figure out some applescript (that I'm running through Alfred) to open an X-Callback URL for Bear App. How can I include special characters in a variable and include them when I open it?

Sample:

 

set mainContent to "1 + 2 = 3"

set myUrl to "bear://x-callback-url/add-text?text=" & mainContent & "&id=DA084FAD"

open location myUrl

It's not a problem if I use this by itself:

set mainContent to "1 + 2"

 

But the moment I include an "=" symbol, or an "&" symbol it doesn't work at all.

Of course, the idea is to set the variable (mainContent) to Alfred's query, but this is the issue that I'm facing whenever I type some special characters.

I even figured out that I can type directly in chrome %3D to replace the "=" symbol when it opens the x-callback url, but when my variable inside applescript has %3D, that's literally what appears in the result without "=" (what?!).

Any help would be greatly appreciated. Thank you!!

Link to comment

Thank you so much for your reply.

 

Unfortunately the Applescript I wrote is a bit more complex than the sample I posted above. Probably it's unnecessarily complex, but I'm just not a coder at all, and I have no clue of how to translate it all to Javascript or how to use Javascript to spit out a variable that I can use in my Applescript. 

 

Actually, the workflow is supposed first figure out if the app (Bear) is running in the same space or not and if it's the active/frontmost app or not, then act on that. Basically if it's open and in front just run the x-callback url but if it's not then either minimize the app window and run the url (if it's in the same space) or do nothing other than running the x-callback url if it's in a different space.

 

The URL will include a variable with the date in a specific format plus Alfred's query. I also figured out a way to replace any "&" character with "+," solving only half of my problem, but when I entered "=" as Alfred's query it all fell apart as I didn't URL-encode - and have no idea how. 

 

Here's the whole thing, in case you or someone would be so kind as to help me out. Has taken me days to work on this. 

 

on count_windows_on_current_space(process_name)
    tell application "System Events"
        tell process process_name
            return count of windows
        end tell
    end tell
end count_windows_on_current_space

tell application "System Events"
set nom to name of process 1 whose frontmost is true
end tell

set toreplace to "{query}"
on replace_chars(this_text, search_string, replacement_string)
 set AppleScript's text item delimiters to the search_string
 set the item_list to every text item of this_text
 set AppleScript's text item delimiters to the replacement_string
 set this_text to the item_list as string
 set AppleScript's text item delimiters to ""
 return this_text
end replace_chars

set queri to replace_chars(toreplace, "&", "+")

if nom is equal to "Bear" then
else
	if my count_windows_on_current_space("Bear") = 0 then
	else
		tell application "Bear"
		activate
		end tell
		tell application "System Events"
    		keystroke "m" using command down
		end tell
	end if
end if

set timo to (do shell script "date +\"%l:%M %p\" | awk '{$1=$1;print}'")
set theDate to (do shell script "date +\"%m.%d.%y\" | awk '{$1=$1;print}'")

if timo contains "PM" then
	set findText to "PM"
	set replaceText to "p.m."
	set newTime to do shell script "sed 's|" & quoted form of findText & "|" & quoted form of replaceText & "|g' <<< " & quoted form of timo
else
	set findText to "AM"
	set replaceText to "a.m."
	set newTime to do shell script "sed 's|" & quoted form of findText & "|" & quoted form of replaceText & "|g' <<< " & quoted form of timo
end if

set bearUrl to "bear://x-callback-url/add-text?text=*" & theDate & " @ " & newTime & "*\n\n" & queri & "\n\n---\n&id=DA084FAD-86A9-42C9-A691-0564B76DADE3-44713-0001D35A1A8F960C&open_note=no&new_window=no&show_window=no&mode=prepend&edit=no"

open location bearUrl

return queri

 

 

 

Link to comment

That script can be simplified a lot in JavaScript because it's much closer to a real programming language. I'm at work now, but I'll have a go at translating it to JXA when I get home later. 

Link to comment

The URL encoding sent me in the right path, thank you. I still didn't figure out how to do all of this in JavaSript, but I found a bit of a ghetto fix with AppleScript. I found a shell script to URL encode. This:

 

do shell script "php -r 'echo urlencode(\"" & thecontent & "\");'")

 

It seems like AppleScript couldn't use 'open location' after this, so I just return the end variable, make it go through a "trim whitespace" and send it to the "Open URL" Alfred Action. This seems to work for the most part. Characters like "&" and "=" now are sent to the app through x-callback-url without problem.

 

From what I've tested, the only character that still breaks the workflow and gives trouble is if I enter double quotes as the initial query. I have no idea if I'll find a solution to this one but at least it all works much better than before.

 

The entire AppleScript code, for reference:

 

on count_windows_on_current_space(process_name)
    tell application "System Events"
        tell process process_name
            return count of windows
        end tell
    end tell
end count_windows_on_current_space

tell application "System Events"	
set nom to name of process 1 whose frontmost is true
end tell

if nom is equal to "Bear" then
else
	if my count_windows_on_current_space("Bear") = 0 then
	else
		tell application "Bear"
		activate
		end tell
		tell application "System Events"
    		keystroke "m" using command down
		end tell
	end if
end if

set timo to (do shell script "date +\"%l:%M %p\" | awk '{$1=$1;print}'")
set theDate to (do shell script "date +\"%m.%d.%y\" | awk '{$1=$1;print}'")

if timo contains "PM" then
	set findText to "PM"
	set replaceText to "p.m."
	set newTime to do shell script "sed 's|" & quoted form of findText & "|" & quoted form of replaceText & "|g' <<< " & quoted form of timo
else
	set findText to "AM"
	set replaceText to "a.m."
	set newTime to do shell script "sed 's|" & quoted form of findText & "|" & quoted form of replaceText & "|g' <<< " & quoted form of timo
end if

on replace_chars(this_text, search_string, replacement_string)
 set AppleScript's text item delimiters to the search_string
 set the item_list to every text item of this_text
 set AppleScript's text item delimiters to the replacement_string
 set this_text to the item_list as string
 set AppleScript's text item delimiters to ""
 return this_text
end replace_chars

set toreplace to "{query}"
set thecontent to replace_chars(toreplace, "'", "`")
set queri to (do shell script "php -r 'echo urlencode(\"" & thecontent & "\");'")

set theWeb to "bear://x-callback-url/add-text?text=*" & theDate & " @ " & newTime & "*\n\n" & queri & "\n\n---\n&id=DA084FAD-86A9-42C9-A691-0564B76DADE3-44713-0001D35A1A8F960C&open_note=no&new_window=no&show_window=no&mode=prepend&edit=no"

set bearUrl to replace_chars(theWeb, "+", " ")

return bearUrl

 

Link to comment
Posted (edited)
17 hours ago, gloogloo said:

This seems to work for the most part.

 

You need to URL-encode the whole value, not just thecontent. You can’t put \n in a URL and expect it to work properly.

 

17 hours ago, gloogloo said:

the only character that still breaks the workflow and gives trouble is if I enter double quotes as the initial query

 

That’s because you aren’t quoting the input properly when you pass it to do shell script. You’re inserting a quote into the shell command and breaking it.

 

You need something like do shell script "php -r 'echo urlencode(" & (quoted form of thecontent) & ");'"

 

I think that might use single quotes, though, so you might need to fiddle with the command.

 

This JavaScript version should be a bit more correct:

 

// application to activate (this is here because I don't have Bear)
const targetAppName = 'Bear',
	// ID of bear note to add text to
	noteId = 'DA084FAD-86A9-42C9-A691-0564B76DADE3-44713-0001D35A1A8F960C'

const se = Application('System Events')


function windowsOnCurrentSpace(procName) {
	let proc = se.processes[procName]
	return ObjC.unwrap(proc.windows).length	
}


// return current time in HH:MM a/p.m. format
function currentTime() {
	let now = new Date(),
		h = now.getHours(),
		m = now.getMinutes(),
		s = 'a.m.'
	
	if (h == 0) {
		h = 12
	} else if (h > 11) {
		s = 'p.m.'
	}
	if (h > 12) h = h-12

	return `${h}:${m} ${s}`
}


// left pad value with zeros to size n
function zpad(v, n) {
	s = v.toString()
	while (s.length < n) {
		s = '0' + s
	}
	return s
}


// return current date in MM.DD.YY format
function currentDate() {
	let now = new Date(),
		y = now.getFullYear(),
		m = now.getMonth(),
		d = now.getDate()
	
	y = y.toString().substr(2, 4)
	return `${zpad(m, 2)}.${zpad(d, 2)}.${y}`
}


// convert Object's keys and values to a properly encoded URL query string,
// i.e key1=value1&key2=value2...
function queryString(params) {
	let vals = []
	for (let k in params) {
		vals.push(encodeURIComponent(k) + '=' + encodeURIComponent(params[k]))
	}
	return vals.join('&')
}


// execute script
function run(argv) {
	// text to insert into note is passed via ARGV
	let content = argv[0] || '',
		proc = se.processes.whose({frontmost: true})[0],
		name = proc.name()

	if (name != targetAppName) {
		let n = windowsOnCurrentSpace(targetAppName)
		if (n != 0) {
			Application(targetAppName).activate()
			se.keystroke('m', {using: 'command down'})
		}
	}

	// construct content to add
	content = content.replaceAll("'", '`')
	let time = currentTime(),
		date = currentDate(),	
		noteBody = `*${date} @ ${time} *\n\n${content}\n\n---\n`

	// all URL parameters
	let urlParams = {
		text: noteBody,
		id: noteId,
		open_note: 'no',
		new_window: 'no',
		show_window: 'no',
		mode: 'prepend',
		edit: 'no'
	}

	return 'bear://x-callback-url/add-text?' + queryString(urlParams)
}

 

Edited by deanishe
Fix bug in code
Link to comment

Genius!!! Seriously, thank you SO MUCH! Man, you got it perfectly. JavaScript was truly the way to go after all.

 

One last thing. Could it be possible, at all, to enter "\n" and use that to create line breaks within the content of the note? As it's right now if I type \n this goes directly into the note. I've tried to replace \n manually to its hexadecimal code but doesn't seem to work.

 

If it's too much trouble or not possible, no worries. It's already great as it is and I really really appreciate your help.

Link to comment
4 hours ago, gloogloo said:

I've tried to replace \n manually to its hexadecimal code but doesn't seem to work.

 

Try content = content.replaceAll('\\n', '\n')

 

Because \n means “newline” in source code, you need to escape it with a backslash to get a literal \n, i.e. \\n.

 

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...