I thought it was interesting that people could unfriend you and you might never notice, or not notice for months or years, and then not know when and if it correlated with something you did or something. So I wrote a program that just compares your old friends' list with your new one so you can get notified when someone unfriends you. The same thing would be useful for Instagram, I'd say. People will want to know when they're being unfollowed and by whom.

read more

on friendExtractionGivenan(id, type)
	
	
	if type is equal to "indirect" then
		tell application "Safari"
			set doc to front document
			set done_loading to false
			do JavaScript "
		window.location.assign('http://www.facebook.com/" & id & "?sk=friends&v=friends');
		" in doc
			delay 1
		end tell
	end if
	
	if type is equal to "direct" then
		tell application "Safari"
			set doc to front document
			set done_loading to false
			do JavaScript "
		window.location.assign('http://www.facebook.com/profile.php?id=" & id & "&sk=friends&v=friends');
		" in doc
			delay 1
		end tell
	end if
	
	
	
	
	tell application "Safari"
		repeat while done_loading is not equal to true
			set doc to front document
			set done_loading to do JavaScript "
			var done = false;
			 if (document.readyState=='complete'){
			 	done=true;
			}
			
			done;
				" in doc
			delay 1
		end repeat
	end tell
	
	
	
	tell application "Safari"
		set doc to front document
		set this_url to URL of doc
		set done_scrolling to false
		set filtered_URLs to {}
		set completed_once to false
		set erred_once to false
		
		
		repeat while done_scrolling is not equal to true
			try
				set done_scrolling to do JavaScript "
		
		var completed_once = " & completed_once & ";
		if(completed_once!=true){
		var done;
		var number_of_trys =0;
		}
    function scrollToBottom(){
      bottom = document.body.scrollHeight;
      current = window.innerHeight+ document.body.scrollTop;
	done = false;
      if((bottom-current) >0){
        window.scrollTo(0, bottom);
        setTimeout (scrollToBottom, 2500 ); //If the loading exceeds this timeout, a try will be used.
      }
	  else {
			done = true;	
			
	  }
    };
	if(completed_once!=true){
   	 scrollToBottom();
	}
	
	if(done==true&&number_of_trys<10){//This number changes the number of allowed timeouts
		done=false;
		number_of_trys++;
		setTimeout(scrollToBottom, 1000);
		//This number sets the allotted timeout length.
		//If the loading exceeds both the timeout above and this timeout, another try will be used immediately.
	}
	
	done;
	
    " in doc
				
				set completed_once to true
				delay 1.0
			on error
				
			end try
		end repeat
		
		
		
		set URLs to false
		repeat while URLs is equal to false
			set URLs to do JavaScript "

	   URLArray = [];

	      		allLinks = document.links;
		for (i = 0; i < allLinks.length; i++) {
		
			URLArray.push(allLinks[i].href);
		}
			URLArray;
			
	  " in doc
		end repeat
		return URLs
		
	end tell
	
end friendExtractionGivenan

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

on extractionOfIDsFrom(unfiltered_links)
	set unfiltered to unfiltered_links
	set filtered to {}
	set direct_IDs to {}
	set indirect_IDs to {}
	set refined_IDs to {}
	set returned_IDs to {}
	repeat with x from 1 to count of items of unfiltered
		set n to item x of unfiltered
		if "=pb" is in n then
			if n is not in filtered then set end of filtered to n
		end if
	end repeat
	
	repeat with y from 1 to count of items of filtered
		set profile to item y of filtered
		
		if "profile.php?" is in profile then
			
			set end of direct_IDs to text ((offset of "=" in profile) + 1) thru ((offset of "&" in profile) - 1) of profile
			
		else
			set end of indirect_IDs to text 25 thru ((offset of "?" in profile) - 1) of profile
			
		end if
		
	end repeat
	
	return direct_IDs & indirect_IDs
	
end extractionOfIDsFrom


------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

on direct_indirect_ID_Checker(id)
	try
		id as integer
		return "direct"
	on error
		return "indirect"
	end try
