Apple Favorites wallpaper handling

I don’t use never Keyboard Maestro, but you can try following with it:


use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "MapKit"
use framework "CoreLocation"

property NSAlert : a reference to current application's NSAlert
property NSString : a reference to current application's NSString
property NSScreen : a reference to current application's NSScreen
property MKMapView : a reference to current application's MKMapView
property MKMapTypeHybrid : a reference to current application's MKMapTypeHybrid
property MKPointAnnotation : a reference to current application's MKPointAnnotation
property MKMapTypeSatellite : a reference to current application's MKMapTypeSatellite
property MKMapTypeStandard : a reference to current application's MKMapTypeStandard
property NSSegmentedControl : a reference to current application's NSSegmentedControl
property NSRunningApplication : a reference to current application's NSRunningApplication
property NSSegmentStyleTexturedRounded : a reference to current application's NSSegmentStyleTexturedRounded
property selSeg : 0
property aMapViewList : {}

on run argv
	if (count of argv) < 1 then
		set screenId to 1
	else
		set screenId to item 1 of argv as integer
	end if
	if screenId ≤ 1 then
		set screenId to 1 -- 1st monior index
	else
		set screenId to 18 -- 2nd monitor index
	end if
	
	set posixaliaspath to (do shell script "/usr/bin/sqlite3 ~/Library/Application\\ Support/Dock/desktoppicture.db \"select d1.value || '/' || d2.value from preferences pf1 join data d1 on pf1.data_id=d1.rowid join preferences pf2 on pf1.picture_id=pf2.picture_id join data d2 on pf2.data_id=d2.rowid where pf1.key=10 and pf2.key=16 and pf1.picture_id=" & screenId & "\"") as string
	set homepath to (do shell script "echo $HOME")
	-- replace "~" in the path to actual $HOME dir
	set posixaliaspath to my replace_chars(posixaliaspath, "~", homepath)
	set aliaspath to (POSIX file posixaliaspath) as string
	set currentPicturePOSIXPath to POSIX path of aliaspath
	
	set gpsCoords to do shell script "usr/local/bin/exiftool " & "'" & currentPicturePOSIXPath & "'" & " -gpslatitude# -gpslongitude#"
	set AppleScript's text item delimiters to ":"
	set aLatitude to (text item 2 of paragraph 1 of gpsCoords as number)
	set aLongitude to (text item 2 of paragraph 2 of gpsCoords as number)
	set AppleScript's text item delimiters to ""
	
	set paramObj to {viewWidth:1000, viewHeight:600, viewSubTitle:"Geolocation Showing Example", viewLat:aLatitude, viewLong:aLongitude}
	my performSelectorOnMainThread:"dispMapViewinDifferentScales:" withObject:(paramObj) waitUntilDone:true
end run

on replace_chars(this_text, search_string, replacement_string)
	-- ref: https://www.macosxautomation.com/applescript/sbrt/sbrt-06.html
	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

