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