Jump to content

Workflow to get next meeting location/url and open it


Recommended Posts

😰🥳🥳nope

 

[17:09:10.138] Logging Started...

[17:09:16.099] Video Conferences[Script Filter] Queuing argument '(null)'

[17:09:16.332] Video Conferences[Script Filter] Script with argv '(null)' finished

[17:09:16.337] STDERR: Video Conferences[Script Filter] .

17:09:16 workflow.py:2061 DEBUG    ---------- Video Conferences (0.0.3) ----------

17:09:16 video-conferences.py:195 DEBUG    args={'--calendar': None,

'--event': None,

'--force-reload': False,

'--help': False,

'--notify': False,

'--reload': False,

'<query>': None}

17:09:16 video-conferences.py:64 DEBUG    max_cache_age=1200

17:09:16 video-conferences.py:66 DEBUG    lookahead_days=3

17:09:16 video-conferences.py:81 DEBUG    regex=https://([a-z0-9]+\.)?zoom\.us/j/\d+\?pwd=[a-z0-9]+

17:09:16 video-conferences.py:81 DEBUG    regex=https://meet\.google\.com/[a-z-]+

17:09:16 video-conferences.py:81 DEBUG    regex=https://[a-z0-9]+\.zoom\.us/[a-z0-9_.-]+/\d+\?pwd=[a-z0-9]+

17:09:16 video-conferences.py:81 DEBUG    regex=https://meet\.lync\.com/[a-z0-9_.-]+/[a-z0-9_.-]+/[a-z0-9]+

17:09:16 workflow.py:1695 DEBUG    loading cached data: /Users/macpro/Library/Caches/com.runningwithcrayons.Alfred/Workflow Data/net.deanishe.alfred.video-conferences/events.cpickle

17:09:16 video-conferences.py:244 DEBUG    0/7 event(s) in specified accounts & calendars are video conferences

17:09:16 workflow.py:1468 DEBUG    reading settings from /Users/macpro/Library/Application Support/Alfred/Workflow Data/net.deanishe.alfred.video-conferences/settings.json

17:09:16 workflow.py:2254 DEBUG    set last run version: 0.0.3

17:09:16 workflow.py:2103 DEBUG    ---------- finished in 0.040s ----------

[17:09:16.341] Video Conferences[Script Filter] {"items": [{"valid": false, "subtitle": "", "icon": {"path": "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/AlertCautionIcon.icns"}, "title": "No Video Conferences"}]}

Bildschirmfoto 2020-05-16 um 17.09.58.jpg

Link to post
3 hours ago, tosbsas said:

😰🥳🥳nope

 

[17:09:10.138] Logging Started...

[17:09:16.099] Video Conferences[Script Filter] Queuing argument '(null)'

[17:09:16.332] Video Conferences[Script Filter] Script with argv '(null)' finished

[17:09:16.337] STDERR: Video Conferences[Script Filter] .

17:09:16 workflow.py:2061 DEBUG    ---------- Video Conferences (0.0.3) ----------

17:09:16 video-conferences.py:195 DEBUG    args={'--calendar': None,

'--event': None,

'--force-reload': False,

'--help': False,

'--notify': False,

'--reload': False,

'<query>': None}

17:09:16 video-conferences.py:64 DEBUG    max_cache_age=1200

17:09:16 video-conferences.py:66 DEBUG    lookahead_days=3

17:09:16 video-conferences.py:81 DEBUG    regex=https://([a-z0-9]+\.)?zoom\.us/j/\d+\?pwd=[a-z0-9]+

17:09:16 video-conferences.py:81 DEBUG    regex=https://meet\.google\.com/[a-z-]+

17:09:16 video-conferences.py:81 DEBUG    regex=https://[a-z0-9]+\.zoom\.us/[a-z0-9_.-]+/\d+\?pwd=[a-z0-9]+

17:09:16 video-conferences.py:81 DEBUG    regex=https://meet\.lync\.com/[a-z0-9_.-]+/[a-z0-9_.-]+/[a-z0-9]+

17:09:16 workflow.py:1695 DEBUG    loading cached data: /Users/macpro/Library/Caches/com.runningwithcrayons.Alfred/Workflow Data/net.deanishe.alfred.video-conferences/events.cpickle

17:09:16 video-conferences.py:244 DEBUG    0/7 event(s) in specified accounts & calendars are video conferences

17:09:16 workflow.py:1468 DEBUG    reading settings from /Users/macpro/Library/Application Support/Alfred/Workflow Data/net.deanishe.alfred.video-conferences/settings.json

17:09:16 workflow.py:2254 DEBUG    set last run version: 0.0.3

17:09:16 workflow.py:2103 DEBUG    ---------- finished in 0.040s ----------