end direct_indirect_ID_Checker

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
on loader(id, type)
	
	if type is equal to "indirect" then
		tell application "Safari"
			set doc to front document
			set done_loading to false
			do JavaScript "
		window.location.assign('http://www.facebook.com/" & id & "');
		" in doc
			delay 8
		end tell
	end if
	
	if type is equal to "direct" then
		tell application "Safari"
			set doc to front document
			set done_loading to false
			do JavaScript "
		window.location.assign('http://www.facebook.com/profile.php?id=" & id & "');
		" in doc
			delay 8
		end tell
	end if
	
end loader
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------




on storeIDs(user_id, friends, database1)
	
	tell application "Database Events"
		tell database1
			tell record "Completed Nodes"
				make new field with properties {name:user_id, value:user_id}
			end tell
			tell record "IDs Awaiting Extraction"
				if field user_id exists then
					delete field user_id
				end if
			end tell
			
			set node to make new record with properties {name:user_id}
			tell node
				repeat with x from 1 to count of items of friends
					set friend_id to item x of friends
					make new field with properties {name:"Friend " & x & "", value:friend_id}
				end repeat
			end tell
		end tell
	end tell
	save database1
end storeIDs

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
on existsInDatabaseChecker(user_id, database1)
	tell application "Database Events"
		
		if record user_id of database1 exists then
			return true
		else
			return false
		end if
	end tell
end existsInDatabaseChecker

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
on recursiveExtraction(database1)
	set IDstobeextracted to {}
	tell application "Database Events"
		if (count of fields of record "IDs Awaiting Extraction" in database1) is equal to 1 then
			repeat with y from 2 to count of fields of record "Completed Nodes" in database1
				set userID to value of field y of record "Completed Nodes" in database1
				repeat with x from 2 to count of fields of record userID in database1
					set currentID to value of field x of record userID of database1
					set end of IDstobeextracted to currentID
					tell database1
						tell record "IDs Awaiting Extraction"
							make new field with properties {name:currentID, value:currentID}
						end tell
					end tell
				end repeat
			end repeat
		else
			repeat with y from 2 to count of fields of record "IDs Awaiting Extraction" in database1
				set userID to value of field y of record "IDs Awaiting Extraction" in database1
				set end of IDstobeextracted to userID
			end repeat
			
		end if
	end tell
	repeat with c from 1 to count of items in IDstobeextracted
		set targetID to item c of IDstobeextracted
		set dataAlreadyCollected to existsInDatabaseChecker(targetID, database1)
		if dataAlreadyCollected is false then
			set IDType to direct_indirect_ID_Checker(targetID)
			set unfiltered_links to friendExtractionGivenan(targetID, IDType)
			set returnedIDs to extractionOfIDsFrom(unfiltered_links)
			storeIDs(targetID, returnedIDs, database1)
		end if
	end repeat
	
end recursiveExtraction
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
on exportToPlist(database1)
	
	tell application "System Events"
		set parent_dictionary to make new property list item with properties {kind:record}
		set the plistfile_path to ("Macintosh HD:Users:Puccio:Documents:My Documents:Scripts:Database:" & "Viewing.plist")
		set plist to make new property list file with properties {contents:parent_dictionary, name:plistfile_path}
	end tell
	
	
	
	tell application "Database Events"
		repeat with y from 1 to count of records in database1
			set thefields to {}
			set currentRecordName to name of record y of database1
			
			repeat with x from 2 to count of fields of record currentRecordName in database1
				set end of thefields to value of field x of record currentRecordName of database1
			end repeat
			
			tell application "System Events"
				tell plist
					set node to make new property list item at end with properties {kind:record, name:currentRecordName}
					tell node
						repeat with z from 1 to count of items of thefields
							set fieldID to item z of thefields
							make new property list item at end with properties {name:"Friend " & z & "", value:fieldID}
						end repeat
					end tell
				end tell
			end tell
			
			
			
			
		end repeat
	end tell
end exportToPlist

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
set theOutputFolder to POSIX path of "Macintosh HD:Users:Puccio:Documents:My Documents:Scripts:Database:"
set databaselocation to POSIX path of "Macintosh HD:Users:Puccio:Documents:My Documents:Scripts:Database:Friends.dbev"

tell application "Database Events"
	set database1 to database databaselocation
end tell
set processCancelled to false
set IDgiven to false

--exportToPlist(database1)

