yt-react-db / issue-tracker

yt-react-db issue tracker
https://yt-react-db.com
0 stars 0 forks source link

Build extensions #3

Closed ComputerBread closed 1 year ago

ComputerBread commented 1 year ago

Explanation

Goal for extension is to do something like:

// on youtube
if (!watching_a_video) {
  return;
}
const channel_ID = grab_channel_ID() // if possible ( or channel Name?)
const permissions = fetch("yt-react-db", channel_ID)
if (!permissions) {
  show_question_grey_mark_icon();
} else if (permissions === "yes") {
  show_green_check_mark();
} else if (permissions === "no") {
  show_red_cross();
} else { // permissions === "yes_with_delay"
  const isDelayPassed = delay_processing(permissions.delay, now());
  if (isDelayPassed) show_green_check_mark();
  else show_red_cross();
}

figure out code color & icons for different cases: Nah, I am just going to make my own, it will be composed of 2 parts: left: live reaction, right: upload. Values:

Tool: https://www.pixilart.com/draw?ref=home-page

From https://developer.chrome.com/docs/extensions/mv3/manifest/icons/

Problems

useful stuff

const videoIDRegex = /youtube\.com\/watch.*?v=([^&]+)/;
const match = window.location.href.match(videoIDRegex);

if (match) { // could also be used to verify that we are watching a video
  const videoID = match[1];
  console.log('Video ID:', videoID);
} else {
  console.log('Not a YouTube video URL');
}

Todo


youtube is a single-page application, so the content script is injected only once, and doesn't reload when changing to a different video, and because there are some loading delays I need to be a bit careful with timing

Def needs my attention rn

ComputerBread commented 1 year ago

Let's talk about caching. To minimize the server's load, I need to cache requests. I first thought about implementing a LRU cache in JavaScript and store the data in the localstorage or indexedDB, but got lazy. I started looking at the Cache Web API, but you still need to do a lot of work:

Items in aĀ CacheĀ do not get updated unless explicitly requested; they don't expire unless deleted. You are also responsible for periodically purging cache entries.)

So instead, I will use the "default HTTP cache" (which you can't really access directly (unless I am wrong)). By default fetch use the cache, the browser looks for a matching request in its HTTP cache:

The good thing is that I don't really need to do anything (except making sure I am sending the HTTP header, Cache-control: max-age=<value>). But it also means that I have almost no control, the browser does everything, and the browser can delete the whole cache (even if it does, I guess it's not that bad).

No control mean: no size limit, will it slow down the user's browser?

I don't really want to think about it too much, I think using the default cache should be good enough. If it becomes a problem I will implement my own. Now the question is about how long should the data be cached, I am pretty sure, 99% of users will never update their permissions, so in practice, the data will never expires but still, what's a good value? 1 day, 2 days, 1 week? Should I make a difference between present and absent youtubers?

fresh and stale

Fresh state usually indicates that the response is still valid and can be reused. Stale state means that the cached response has already expired. The criterion used is age. In HTTP, age is the time elapsed since the response was generated. In HTTP/1.1, server can specify the header Cache-control: max-age=<value_in_seconds> to specify when the response should expire. When a response is stored in a shared cache, itā€™s necessary to inform the client of the responseā€™s age, to do that, the cache can add the HTTP header Age: nb_secs indicating how long the response has been cached.

In HTTP/1.0, freshness used to be specified by theĀ ExpiresĀ header. (Obsolete, cause uses an explicit time (like Tue, 28 Feb 2022 22:22:22 GMT ) which is harder to parse).

validation

stale responses are not immediately discarded. HTTP has a mechanism to transform a stale response into a fresh one by asking the origin server. This is called validation (or revalidation). Validation is done by using a conditional request that includes an If-Modified-SinceĀ orĀ If-None-MatchĀ request header.

I didn't know about conditional request before, it could definitely be useful for the full list, but to get a single permissions I think it could be worse. To implement conditional requests, the server needs to return at least one of Last-Modified or ETag HTTP headers.

:warning: note on cache being disabled

There's an option to disable the cache in the DevTools > Network. In firefox it was disable for some reason, and I lost a bit of time because of it ^^

ComputerBread commented 1 year ago

Content scripts don't have access to the chrome.action API (source), so I need to take care of modifying the icon in the background.

1. content script is injected
2. (optional) send message to background worker to change icon to loading icon
3. fetch permissions
4. send permission to background worker
5. background worker takes care of the logic

So, I need to learn about background worker. I also need to figure out:

intuitively I would say:

ComputerBread commented 1 year ago

Known issues

meta tag containing convenient publication date isn't always present on youtube

When the first page you load isn't a video, the meta tag, found using document.querySelector('meta[itemprop="datePublished"]'), isn't present on any pages afterward. If you start with a video it's present on every pages!

This tag is useful because it has a nice "yyyy-mm-dd" format (like "2022-07-31").

We can find the publication date using document.querySelector("#info-strings > yt-formatted-string").innerText but it returns a localeDateString (ex: Jul 31, 2022 or 7 avr. 2023 in french)

const event = new Date(Date.UTC(2012, 11, 20, 3, 0, 0));
const options = { year: 'numeric', month: 'short', day: 'numeric' };
console.log(event.toLocaleDateString('de-DE', options)); //"20. Dez. 2012"
console.log(event.toLocaleDateString('ar-EG', options)); // "Ł¢Ł  ŲÆŁŠŲ³Ł…ŲØŲ± Ł¢Ł Ł”Ł¢"
console.log(event.toLocaleDateString("fr-FR", options)); // "20 dƩc. 2012"
console.log(event.toLocaleDateString('en', options)); // "Dec 20, 2012"

But these strings are annoying to parse, I will need to use something like date-fns to help me:

import { parse } from "date-fns";

function parseDate(dateString, locale) {
      return parse(dateString, 'd LLL y', new Date(), { locale  });
}

const frenchDateStr = '7 avr. 2023';
const parsedDate = parseDate(frenchDateStr, require('date-fns/locale/fr'));
console.log(parsedDate); // Output: 2014-04-07T00:00:00.000Z

I found the list of country code used by google using the API:

"af", "am", "ar", "as", "az", "be", "bg", "bn", "bs", "ca", "cs", "da", "de", "el", "en-GB", "en-IN", "en", "es", "es-419", "es-US", "et", "eu", "fa", "fi", "fil", "fr-CA", "fr", "gl", "gu", "hi", "hr", "hu", "hy", "id", "is", "it", "iw", "ja", "ka", "kk", "km", "kn", "ko", "ky", "lo", "lt", "lv", "mk", "ml", "mn", "mr", "ms", "my", "no", "ne", "nl", "or", "pa", "pl", "pt", "pt-PT", "ro", "ru", "si", "sk", "sl", "sq", "sr-Latn", "sr", "sv", "sw", "ta", "te", "th", "tr", "uk", "ur", "uz", "vi", "zh-CN"

For now, I just set a condition to use "0000-00-00" when we can't find the meta tag, because I don't want to waste too much time, I don't want to deal with a build step right now, I want to be done with the overall logic before! But once I am done, here what I can do:

prerequisites:

algo:

  1. if meta tag exists: return itā€™s content attribute
  2. otherwise, get userā€™s locale using const userLocale = navigator.language;
  3. compare it to the one supported by date-fns
    1. if thereā€™s a match ā€œreturn localeā€
    2. if thereā€™s no match return ā€œ0000-00-00ā€
  4. extract date from document.querySelector("#info-strings > yt-formatted-string").innerText
  5. parse it into the wanted format ā€œyyyy-MM-ddā€ and return it
  6. (donā€™t forget to deal with the timeout and shit)

build:

ComputerBread commented 1 year ago

For firefox, the manifest needs to be a bit different, for now I just have 2 manifest.json files. I will deal with it later! It seems to work alright in firefox

ComputerBread commented 1 year ago

Ok, I think I am done building the alpha version! probably a lot of bugs, surely it's not entirely done (like shouldn't the extension ask for permission to access a website?) but I really want to close this issue ^^, just press the button