[17:09:16.341] Video Conferences[Script Filter] {"items": [{"valid": false, "subtitle": "", "icon": {"path": "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/AlertCautionIcon.icns"}, "title": "No Video Conferences"}]}

Bildschirmfoto 2020-05-16 um 17.09.58.jpg

 

Could you message me the format of the URL to test with?

Link to post
2 hours ago, Terminal said:

Awesome! Checking out the regex now

 

 

@deanishe just appears your aren't capturing url's that don't require or don't embed the pwd component. I would update this regex to be

 


r"https://[a-z0-9]+\.zoom\.us/[a-z0-9_.-]+/\d+(?:\?pwd=[a-z0-9]+)?"

 

 

No, I'm not capturing URLs without the password. I figured since all the fun people had gatecrashing Zoom meetings thanks to the easily-guessable numbers, everyone would be using passwords now.

 

Apparently not… I guess I'll have update the workflow again.

Link to post
6 hours ago, Terminal said:

@tosbsas since you can update the regex yourself,

 

1. Open Alfred Preferences

2. Click Workflows

3. Click Video Conferences

4. Click the [X] Icon

5. Edit the zoom_regex_2 and put https://[a-z0-9]+\.zoom\.us/[a-z0-9_.-]+/\d+(?:\?pwd=[a-z0-9]+)?

6. Alfred -> .vc reload

works now perfect

Link to post
  • 1 month later...

I'm using the following regex for teams as well. While we're at it, I also added zoomgov:

https://teams\.microsoft\.com/l/meetup-join/[a-z0-9%_\.-]+
https:\/\/([a-z0-9]+\.)?zoomgov\.com\/j\/\d+(\?pwd=[A-Za-z0-9]+)?

 

Edited by psifertex
Link to post
  • 4 weeks later...

@deanishe Thank  you for this, it's great !

 

I tweaked it a little bit, in order to just join the ZOOM meeting without having to open a browser tab. I'm new to Alfred and Python so it's only a humble hack, with hardcoded regex. 

 

I used Zoom url-scheme, as per https://marketplace.zoom.us/docs/guides/guides/client-url-schemes

 

In video-conferences.py: 

(Around line 261....)
it.setvar('event_id', d['uid'])

# PDAZERO: Set url to zoom scheme (in case it's zoom)
zoom_url_match = re.search('https://[a-z0-9]+\.zoom\.us/[a-z0-9_.-]+/(\d+.*)',d['url'])
if zoom_url_match:
  it.setvar('zoom_url','zoommtg://zoom.us/join?confno=' + zoom_url_match.group(1))

And then open url with the "zoom_url" variable. If you are interested maybe you could do this a lot cleaner but my coding skills are not at their best today. Thanks again for this workflow.

Link to post
  • 4 weeks later...

@deanishe I'm trying to figure out how to extract the list of attendees and then use that to build a markdown minute template, but I don't find a way to access  that list in your script. Can you give me a hand? 

 

BTW I use this script several times a day, it's really great!

Link to post
3 hours ago, pdazero said:

I don't find a way to access  that list in your script.

 

You need to edit the CalendarEvents.scpt script. Something like this:

let arr = getEvents(days),
  ekEvents = arr[0],
  colours = arr[1],
  attendees = []

ekEvents.forEach(event => {
  if (event.status === $.EKEventStatusCanceled) return
  if (event.allDay) return

  let title = ObjC.unwrap(event.title),
    url = ObjC.unwrap(event.URL.absoluteString),
    notes = ObjC.unwrap(event.notes),
    location = ObjC.unwrap(event.location)

  if (event.hasAttendees) {
    ObjC.unwrap(event.attendees).forEach(a => {
      attendees.push(ObjC.unwrap(a.name))
    })
  }

  // ensure these have values otherwise they'll be omitted from
  // JSON output because they're undefined
  title = title ? title : ''
  url = url ? url : ''
  notes = notes ? notes : ''
  location = location ? location : ''

  events.push({
    uid: ObjC.unwrap(event.eventIdentifier),
    title: title,
    url: url,
    notes: notes,
    location: location,
    attendees: attendees,
    account: ObjC.unwrap(event.calendar.source.title),
    calendar: ObjC.unwrap(event.calendar.title),
    calendar_id: ObjC.unwrap(event.calendar.calendarIdentifier),
    start_date: ObjC.unwrap(formatter.stringFromDate(event.startDate)),
    end_date: ObjC.unwrap(formatter.stringFromDate(event.endDate)),
    colour: colours[ObjC.unwrap(event.calendar.calendarIdentifier)],
  })
})

 

Link to post
  • 2 weeks later...

@deanisheThank you. I have to say this was a huge feat for me, but finally managed to do it. I first had to learn javascript arrow functions, what the hell is objc.unwrap() and other spices lol.

 

Here is the final run function from CalendarEvents.scpt:

