Skip to content

Commit

Permalink
Apply Requested Changes
Browse files Browse the repository at this point in the history
  • Loading branch information
GRWalter authored and Stadly committed Jul 30, 2024
1 parent 897b2ab commit 6824e3e
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 41 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,18 @@ Follow the steps below to get your authentication cookie from Google Maps Timeli
2. Open `Developer tools` (`F12`).
3. In the console, run this command to download the currently selected day's KML file `document.querySelector('.goog-menuitem.export-kml').click();`.
4. A new tab will briefly open and your KML download will start.
- Depending on your browser settings, you may get a message saying that a pop-up has been prevented from opening; click the message and open the pop-up.
- If you are prompted to save or cancel the download, be sure to save it (otherwise the URL may not be logged in the history and we'll need that).
5. Open the browser history (`CTRL` + `Shift` + `H`).
6. Copy the most recent URL, which should be something like this: `https://timeline.google.com/maps/timeline/kml?authuser=1&pb=%211m8%211m3%211i1990%212i0%213i1%212m3%211i2090%212i0%213i1&pli=1&rapt=<REAUTH PROOF TOKEN>`.
- Depending on your browser settings, you may get a message saying that a pop-up has been prevented from opening; click the message and open the pop-up.
- If you are prompted to save or cancel the download, be sure to save it (otherwise the URL may not be logged in the history and we'll need that).
5. Open the browser history in Firefox (`CTRL` + `Shift` + `H`) or the download history in Chrome (`CTRL` + `J`).
6. Copy the most recent URL, which should be something like this: `https://timeline.google.com/maps/timeline/kml?authuser=<AUTH USER NUMBER>&pb=%211m8%211m3%211i1990%212i0%213i1%212m3%211i2090%212i0%213i1&pli=1&rapt=<REAUTH PROOF TOKEN>`.
7. With the Developer tools still open, paste that URL into the address bar of your browser.
8. A new request will appear in the `Network` tab. Click on it.
9. Details about the request should appear; look for the `Cookie` in the request headers and copy the cookie value.
10. Save the cookie's content so you can use it to authenticate requests sent by `TimelineExtractor` when downloading location history. It is recommended to store it in a file called `cookie` in the directory `src`, as that will be assumed in most of the examples further down.
11. Make note of the `authuser` number in the URL. Pass this to the `TimelineExtractor` script with the `-u` or `--authuser` argument.
12. Copy the value of the `rapt` parameter in the URL. Pass this to the `TimelineExtractor` script with the `-r` or `--rapt` argument.
11. Make note of the `authuser` number in the URL. Pass this to the `TimelineExtractor` script with the `-u` or `--authuser` argument.
12. Copy the value of the `rapt` parameter in the URL. Pass this to the `TimelineExtractor` script with the `-r` or `--rapt` argument.

Please note that valid cookie and reauth proof tokens change frequently, so these steps may need to be repeated, depending on your usage of the `TimelineExtractor`.
Please note that valid cookie and reauth proof tokens change frequently, so these steps may need to be repeated, depending on your usage of `TimelineExtractor`.

### Install in Docker container

Expand Down
46 changes: 23 additions & 23 deletions src/LocationHistory.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,68 +55,68 @@ def Merge(LocationHistory1: ET.ElementTree, LocationHistory2: ET.ElementTree) ->
return LocationHistory1


def GetDate(Date: DT.date, AuthCookie: str, authuser: int, rapt: str) -> ET.ElementTree:
def GetDate(Date: DT.date, AuthCookie: str, AuthUser: int, Rapt: str) -> ET.ElementTree:
"""
Get location history for a date.
"""
Url = 'https://www.google.com/maps/timeline/kml?authuser={3}&pb=!1m8!1m3!1i{0}!2i{1}!3i{2}!2m3!1i{0}!2i{1}!3i{2}&pli=1&rapt={4}'.format(Date.year, Date.month - 1, Date.day, authuser, rapt)
Url = 'https://www.google.com/maps/timeline/kml?authuser={3}&pb=!1m8!1m3!1i{0}!2i{1}!3i{2}!2m3!1i{0}!2i{1}!3i{2}&pli=1&rapt={4}'.format(Date.year, Date.month - 1, Date.day, AuthUser, Rapt)

Response = requests.get(Url, cookies=dict(cookie=AuthCookie))
if 200 != Response.status_code:
raise Exception('Could not fetch location history.')

if not Response.text.startswith('<?xml'):
raise Exception('Could not fetch location history. Check your cookie and reauth proof token (rapt).')
raise Exception('Could not fetch location history. Check your cookie and reauth proof token (rapt).')

return ET.ElementTree(ET.fromstring(Response.text))


def GetDates(Dates: List[DT.date], AuthCookie: str, authuser: int, rapt: str) -> ET.ElementTree:
def GetDates(Dates: List[DT.date], AuthCookie: str, AuthUser: int, Rapt: str) -> ET.ElementTree:
"""
Get location history for one or more dates.
"""
if not bool(Dates):
raise Exception('You must specify at least one date.')

SortedDates = sorted(Dates)
total_dates = len(SortedDates)
current_date = 1
DisplayProgress(SortedDates[0], current_date, total_dates)
TotalDates = len(SortedDates)
CurrentDate = 1
DisplayProgress(SortedDates[0], CurrentDate, TotalDates)

LocationHistory = GetDate(SortedDates[0], AuthCookie, authuser, rapt)
LocationHistory = GetDate(SortedDates[0], AuthCookie, AuthUser, Rapt)

for Date in SortedDates[1:]:
current_date += 1
DisplayProgress(Date, current_date, total_dates)
CurrentDate += 1
DisplayProgress(Date, CurrentDate, TotalDates)
try:
LocationHistory = Merge(LocationHistory, GetDate(Date, AuthCookie, authuser, rapt))
LocationHistory = Merge(LocationHistory, GetDate(Date, AuthCookie, AuthUser, Rapt))
except:
logging.error('Location history could not be downloaded. You may have been unauthenicated or a Captcha may be required in your browser. Your output file is being saved with what was downloaded so far.')
logging.error('Location history could not be downloaded. You may have been unauthenicated or a Captcha may be required in your browser. Your output file is being saved with what was downloaded so far.')
return LocationHistory

return LocationHistory


def GetDateRange(StartDate: DT.date, EndDate: DT.date, AuthCookie: str, authuser: int, rapt: str) -> ET.ElementTree:
def GetDateRange(StartDate: DT.date, EndDate: DT.date, AuthCookie: str, AuthUser: int, Rapt: str) -> ET.ElementTree:
"""
Get location history for a date range.
"""
if EndDate < StartDate:
raise Exception('Start date cannot be later than end date.')

total_dates = (EndDate - StartDate).days
current_date = 1
DisplayProgress(StartDate, current_date, total_dates)
LocationHistory = GetDate(StartDate, AuthCookie, authuser, rapt)
TotalDates = (EndDate - StartDate).days
CurrentDate = 1
DisplayProgress(StartDate, CurrentDate, TotalDates)
LocationHistory = GetDate(StartDate, AuthCookie, AuthUser, Rapt)

for Delta in range(total_dates):
for Delta in range(TotalDates):
Date = StartDate + DT.timedelta(Delta + 1)
current_date += 1
DisplayProgress(Date, current_date, total_dates)
CurrentDate += 1
DisplayProgress(Date, CurrentDate, TotalDates)
try:
LocationHistory = Merge(LocationHistory, GetDate(Date, AuthCookie, authuser, rapt))
LocationHistory = Merge(LocationHistory, GetDate(Date, AuthCookie, AuthUser, Rapt))
except:
logging.error('Location history could not be downloaded. You may have been unauthenicated or a Captcha may be required in your browser. Your output file is being saved with what was downloaded so far.')
logging.error('Location history could not be downloaded. You may have been unauthenicated or a Captcha may be required in your browser. Your output file is being saved with what was downloaded so far.')
return LocationHistory


Expand Down Expand Up @@ -189,4 +189,4 @@ def RemoveErroneousAltitude(KmlTree: ET.ElementTree) -> None:

def DisplayProgress(date: DT.date, current_download: int, total_downloads: int):
"""Display Current Progress"""
print(f'Downloading {date} | {current_download}/{total_downloads} | {current_download/total_downloads*100:.2f}%\r', end='', flush=True)
print(f'Downloading {date} | {current_download}/{total_downloads} | {current_download/total_downloads*100:.2f}%\r', end='', flush=True)
22 changes: 11 additions & 11 deletions src/extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,31 @@
import CaptureDate
import LocationHistory

def OutputLocationHistory(History: ET.ElementTree, output: argparse.FileType) -> None:
def OutputLocationHistory(History: ET.ElementTree, Output: argparse.FileType) -> None:
LocationHistory.RemoveErroneousAltitude(History)
LocationHistory.ConvertTimeSpanPointToLineString(History)
LocationHistory.ReorderLineStringAndTimeSpan(History)

# Set the default namespace. Workaround for bug in GPSBabel: https://github.com/gpsbabel/gpsbabel/issues/508
ET.register_namespace('', 'http://www.opengis.net/kml/2.2')
with open(output.name, 'w', encoding='utf-8') as out_file:
out_file.write('<?xml version="1.0" encoding="UTF-8"?>\n')
out_file.write(ET.tostring(History.getroot(), encoding='utf-8').decode('utf-8'))
with open(Output.name, 'w', encoding='utf-8') as OutputFile:
OutputFile.write('<?xml version="1.0" encoding="UTF-8"?>\n')
OutputFile.write(ET.tostring(History.getroot(), encoding='utf-8').decode('utf-8'))

logging.info(f'Location history has been saved to {output.name}')
logging.info(f'Location history has been saved to {Output.name}')


def GetLocationHistoryForDates(Dates: List[DT.date], AuthCookie: str, authuser: int, rapt: str) -> ET.ElementTree:
def GetLocationHistoryForDates(Dates: List[DT.date], AuthCookie: str, AuthUser: int, Rapt: str) -> ET.ElementTree:
logging.info(f'Calculating location history for {len(Dates)} date(s)')
return LocationHistory.GetDates(Dates, AuthCookie, authuser, rapt)
return LocationHistory.GetDates(Dates, AuthCookie, AuthUser, Rapt)


def GetLocationHistoryForDateRange(StartDate: DT.date, EndDate: DT.date, AuthCookie: str, authuser: int, rapt: str) -> ET.ElementTree:
def GetLocationHistoryForDateRange(StartDate: DT.date, EndDate: DT.date, AuthCookie: str, AuthUser: int, Rapt: str) -> ET.ElementTree:
logging.info(f'Calculating location history for {StartDate:%Y-%m-%d} to {EndDate:%Y-%m-%d}')
return LocationHistory.GetDateRange(StartDate, EndDate, AuthCookie, authuser, rapt)
return LocationHistory.GetDateRange(StartDate, EndDate, AuthCookie, AuthUser, Rapt)


def GetLocationHistoryForPaths(Paths: List[str], VisitSubdirectories: bool, AuthCookie: str, authuser: int, rapt: str) -> Optional[ET.ElementTree]:
def GetLocationHistoryForPaths(Paths: List[str], VisitSubdirectories: bool, AuthCookie: str, AuthUser: int, Rapt: str) -> Optional[ET.ElementTree]:
DateTimes = set()
for Path in Paths:
logging.info(f'Calculating dates for photos in {Path}')
Expand All @@ -41,7 +41,7 @@ def GetLocationHistoryForPaths(Paths: List[str], VisitSubdirectories: bool, Auth
return None

Dates = list(set(map(lambda d: d.date(), DateTimes)))
return GetLocationHistoryForDates(Dates, AuthCookie, authuser, rapt)
return GetLocationHistoryForDates(Dates, AuthCookie, AuthUser, Rapt)


def StringToDate(DateString: str) -> DT.date:
Expand Down

0 comments on commit 6824e3e

Please sign in to comment.