on dispMapViewinDifferentScales:paramObj
	set aWidth to (viewWidth of paramObj) as real
	set aHeight to (viewHeight of paramObj) as real
	set aLat to (viewLat of paramObj) as real
	set aLong to (viewLong of paramObj) as real
	--set aTitle to (viewTitle of paramObj) as string
	set aSubTitle to (viewSubTitle of paramObj) as string
	
	set selSeg to 0
	
	--NSViewをつくる
	set aView to current application's NSView's alloc()'s initWithFrame:(current application's NSMakeRect(0, 0, aWidth, aHeight))
	
	--各レベルのMapViewをBoxでつくる
	set wList to {{3, "????World Level Map"}, {5, "????Country Level Map"}, {10, "????City Level Map"}, {17, "????Town Level Map"}}
	set xPos to 0
	repeat with i in wList
		copy i to {aLevelNum, aBoxTitle}
		
		--Boxをつくる
		set aBox to (current application's NSBox's alloc()'s initWithFrame:(current application's NSMakeRect(xPos, 40, aWidth * 0.25, aHeight - 70)))
		(aBox's setTitle:aBoxTitle)
		
		--MapView+Pinをつくる
		set aMapView to makeMKMapView(aWidth * 0.25, aHeight - 70, aLevelNum, aLat, aLong) of me
		
		(aBox's addSubview:aMapView)
		(aView's addSubview:aBox)
		
		set the end of aMapViewList to aMapView
		set xPos to xPos + (aWidth * 0.25)
	end repeat
	
	--Segmented Controlをつくる
	set aSeg to makeSegmentedControl({"Map", "Satellite", "Satellite + Map"}, aWidth, aHeight) of me
	aView's addSubview:aSeg
	
	-- set up alert	
	set theAlert to NSAlert's alloc()'s init()
	tell theAlert
		its setMessageText:""
		its setInformativeText:aSubTitle
		its addButtonWithTitle:"OK"
		its addButtonWithTitle:"Cancel"
		its setAccessoryView:aView
	end tell
	
	-- show alert in modal loop
	NSRunningApplication's currentApplication()'s activateWithOptions:0
	my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
	if (my returnCode as number) = 1001 then error number -128
end dispMapViewinDifferentScales:


on doModal:aParam
	set (my returnCode) to aParam's runModal()
end doModal:



--MKMapViewをつくる
on makeMKMapView(aWidth, aHeight, aZoomLevel, aLat, aLong)
	set aMapView to MKMapView's alloc()'s initWithFrame:(current application's NSMakeRect(0, 0, aWidth, aHeight))
	aMapView's setMapType:(current application's MKMapTypeStandard)
	
	aMapView's setZoomEnabled:true
	aMapView's setScrollEnabled:true
	aMapView's setPitchEnabled:false
	aMapView's setRotateEnabled:false
	aMapView's setShowsCompass:true
	aMapView's setShowsZoomControls:true
	aMapView's setShowsScale:true
	aMapView's setShowsUserLocation:true
	
	set aLocation to current application's CLLocationCoordinate2DMake(aLat, aLong)
	aMapView's setCenterCoordinate:aLocation zoomLevel:aZoomLevel animated:false
	aMapView's setDelegate:me
	
	--MapにPinを追加
	set anAnnotation to current application's MKPointAnnotation's alloc()'s init()
	anAnnotation's setCoordinate:aLocation
	anAnnotation's setTitle:""
	aMapView's addAnnotation:anAnnotation
	
	return aMapView
end makeMKMapView


--Make Segmented Control
on makeSegmentedControl(titleList, aWidth, aHeight)
	set aLen to length of titleList
	
	set aSeg to NSSegmentedControl's alloc()'s init()
	aSeg's setSegmentCount:aLen
	
	set aCount to 0
	repeat with i in titleList
		set j to contents of i
		(aSeg's setLabel:j forSegment:aCount)
		set aCount to aCount + 1
	end repeat
	
	aSeg's setTranslatesAutoresizingMaskIntoConstraints:false
	aSeg's setSegmentStyle:(NSSegmentStyleTexturedRounded)
	aSeg's setFrame:(current application's NSMakeRect(10, 5, 260, 30))
	aSeg's setTrackingMode:0
	aSeg's setTarget:me
	aSeg's setAction:"clickedSeg:"
	aSeg's setSelectedSegment:0
	
	return aSeg
end makeSegmentedControl

--Segmented Control's clicked event handler
on clickedSeg:aSender
	set aSel to aSender's selectedSegment()
	set selSeg to (aSel + 1)
	set mapList to {MKMapTypeStandard, MKMapTypeSatellite, MKMapTypeHybrid}
	set curMap to contents of item selSeg of mapList
	
	repeat with i in aMapViewList
		set aView to contents of i
		(aView's setMapType:(curMap))
	end repeat
end clickedSeg:

Right this script works:

use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "MapKit"
use framework "CoreLocation"



-- https://discussions.apple.com/thread/8373854?answerId=33344100022#33344100022
--
-- Usage: osascript find_wall_pic n

--        n = 1 or 2 (monitor ID)



on replace_chars(this_text, search_string, replacement_string)
	
	-- ref: https://www.macosxautomation.com/applescript/sbrt/sbrt-06.html
	
	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 screenId to 1


--        set a to (do shell script "/usr/bin/sqlite3 ~/Library/Application\\ Support/Dock/desktoppicture.db \"SELECT data.value FROM preferences INNER JOIN data on preferences.key=16 and preferences.data_id=data.ROWID where preferences.picture_id =" & screenId & "\"") as string

--        set posixaliaspath1 to "/Users/kangfucius/Library/Caches/com.apple.preference.desktopscreeneffect.desk top/69677504/DSKPhotosRootSource/" & a



set posixaliaspath to (do shell script "/usr/bin/sqlite3 ~/Library/Application\\ Support/Dock/desktoppicture.db \"select d1.value || '/' || d2.value from preferences pf1 join data d1 on pf1.data_id=d1.rowid join preferences pf2 on pf1.picture_id=pf2.picture_id join data d2 on pf2.data_id=d2.rowid where pf1.key=10 and pf2.key=16 and pf1.picture_id=" & screenId & "\"") as string

set homepath to (do shell script "echo $HOME")

-- replace "~" in the path to actual $HOME dir

set posixaliaspath to replace_chars(posixaliaspath, "~", homepath)


set aliaspath to (POSIX file posixaliaspath) as string

set posixpath to POSIX path of aliaspath

set imgfile to POSIX file posixpath


-- tell application "Finder" to reveal imgfile

-- tell application "Finder"

--	activate

--	reveal imgfile

-- end tell

-- end run


-- set imageFile to imgfile
set imageFile to posixpath

-- Created by Hubert =========================================
-- https://exiftool.org/forum/index.php?topic=12726.new;topicseen#new
-- set imageFile to POSIX path of ((choose file) as string)
set gpsCoords to do shell script "usr/local/bin/exiftool " & "'" & imageFile & "'" & " -gpslatitude# -gpslongitude#"
set AppleScript's text item delimiters to ":"
-- set AppleScript's text item delimiters to "\"
set aLatitude to (text item 2 of paragraph 1 of gpsCoords as number)
set aLongitude to (text item 2 of paragraph 2 of gpsCoords as number)

property NSAlert : a reference to current application's NSAlert
property NSString : a reference to current application's NSString
property NSScreen : a reference to current application's NSScreen
property MKMapView : a reference to current application's MKMapView
property MKMapTypeHybrid : a reference to current application's MKMapTypeHybrid
property MKPointAnnotation : a reference to current application's MKPointAnnotation
property MKMapTypeSatellite : a reference to current application's MKMapTypeSatellite
property MKMapTypeStandard : a reference to current application's MKMapTypeStandard
property NSSegmentedControl : a reference to current application's NSSegmentedControl
property NSRunningApplication : a reference to current application's NSRunningApplication
property NSSegmentStyleTexturedRounded : a reference to current application's NSSegmentStyleTexturedRounded
property selSeg : 0
property aMapViewList : {}


-- set aLatitude to "52.3740"
-- set aLongitude to "4.8897"
set paramObj to {viewWidth:1000, viewHeight:600, viewSubTitle:"Geolocation Showing Example", viewLat:aLatitude, viewLong:aLongitude}
my performSelectorOnMainThread:"dispMapViewinDifferentScales:" withObject:(paramObj) waitUntilDone:true


on dispMapViewinDifferentScales:paramObj
	set aWidth to (viewWidth of paramObj) as real
	set aHeight to (viewHeight of paramObj) as real
	set aLat to (viewLat of paramObj) as real
	set aLong to (viewLong of paramObj) as real
	--set aTitle to (viewTitle of paramObj) as string
	set aSubTitle to (viewSubTitle of paramObj) as string
	
	set selSeg to 0
	
	--NSViewをつくる
	set aView to current application's NSView's alloc()'s initWithFrame:(current application's NSMakeRect(0, 0, aWidth, aHeight))
	
	--各レベルのMapViewをBoxでつくる
	set wList to {{3, "World Level Map"}, {5, "Country Level Map"}, {10, "City Level Map"}, {17, "Town Level Map"}}
	set xPos to 0
	repeat with i in wList
		copy i to {aLevelNum, aBoxTitle}
		
		--Boxをつくる
		set aBox to (current application's NSBox's alloc()'s initWithFrame:(current application's NSMakeRect(xPos, 40, aWidth * 0.25, aHeight - 70)))
		(aBox's setTitle:aBoxTitle)
		
		--MapView+Pinをつくる
		set aMapView to makeMKMapView(aWidth * 0.25, aHeight - 70, aLevelNum, aLat, aLong) of me
		
		(aBox's addSubview:aMapView)
		(aView's addSubview:aBox)
		
		set the end of aMapViewList to aMapView
		set xPos to xPos + (aWidth * 0.25)
	end repeat
	
	--Segmented Controlをつくる
	set aSeg to makeSegmentedControl({"Map", "Satellite", "Satellite + Map"}, aWidth, aHeight) of me
	aView's addSubview:aSeg
	
	-- set up alert    
	set theAlert to NSAlert's alloc()'s init()
	tell theAlert
		its setMessageText:""
		its setInformativeText:aSubTitle
		its addButtonWithTitle:"OK"
		its addButtonWithTitle:"Cancel"
		its setAccessoryView:aView
	end tell
	
	-- show alert in modal loop
	NSRunningApplication's currentApplication()'s activateWithOptions:0
	my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
	if (my returnCode as number) = 1001 then error number -128
end dispMapViewinDifferentScales:


on doModal:aParam
	set (my returnCode) to aParam's runModal()
end doModal:



--MKMapViewをつくる
on makeMKMapView(aWidth, aHeight, aZoomLevel, aLat, aLong)
	set aMapView to MKMapView's alloc()'s initWithFrame:(current application's NSMakeRect(0, 0, aWidth, aHeight))
	aMapView's setMapType:(current application's MKMapTypeStandard)
	
	aMapView's setZoomEnabled:true
	aMapView's setScrollEnabled:true
	aMapView's setPitchEnabled:false
	aMapView's setRotateEnabled:false
	aMapView's setShowsCompass:true
	aMapView's setShowsZoomControls:true
	aMapView's setShowsScale:true
	aMapView's setShowsUserLocation:true
	
	set aLocation to current application's CLLocationCoordinate2DMake(aLat, aLong)
	aMapView's setCenterCoordinate:aLocation zoomLevel:aZoomLevel animated:false
	aMapView's setDelegate:me
	
	--MapにPinを追加
	set anAnnotation to current application's MKPointAnnotation's alloc()'s init()
	anAnnotation's setCoordinate:aLocation
	anAnnotation's setTitle:""
	aMapView's addAnnotation:anAnnotation
	
	return aMapView
end makeMKMapView


--Make Segmented Control
on makeSegmentedControl(titleList, aWidth, aHeight)
	set aLen to length of titleList
	
	set aSeg to NSSegmentedControl's alloc()'s init()
	aSeg's setSegmentCount:aLen
	
	set aCount to 0
	repeat with i in titleList
		set j to contents of i
		(aSeg's setLabel:j forSegment:aCount)
		set aCount to aCount + 1
	end repeat
	
	aSeg's setTranslatesAutoresizingMaskIntoConstraints:false
	aSeg's setSegmentStyle:(NSSegmentStyleTexturedRounded)
	aSeg's setFrame:(current application's NSMakeRect(10, 5, 260, 30))
	aSeg's setTrackingMode:0
	aSeg's setTarget:me
	aSeg's setAction:"clickedSeg:"
	aSeg's setSelectedSegment:0
	
	return aSeg
end makeSegmentedControl

--Segmented Control's clicked event handler
on clickedSeg:aSender
	set aSel to aSender's selectedSegment()
	set selSeg to (aSel + 1)
	set mapList to {MKMapTypeStandard, MKMapTypeSatellite, MKMapTypeHybrid}
	set curMap to contents of item selSeg of mapList
	
	repeat with i in aMapViewList
		set aView to contents of i
		(aView's setMapType:(curMap))
	end repeat
end clickedSeg:

But half the time I run it I get:

If I run that I get the following error, even if I run it as a straight script:

It’s weird to hear that the script in post #22 works and the script in post #21 doesn’t, because they are the same thing. Only my script is more orderly when it comes to properties and handlers. The given error most likely means that the current photo does not contain any GPS data.

You must understand - it is impossible for me to check what you are doing there, because I have neither Keyboard Maestro nor your photos (with or without GPS data). Here you have to figure it out for yourself.

It is a strange one indeed. The script you use always returns the same location which is weird.

The other script doesn’t. Very strange indeed.

That error is indeed generated when there is no GPS data in the photo :slight_smile:

The scrips were being run stand alone. But now we have the ‘finished’ item I’ve copied it into Keyboard Maestro and it runs perfectly!

So I have a solution. Many, many many thanks for your assistance.

The last thing I’ll do is work out how remove the first two maps (done already) and then resize the background to half the size (now done).

So all finished.

So I guess the final part would be to show on screen a dialog box saying ‘No GPS data in photo’ if the

Error was detected. Is this possible?

It is possible with try block, but it is better detect the empty GPS data before the error occurs:


set gpsCoords to do shell script "usr/local/bin/exiftool " & "'" & imageFile & "'" & " -gpslatitude# -gpslongitude#"
if gpsCoords = "" then
	display dialog "The image doesn't contain GPS data"
	return
end if
-- rest script

Brilliant many thanks! :smiley: