/* * Downloads all images from your Instagram timeline * to your disk and reinserts geo and time EXIF metadata. */ // conductance deps var http = require('sjs:http'); var fs = require('sjs:nodejs/fs'); var string = require('sjs:string'); // node deps var nodeFs = require('fs'); var nodeHttp = require('https'); var ex = require('exiv2'); var util = require('util'); // read instagram access token from a file called token // go get a token at https://apigee.com/console/instagram var accessToken = fs.readFile('token').toString(); var base = 'https://api.instagram.com/v1/users/self/media/recent/?access_token=' + accessToken; var data = []; var urlCursor = base; function downloadItem(item) { var file = downloadFile( item.images.standard_resolution.url, 'timeline/' + item.id + '.jpg'); var timestamp = customFormat( new Date(parseInt(item.created_time)*1000), '#YYYY#:#MM#:#DD# #hh#:#mm#:#ss#'); var tags = { 'Exif.Image.DateTime': timestamp, 'Exif.Image.DateTimeOriginal': timestamp, 'Exif.Image.ImageDescription': item.caption ? item.caption.text : '' }; if (item.location) { var lat = ConvertDDToDMS(item.location.latitude, false); var lng = ConvertDDToDMS(item.location.longitude, true); tags['Exif.GPSInfo.GPSLatitude'] = GPSString(lat); tags['Exif.GPSInfo.GPSLatitudeRef'] = lat.dir; tags['Exif.GPSInfo.GPSLongitude'] = GPSString(lng); tags['Exif.GPSInfo.GPSLongitudeRef'] = lng.dir; } setImageTags(file, tags); } while (urlCursor) { var response = http.json(urlCursor); timeline = timeline.concat(response.data); response.data.forEach(downloadItem); urlCursor = response.pagination.next_url; } fs.writeFile('timeline.json', JSON.stringify(timeline)); /*********** Code found on the internet ***********/ function GPSString(obj) { return dec2frac(obj.deg) + ' ' + dec2frac(obj.min) + ' ' + dec2frac(obj.sec); } function ConvertDDToDMS(D, lng){ return { dir : D<0?lng?'W':'S':lng?'E':'N', deg : 0|(D<0?D=-D:D), min : 0|D%1*60, sec :(0|D*60%1*6000)/100 }; } function downloadFile(path, file) { waitfor() { var f = nodeFs.createWriteStream(file); nodeHttp.get(path,function(res){ res.on('data', function (chunk) { f.write(chunk); }); res.on('end',function(){ f.end(); hold(10); resume(); }); }); } return file; } function getImageTags(path) { var rv; waitfor() { ex.getImageTags(path, function(err, tags) { rv = tags; resume(); }); } return rv; } function setImageTags(path, tags) { waitfor() { ex.setImageTags(path, tags, function(err){ resume(); }); } } function customFormat(date, formatString){ var YYYY,YY,MMMM,MMM,MM,M,DDDD,DDD,DD,D,hhhh,hhh,hh,h,mm,m,ss,s,ampm,AMPM,dMod,th; YY = ((YYYY=date.getFullYear())+"").slice(-2); MM = (M=date.getMonth()+1)<10?('0'+M):M; MMM = (MMMM=["January","February","March","April","May","June","July","August","September","October","November","December"][M-1]).substring(0,3); DD = (D=date.getDate())<10?('0'+D):D; DDD = (DDDD=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"][date.getDay()]).substring(0,3); th=(D>=10&&D<=20)?'th':((dMod=D%10)==1)?'st':(dMod==2)?'nd':(dMod==3)?'rd':'th'; formatString = formatString.replace("#YYYY#",YYYY).replace("#YY#",YY).replace("#MMMM#",MMMM).replace("#MMM#",MMM).replace("#MM#",MM).replace("#M#",M).replace("#DDDD#",DDDD).replace("#DDD#",DDD).replace("#DD#",DD).replace("#D#",D).replace("#th#",th); h=(hhh=date.getHours()); if (h===0) h=24; if (h>12) h-=12; hh = h<10?('0'+h):h; hhhh = h<10?('0'+hhh):hhh; AMPM=(ampm=hhh<12?'am':'pm').toUpperCase(); mm=(m=date.getMinutes())<10?('0'+m):m; ss=(s=date.getSeconds())<10?('0'+s):s; return formatString.replace("#hhhh#",hhhh).replace("#hhh#",hhh).replace("#hh#",hh).replace("#h#",h).replace("#mm#",mm).replace("#m#",m).replace("#ss#",ss).replace("#s#",s).replace("#ampm#",ampm).replace("#AMPM#",AMPM); } function dec2frac(d) { var df = 1; var top = 1; var bot = 1; while (df != d) { if (df < d) { top += 1; } else { bot += 1; top = parseInt(d * bot); } df = top / bot; } return top + '/' + bot; }