function run(argv) {
	if (!haveAccess()) {
		return JSON.stringify({error: 'No Access to Calendars', events: []})
	}

	let days = 7,
		events = [],
		formatter = $.NSISO8601DateFormatter.alloc.init
		
	// convert all times to local time because Python sucks at timezones
	formatter.timeZone = $.NSTimeZone.localTimeZone

	if (argv.length > 0) days = parseInt(argv[0], 10)
	
	let arr = getEvents(days),
		ekEvents = arr[0],
		colours = arr[1],
		attendees = [],
		strAttendees = ''

	ekEvents.forEach(event => {
			
		if (event.status === $.EKEventStatusCanceled) return
		if (event.allDay) return
				
		let title = ObjC.unwrap(event.title),
			url = ObjC.unwrap(event.URL.absoluteString),
			notes = ObjC.unwrap(event.notes),
			location = ObjC.unwrap(event.location)

		// Clean attendees
		while (attendees.length > 0) {
		 	attendees.pop();
		}
					
		if (event.hasAttendees) {
			ObjC.unwrap(event.attendees).forEach(a => {
				attendees.push(ObjC.unwrap(a.name))
				}
			)
			strAttendees = attendees.join();
		}
		
		// ensure these have values otherwise they'll be omitted from
		// JSON output because they're undefined
		title = title ? title : ''
		url = url ? url : ''
		notes = notes ? notes : ''
		location = location ? location : ''

		events.push({
			uid: ObjC.unwrap(event.eventIdentifier),
			title: title,
			url: url,
			notes: notes,
			location: location,
			attendees: strAttendees,
			account: ObjC.unwrap(event.calendar.source.title),
			calendar: ObjC.unwrap(event.calendar.title),
			calendar_id: ObjC.unwrap(event.calendar.calendarIdentifier),
			start_date: ObjC.unwrap(formatter.stringFromDate(event.startDate)),
			end_date: ObjC.unwrap(formatter.stringFromDate(event.endDate)),
			colour: colours[ObjC.unwrap(event.calendar.calendarIdentifier)],
		})
	})
	
	events.sort((a, b) => {
		if (a.start_date < b.start_date) return -1
		if (a.start_date > b.start_date) return 1
		if (a.title < b.title) return -1
		if (a.title > b.title) return 1
		return 0
	})
	
	console.log(`${events.length} event(s)`)

	return JSON.stringify({error: null, events: events})
}

So, I modified a bit your suggestion in order to pass a comma-separated list of the attendees. I had to did this because it looks I had troubles with passing an array.

 

Then, edited main function on video-conferences.py (just an excerpt):

 

    icons = Icons(wf.cachefile('icons'))
    for d in events:
        subtitle = u'{}–{} on {} // {} ({})'.format(
            d['start_date'].strftime('%H:%M'),
            d['end_date'].strftime('%H:%M'),
            d['start_date'].strftime('%Y-%m-%d'),
            d['calendar'], d['account'])

        it = wf.add_item(d['title'], subtitle, arg=d['url'], valid=True,
                         icon=icons.get_icon(d['colour']))
        it.setvar('calendar_name', d['calendar'])
        it.setvar('event_id', d['uid'])
    
        # PDAZERO: Set url to zoom scheme (in case it's zoom)
        zoom_url_match = re.search('https://[a-z0-9]+\.zoom\.us/[a-z0-9_.-]+/(\d+.*)',d['url'])
        if zoom_url_match:
            it.setvar('zoom_url','zoommtg://zoom.us/join?confno=' + zoom_url_match.group(1))

        if d['attendees'] is not None:
            strAttendees = ''
            attendees = d['attendees'].split(',')
            for attendee in attendees:
                strAttendees = strAttendees + "\n- " + attendee

            it.setvar('attendees', strAttendees)
            del strAttendees
        else:
            it.setvar('attendees', '')

Later on, I just pass the attendees var to the clipboard and paste it on my markdown minute. I'll work now in building the minute from scratch because I still have friction in that part of my everyday routine.

 

BTW I'm also using https://www.aaronsaray.com/2020/leave-zoom-with-alfred "lz" alfred command to just leave the meeting right now without fiddling with the exit buttons.

 

Thanks again !

Link to post
2 hours ago, pdazero said:

what the hell is objc.unwrap()

 

Objective-C APIs (i.e. macOS APIs) don’t return JavaScript objects. ObjC.unwrap() converts Objective-C strings/arrays/etc. to JavaScript ones.

 

I don't understand why you're converting the array of attendees into a string only to convert it back to an array in Python.

Link to post
  • 3 weeks later...

@deanishe Actually I tried directly using arrays but it didn't work. It might have been some obscure bug or error on my side (probably) but could not access the array elements. After I did that probably silly array-to-string-to-array stuff, everything started working.

 

🤷‍♂️

Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...