repeat while IDgiven is not equal to true
	set requestingStartingID to display dialog "What is the starting ID?" default answer "Monstermac77" with title "Facebook Data Extraction" buttons {"Indirect", "Direct", "More Options"} default button 1
	set button_pressed to the button returned of the result
	if the button_pressed is "Direct" then
		set startingIDType to "Direct"
		set IDgiven to true
	else if the button_pressed is "Indirect" then
		set startingIDType to "Indirect"
		set IDgiven to true
	else
		display dialog "These are your options:
	
	" with title "More Options" buttons {"Database Options", "Cancel Process", "Return to previous dialog"} default button 3
		if the button returned of the result is "Database Options" then
			display dialog "These are your options:
	" with title "More Options" buttons {"Visualize Data", "Reset Database", "Return to original dialog"} default button 3
			if the button returned of the result is "Reset Database" then
				tell application "Database Events"
					tell database1
						delete every record
					end tell
					save database1
					set database1 to make new database with properties {name:"Database", location:theOutputFolder}
					tell database1
						make new record with properties {name:"Completed Nodes"}
						make new record with properties {name:"IDs Awaiting Extraction"}
						
					end tell
					save database1
				end tell
			else if the button returned of the result is "Visualize Data" then
				exportToPlist(database1)
			end if
			
		else if the button returned of the result is "Cancel Process" then
			set processCancelled to true
			set IDgiven to true
		end if
	end if
end repeat


if processCancelled is false then
	
	set startingID to text returned of requestingStartingID
	set dataAlreadyCollected to existsInDatabaseChecker(startingID, database1)
	
	if dataAlreadyCollected is false then
		display dialog "Well you haven't even collected the first user's friends so we'll do that now"
		set unfiltered_links to friendExtractionGivenan(startingID, startingIDType)
		set returnedIDs to extractionOfIDsFrom(unfiltered_links)
		storeIDs(startingID, returnedIDs, database1)
		
		
		display dialog "Would you like to get the friends of everyone else and store them?" buttons {"Yes", "No"} default button 1
		if button returned of the result is "Yes" then
			recursiveExtraction(database1)
		end if
		
	else
		display dialog "What would you like to do?" buttons {"Store IDs", "Cross"} default button 2
		if button returned of the result is "Store IDs" then
			recursiveExtraction(database1)
		else
			set blah to display dialog "Enter the user whose current friends you want to cross with past friends" default answer "Monstermac77" buttons {"Indirect", "Direct"} default button 1
			if button returned of the result is "Indirect" then
				set startingIDType to "Indirect"
			else
				set startingIDType to "Direct"
			end if
			set IDOfInterest to text returned of blah
			
			
			set dataAlreadyCollected to existsInDatabaseChecker(IDOfInterest, database1)
			if dataAlreadyCollected is true then
				set unfiltered_links to friendExtractionGivenan(IDOfInterest, startingIDType)
				set friendsAtCurrentTime to extractionOfIDsFrom(unfiltered_links)
				set friendsAtOriginalTime to {}
				tell application "Database Events"
					repeat with x from 2 to count of fields of record IDOfInterest in database1
						set currentID to value of field x of record IDOfInterest of database1
						set end of friendsAtOriginalTime to currentID
					end repeat
				end tell
				
				
				--note that the date of original collection was Monday, November 29th. 
				--ask the user if they want to see who's new or who is old, put an if statement
				
				
				
				
				repeat with a from 1 to count of items in friendsAtOriginalTime
					set hey to item a of friendsAtOriginalTime
					if hey is not in friendsAtCurrentTime then
						set IDType to direct_indirect_ID_Checker(hey)
						loader(hey, IDType)
					end if
					
				end repeat
				--for people who have the timeline, the IDs on their friends list do not follow the same format which means we have to 
				--use the alternate filtering as we did in the other program
				
				
				display dialog "hey"
				
				repeat with a from 1 to count of items in friendsAtCurrentTime
					set hey to item a of friendsAtCurrentTime
					if hey is not in friendsAtOriginalTime then
						display dialog hey
					end if
				end repeat
				
			else
				display dialog "The friends of the user you entered are not in the database, pressing OK will collect just their friends"
				set unfiltered_links to friendExtractionGivenan(IDOfInterest, startingIDType)
				set returnedIDs to extractionOfIDsFrom(unfiltered_links)
				storeIDs(IDOfInterest, returnedIDs, database1)
			end if
		end if
		
	end if
end if