Skip to content

Instantly share code, notes, and snippets.

@guillaumematheron
Last active April 4, 2024 21:08
Show Gist options
  • Save guillaumematheron/89f52ffd274ff3ac99f6dc0249bcc331 to your computer and use it in GitHub Desktop.
Save guillaumematheron/89f52ffd274ff3ac99f6dc0249bcc331 to your computer and use it in GitHub Desktop.
"""
Simulate re-watching all your videos from a given date onwards.
If part of your youtube history has been deeleted but is still visible from 'my activity', then
you can export it using google takeout, and use this script to simulate watching all these videos
in order, in a relatively short time.
Note that the history will not be backdated.
License: CC0 / Public domain
"""
import hashlib
import json
import random
import os
import time
from typing import Any, Dict, List
import yt_dlp
RESUME = "2022-08-17T11:50:00.000Z"
def main():
# An empty file will be created in the 'done' directory to keep track
# of videos that were already watched, so that this script can be
# interrupted and resumed.
try:
os.makedirs("done")
except FileExistsError:
pass
# This file should be generated using google takeout
with open("watch-history.json", encoding="utf8") as f:
data = json.load(f)
kept: List[Dict[str, Any]] = []
for event in data:
# Disregard youtube music
if event["header"] != "YouTube":
continue
if "details" in event and event["details"][0]["name"] == "From Google Ads":
continue
if event["time"] < RESUME:
continue
if "titleUrl" not in event:
continue
kept.append(event)
print(f"Found {len(kept)} videos to watch")
# Deduplicate
kept = [event for event in {event["titleUrl"]: event for event in kept}.values()]
print(f"Found {len(kept)} videos to watch after de-duplication")
# Sort
kept.sort(key=lambda x: x["time"])
opts = {
"mark_watched": True,
"simulate": True,
"quiet": True,
"cookiesfrombrowser": ("firefox",),
}
with yt_dlp.YoutubeDL(opts) as ydl:
for i, event in enumerate(kept):
t = event["time"]
url = event["titleUrl"]
title = event["title"][8:]
m = hashlib.sha256()
m.update(url.encode("utf-8"))
marker = "done/" + m.hexdigest()
print(
f"{i}/{len(kept)} \t {t} \t {url} \t {title} ... ", end="", flush=True
)
try:
with open(marker, "r"):
pass
print(" -> Already done")
continue
except FileNotFoundError:
pass
try:
ydl.download(url)
print(" -> Sleeping ... ", end="", flush=True)
time.sleep(3 + random.random() * 8)
print(" -> Done")
except yt_dlp.utils.DownloadError:
print(" -> DownloadError")
with open(marker, "w"):
pass
if __name__ == "__main__":
main()
@seaque
Copy link

seaque commented Mar 7, 2024

Not ideal at all, tried couple dozens of videos and all of them falls into the current date, not the date you have watched.

@guillaumematheron
Copy link
Author

Yes, as far as I know there is no way to backdate the watch date of videos unfortunately. I'll add a comment making that clear.

@quangvux2001
Copy link

quangvux2001 commented Mar 10, 2024

It's seem that my history json have only history recently. It does not contain any history further than 28 february 2024. Does anyone can explain this to me and have the same issue? Thanks
image

@seaque
Copy link

seaque commented Mar 15, 2024

an update, the history entries started coming back for a lot of people. It seems mine is mostly fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment