Podchaser Logo
Home
783: How We Built a Netflix Style “Save for Offline” Feature Into Syntax

783: How We Built a Netflix Style “Save for Offline” Feature Into Syntax

Released Monday, 17th June 2024
Good episode? Give it some love!
783: How We Built a Netflix Style “Save for Offline” Feature Into Syntax

783: How We Built a Netflix Style “Save for Offline” Feature Into Syntax

783: How We Built a Netflix Style “Save for Offline” Feature Into Syntax

783: How We Built a Netflix Style “Save for Offline” Feature Into Syntax

Monday, 17th June 2024
Good episode? Give it some love!
Rate Episode

Episode Transcript

Transcripts are displayed as originally observed. Some content, including advertisements may have changed.

Use Ctrl + F to search

0:00

Ooh, welcome to syntax on this Monday, hasty

0:03

treat. We're going to be once again, talking

0:05

about the thing that we all hold so

0:07

dearly. In fact, we hold it for a

0:09

long time. Sometimes we hold it for days

0:12

and days. I'm talking about caching. We're going

0:14

to be talking about caching, but not necessarily

0:16

in the ways that we've talked about it

0:18

before. We're going to be talking about the

0:20

cache API, which many people think of as

0:23

being part of service workers, but we're going

0:25

to be talking about how we used it

0:27

to build a Netflix style save for offline

0:29

for the application for

0:31

podcast episodes on our syntax site. My

0:34

name is Scott Tolinsky. I'm a developer

0:36

from Denver and with me as always

0:38

is Wes boss. Hey,

0:40

I am really excited about this because

0:43

I did not realize that this was the

0:45

API that you needed to, to

0:48

store stuff locally, um, in the browser.

0:50

I always thought it was like file system APIs

0:53

or index DB. And it turns out

0:55

that there is a really nice cache API.

0:57

That's not just service worker. I've used it

0:59

plenty of times in service workers, but not

1:01

for storing data in the browser and

1:03

I've always wondered myself, like I would love to be

1:06

able to. For

1:08

my courses, like save them in the browser,

1:10

so people can watch them, but still get

1:12

the whole streaming experience. You know? Yeah. I

1:14

know the solutions I thought of for that

1:16

at some point, because I thought about the

1:18

same thing when I was doing level up

1:20

tutorials was, I guess I'm

1:22

going to have to make an electron app,

1:24

right? Making a desktop app and then therefore

1:26

they could download the course and then have

1:28

it be easily work with the file system

1:30

that way because the browser file system, if,

1:32

if we haven't taken a look at

1:34

that yet, in fact, maybe I should even pull that up here before

1:37

we even get too deep into this, if

1:39

you are listening on audio, we'll be showing some

1:41

stuff on video here. I know, I know I've

1:44

said that a couple of times here, but I'll

1:46

be pulling up API docs, I'll be showing some

1:48

code. We're going to make the experience of the

1:50

episode work just fine with audio as well. But

1:52

I will be showing some things like this,

1:54

like the file system API. And

1:57

you can see what the file system API browser.

2:00

is not yet here. It works with Safari,

2:02

it works with Chrome, it works with Edge.

2:04

It does not work with Firefox fully. Now,

2:07

this is going to be the type of thing that's potentially

2:10

going to throw an error in your system if you're

2:13

trying to load up the file system API and

2:15

it doesn't exist and you don't have permissions for

2:18

it. For something like that, you might want a

2:20

tool like Sentry at sentry.io/syntax. Sign up and get

2:22

two months for free and it'll track and log

2:24

all of the errors in your application and that's

2:26

going to be really handy if you're working with

2:28

things like a cache, right? You don't know what

2:30

you don't know if you're trying to save things.

2:33

So, why not use the file

2:35

system API for storing this kind of thing? One,

2:37

it doesn't work on every browser. Two, you do

2:40

have to get permissions and how,

2:42

like, you click a thing to

2:45

access the file system API.

2:47

In fact, I did a whole course using

2:49

the file system API and it

2:51

pops up saying like, hey, the browser wants to

2:53

access your local files. I think they can bring

2:55

some people out. It's kind of spooky when it

2:57

happens. It'll freak me out, yeah. So,

3:00

you know, I think there is some reason there.

3:02

I wanted this to just work transparently. Like, you

3:04

hit a button, it saves to

3:06

your system, that's it, right? So,

3:09

that's why I reached for the cache

3:11

API which is, like you mentioned, you

3:13

mentioned it being related to service workers.

3:15

It's a part of the service worker

3:17

API and I think because of that,

3:19

people don't realize you don't have to

3:21

use it within service workers. And in

3:23

fact, somewhere in this

3:25

mess on the MDN docs of paragraphs, it

3:27

says, hey, just because this is a part

3:30

of the service worker API

3:32

does not mean you need to use it

3:34

in service workers itself. It does need to

3:36

be in a secure context, HTTPS, all that

3:38

stuff. Not really super

3:40

surprising there. But, hey,

3:42

man, what is the cache API? It's basically

3:44

a way for you to access and

3:47

cache things in a request

3:49

response way without

3:51

having to do it via the

3:54

browser cache or caching headers. You're

3:56

essentially creating your own cache

3:58

response directly inside. in the browser. And

4:01

it's really pretty simple. So

4:03

we're going to be diving into one, how we

4:06

pulled off, what we pulled off on the

4:08

syntax site, maybe some gotchas. And then we're

4:10

going to be talking even further about

4:13

persistent storage and sizes of storage

4:15

and those types of things. So

4:18

first and foremost, like I said, cache API, you

4:21

could do a lot with this stuff. You can

4:23

put anything in here. There is some caveats

4:26

there in terms of size. So

4:29

Chrome. Chrome is probably the best for this,

4:31

because Chrome lets you store a percentage,

4:34

typically 6% to 10% of

4:37

the device's free space, meaning that if

4:39

your device has 100 gigabytes

4:42

free, you could store anywhere from 6%

4:44

to 10 gigabytes, which

4:46

is kind of wild compared to when you

4:48

see some of the limits of some of

4:50

these other ones, where Firefox has a global

4:52

limit of 2 gigabytes for all storage APIs

4:55

combined. This is cache storage. It's any

4:57

of the storage APIs on your browser.

5:00

Yeah, because there's lots of ways to

5:03

store data in the browser. You have local

5:05

storage. You have index DB. You have one

5:07

of the other ones. I just

5:09

sent you a whole list. Is cookies coming from that?

5:12

Probably not. Local storage, cache API,

5:15

index DB, service worker, and file

5:17

system. So you talked about the

5:19

file system API. We're

5:21

talking about the cache API here. Index DB

5:23

is kind of like local storage, but it's

5:25

a bit more flexible for doing

5:27

full-blown database stuff. And then local storage

5:29

is just a nice key value store.

5:31

What I am curious about this cache

5:34

API is that you said

5:36

it's based on request and response, meaning

5:38

that those are web requests and web

5:41

response. And that's generally the

5:43

way that works with a service worker is that

5:46

when the browser requests like a CSS

5:48

file, you can write a service worker to

5:50

jump in the middle there. And then you

5:53

can say, oh, I've already stored this and

5:55

sent it on back because it's in the cache API.

5:57

But when you're not in a service worker,

6:00

Service Worker that's primarily a fetch request,

6:02

right? Mm-hmm. The thing you need to

6:04

talk about this is that it is

6:07

essentially the same API that you

6:09

use with caching headers, right? You're

6:11

caching things Like normal

6:13

it goes into the the browser cache and

6:15

that is a request response as

6:18

well Right you cache a font or you recr

6:20

at what you cache an image You

6:22

pop open your network tab you see that

6:24

being loaded directly from the cache But it's

6:27

not like it's not like a

6:29

key value store. It's the request and response It

6:31

just happens transparently behind the scenes What this API

6:33

allows you to do is just step in and

6:36

store anything that you want in

6:38

that same caching mechanism Which

6:40

which is thumbs and handy for all kinds of things You

6:43

might be wondering why we don't just cache it

6:45

via HTTP caching I'll tell talk a little bit

6:47

about that but before we get off that Safari

6:49

only has a limit of 500 megabits Megabytes

6:53

I say bits 500

6:56

megabytes per domain and

6:58

if it exceeds that limit Safari Will

7:00

start removing items from the cache to make space

7:03

for new data Which

7:05

is one of the reasons why tools like

7:07

what Riverside that we used for recording You

7:09

can only use it on Chrome because simply

7:11

recording that much video Is

7:14

not gonna work in Firefox or Safari

7:16

because you're gonna hit those limits Probably

7:20

while you're recording which that's no good,

7:22

right? Yeah, I was just just looking at

7:25

I'm in the dev tools right now

7:27

for Riverside as we're recording this and

7:29

they are sticking it in Index

7:33

DB. Yeah, and you can see the

7:35

little chunks like so

7:37

there's an API in the browser called

7:40

media recorder Not sure if they're

7:42

using media record or not But the get user media

7:44

will give you chunks of the users video and you

7:46

can put those into the

7:48

browser storage so that you can upload

7:50

them as you have As

7:53

you have space to do so and I was

7:55

always curious what that looks like and I guess

7:57

the reason why they're using Index DB here instead

8:00

of the cache API is because like

8:02

you said, cache API is only for requests

8:05

in response, right? It's not for, oh,

8:09

I made an image in the browser, or

8:11

I have this canvas element that I want to

8:13

be able to persist offline

8:15

and when I refresh, if it's not actually

8:17

a request to a server,

8:20

the cache API is not for that, right? Yes,

8:23

yeah, and it's, I

8:25

think, I wonder if I could have just

8:27

done this in IndexedDB as well. Honestly, I

8:29

don't know, but I think this was

8:31

the best approach for me and I'll talk a little bit about

8:33

why. I think so because at the end of the day, the

8:37

MP3 for the show is a request, right?

8:39

So it makes sense that you would request,

8:41

you would save it. Yeah, although

8:43

the way I am accessing it, I kind of am

8:45

accessing it like a key value store. Let's

8:48

talk real quick about eviction, that is

8:50

when the data is gone because you

8:53

cannot promise that the data will be

8:55

there forever. We'll talk

8:57

about persistence in just a second,

8:59

but eviction is when,

9:02

at some point, your hard drive is going to get

9:04

full. Between all

9:07

of the origins, which is like a domain

9:09

name on a browser, you're going to be

9:11

using too much of the space and there's

9:13

only so much that Chrome can be

9:16

allowed to use on your user's computer. And

9:19

when you get close to that limit, the

9:21

browser will just purge it for

9:23

you. So I always like to think of

9:25

these caches as unfortunately

9:27

you can keep

9:30

them there for fairly long and it

9:32

works fairly well. Like we use Riverside

9:34

and I don't think ever we've lost

9:36

a recording, maybe once, but

9:40

at a certain point, the browser will purge it

9:42

and you cannot guarantee that it

9:44

will be there forever. Yeah,

9:46

I like to think of these things as like

9:49

questionable storage. Not that it's questionable if it

9:51

will work, but questionable if it will be

9:54

there, right? You couldn't put things

9:56

in here, but you can't always

9:58

assume that it's going to be there. because

10:00

again, because of storage limits, how

10:03

the different browsers work or time or any of

10:05

that, different maybe you open it up on one

10:07

browser profile in another, so you can't always rely.

10:09

You kind of have to take it as like,

10:11

hey, I'm checking to make sure that the cache

10:13

exists first before doing anything. So

10:16

how exactly are we using it and what are

10:18

we using it for? I mentioned a little bit

10:20

about this. I'm gonna show a quick demo here.

10:22

I have the code open, I have a website

10:25

open if you're watching on YouTube, if you're watching

10:27

on your podcast player. If not, I'll describe it

10:29

basically, and I'm gonna preface

10:31

this, this is still in dev. This is

10:33

a, the interface is not complete for this

10:35

yet. So the way this works is

10:38

that I have a little pin here in the

10:40

player, and if I click the pin, it's

10:43

downloading the MP3 right now, and it's

10:45

downloading it and storing it as

10:48

a blob. When it's completed, the pin kind

10:50

of goes straight up and down, again, UI

10:52

is still being worked on here. But

10:54

one thing that you'll notice happened is

10:57

in my dev tools over here, which

10:59

is in dev tools application cache storage.

11:02

You'll see I have an MP3 cache here, and

11:05

now right over here, since that is

11:07

completed, I have an MP3 cache

11:09

where the, essentially the name of

11:12

it is the request URL. So

11:15

just syntax/and then an MP3. I

11:18

chose this URL as,

11:20

a URL that's not going to

11:22

be hit in the site necessarily.

11:25

That's not too important. Either way, you can see

11:27

that, you can see when it was stored, the

11:29

size of it, the response type,

11:31

and if I click on it, yeah,

11:34

there's no preview, but you do get the

11:36

headers and stuff here. So now, if I

11:39

were to go and play this file, if

11:41

I head to my network and I click

11:43

play episode, you can see

11:45

that, where did that go? Where's the

11:47

blob? Okay, so

11:50

I filtered by media, and you can see

11:52

that instead of trying to load this from

11:54

Libsyn, which is where we host our MP3

11:56

files, you can see it's actually loading it

11:58

directly from local host. as a blob

12:00

here. So you can tell size

12:03

is zero bytes because it's

12:05

saved in storage. You didn't have to

12:07

download anything from the internet. So therefore,

12:09

this is now officially loading this file

12:11

from the local storage, not local storage,

12:14

but from my caching API as a

12:16

blob. So how do we

12:18

do this in code? Well, it's actually

12:20

pretty simple. Okay. So when we go

12:22

to save something offline, the first thing

12:24

we do is we fetch the MP3

12:26

as we normally would. And when that

12:29

comes back as a response, we grab

12:31

the blob from it. So

12:33

we don't grab JSON, whatever, it's an MP3,

12:35

right? So we grab the blob. Then

12:38

with that blob, what we're able

12:40

to do is create a new

12:42

response. Now I created a new

12:44

response specifically to attach not

12:46

only like content length here, but also metadata

12:49

here. For some reason, I don't know, I

12:51

don't know if this is maybe you can

12:53

tell me why West when I was doing

12:55

this without adding metadata in creating a new

12:57

response and just using the response from the

13:00

initial fetch, the content length

13:02

was zero for some reason, I had to

13:04

do this manually. I don't, I'm not exactly

13:06

sure why. Oh, that's,

13:10

it's, it's probably because it

13:12

was pulling it from your

13:15

browser's cache initially. Yeah, it's interesting.

13:17

I'm not quite sure why the whole

13:19

response and like streaming thing is really funky.

13:21

I was doing that with the syntax

13:23

website as well where I had to like,

13:26

I was trying to modify a response

13:28

and node was not letting me because

13:30

I'm trying to like modify a header.

13:32

So essentially had to like clone

13:35

the response and then loop over every

13:37

single header and add it in manually.

13:39

Yep. Because it was, it was kind

13:42

of funky. Yeah. So I had to

13:44

create a new response and I did

13:46

so using the blob, I made it

13:49

a content type of audio and MPEG

13:51

again, set the content links myself and

13:53

then the metadata header. What I did

13:55

is I JSON stringified the entire object

13:58

of the show data because What

14:00

we do when we have the syntax player

14:02

and you could click play it doesn't just

14:04

load the mp3 file It has the

14:06

title it has Link

14:08

to the episode it has like share stuff it

14:10

has a lot of information there But

14:13

if you're just doing a request and response to save

14:15

an mp3 And if I

14:17

was going to just cache that mp3 response

14:19

without the metadata It wouldn't

14:21

have any of that and then you'd click play

14:23

and yeah, you'd get the audio, but you wouldn't

14:26

get all the other stuff So I added the

14:28

metadata header I used the JSON stringify through all

14:30

the show information in there So that way when

14:32

we do load from cache we can retrieve that

14:35

information and load it up like normal So

14:37

to actually do the caching bit since I've

14:39

just created the response All we

14:41

did is we do caches, which is a

14:43

global dot open and then you give it

14:46

a name You'll notice mp3 cache

14:48

was the exact same name that we

14:50

saw in The browser

14:52

dev tools when I looked at my

14:54

application cache right here It's the name

14:56

that you're giving to this bucket So

14:59

by giving your information or your

15:01

cache a name you're essentially making

15:04

a bucket So once

15:06

the cache is open it returns a promise so

15:08

I do a then and then I

15:10

can do cache dot put Where I

15:12

then give it a URL which is essentially

15:14

the key of a key value and the

15:16

response which is essentially the value of the

15:18

key value even though it is a Request

15:21

and response at the URL and a

15:23

response not a request so to say

15:25

but a URL and a response That's

15:28

it. That's really it. I can

15:30

then uh, if if you do cache

15:32

dot put there's no async response

15:34

there anything like that You can just be assured

15:36

that it's in there which is neat It

15:39

works really well One thing that

15:41

I had a little bit of trouble trying

15:43

to do that. I would like to try

15:45

to do again Wes was yeah streaming this

15:48

so that way I could get like a progress of how

15:51

Like where I'm at in the downloading

15:53

Oh, yeah process because you can do

15:55

that and I had it working

15:57

to a degree, but I was still kind

15:59

of new to work I was doing. So I'd like to

16:01

try to get now that I have like a fully working

16:04

implementation. I like paired it back

16:06

a bit. You know when you like work on something really

16:09

foreign to you that you haven't done before? You try to do

16:11

a lot of stuff and you're like, let me pull this back

16:13

a little bit to the bare bones so I can get it

16:15

working. So that's where I'm at right now. Okay,

16:18

so this is the whole

16:20

bit for saving it in the cash. Once you do

16:22

this, whatever you're trying to save into the cash you

16:24

open, you put it in the cash. How

16:27

do you get something from the cash manually

16:29

instead of like having it be the browser's

16:31

request for that thing? Well, I'll show you

16:33

that now. It's within the player

16:36

state here. So we wanted to

16:38

have this work very transparently where

16:42

the user is not going to necessarily know if

16:44

they're playing from local or not. So I wanted

16:46

it to be a part of the normal play

16:49

flow. And the normal play flow again, as you

16:51

click play, it loads up the data, it loads

16:53

up the mp3, it saves it all to a

16:55

svelte writable, and then it opens up the player.

16:57

We have a big old state object here. This

16:59

might be the largest state object I've ever written

17:01

in svelte. So how

17:03

do we load it from cash? The first

17:06

thing we do is we open our cash

17:08

of the same name. So mp3 cash returns

17:10

a promise, you await that, then you have

17:12

access to your actual cash. From there, all

17:15

you have to do is a datmatch with the

17:17

string of the path, and it will give you

17:19

a response. That's a normal response. With

17:22

that normal response, what

17:24

I did is I first got the

17:26

metadata headers, I parsed it as JSON, and

17:28

then I essentially returned it as part of

17:31

the data. And then I

17:33

replaced the URL of the data

17:35

that the player is typically looking for

17:37

with a URL created from the blob.

17:39

You can do that with URL create

17:42

object URL pass in the blob, that

17:44

gives you a blob URL. Guess

17:47

what? An audio player, you

17:49

might not know this, you might. An audio player does

17:51

not care if it's a .mp3

17:53

URL or a blob URL, it will

17:55

play the audio as long as it's

17:57

valid. So that's pretty much it. That's

18:00

the whole process. So when you click play it

18:02

really quickly checks to make sure that something is

18:05

in cash If it's not in cash gets out

18:07

and plays a normal one if it's in cash

18:10

Loads it up Makes it into

18:12

a blob URL Plays it

18:14

in the audio player. That's awesome

18:16

I was just looking up your streaming

18:19

thing that you were asking about

18:21

and I remembered that we did a show on

18:23

on streaming and When

18:27

you want to both use a stream for

18:29

something like save it to the cash and

18:32

View the progress you can't do two of those

18:34

things at once, right? You're either you're they're saving

18:36

it or you're viewing the the actual progress if

18:39

you do want to see both of them You

18:41

have to use the dot T method and

18:43

that will basically T

18:46

split it split the stream and one of

18:48

them you can create a reader that will

18:50

watch the progress and then the other One

18:52

you can throw you could

18:54

probably just pass directly into the

18:57

cache API Although adding

19:00

that metadata it might get a little bit

19:02

angry that you're trying to modify the headers

19:05

Yeah, before you put it in that's probably the issue you

19:08

had The metadata piece was interesting

19:10

because I did think like all right. Here's another

19:12

way I could do the metadata. I could toss

19:14

it all in local

19:16

storage and Just with like

19:19

a key of the same key as the cache

19:21

and then when I'm loading up the URL I

19:23

just love that that's very valid. I

19:25

think I could have done that as well I think

19:27

this for me was just like alright, I'll put it

19:30

all in one spot No, BZ, so maybe alternate methods

19:32

there you could do but as you can see I

19:34

can store a couple of these boom It loads pretty

19:36

quick. I got faster in it and every time you

19:38

save one here another one pops in Oh,

19:42

I won. What's that issue? You just got

19:44

I think yeah, what related failed the touch

19:46

mp3 Okay,

19:49

something might be wrong with that mp3 itself. Oh

19:53

I'm on a local build of the site here,

19:55

so I'm not guaranteed. Oh,

19:57

wow another one failed to construct

19:59

response contains an

20:02

ISO. It contains non-ISO code point. Whoa.

20:06

Alright, I got some googling to do.

20:08

Like I said, this is still in my development branch. But

20:10

for generally, it's working. At least the

20:12

first two, it works. So

20:14

I got some googling to do about whatever this

20:17

ISO code point is. I'm

20:19

wondering if it has something to do with the file name. I

20:21

don't know. Let's try this one. This

20:23

is a pretty generic file. Yeah,

20:25

this one's working. There we go. It's

20:28

probably something in the show notes

20:31

that is not

20:33

a... Stringify incorrectly. Okay.

20:36

Yeah. You're doing JSON.stringify of the

20:38

show and there's probably something in

20:40

there. And if you're trying to

20:42

set that to a header, you're

20:44

trying to stick the entire show

20:46

into a header as storage, there's probably

20:48

a weird character in there that it's

20:50

not okay with. Well, here's what I

20:53

should do then, Wes. I should remove

20:55

the show notes because we don't need

20:57

the show notes for the player. We

21:01

really just need things like the show title

21:03

and some metadata there. We don't

21:05

need the show notes saved in there. So I got

21:07

some work to do, so to say. Yeah,

21:10

but even then, if somebody's

21:12

name has an accented character in

21:14

it, are you going to hit that? So

21:17

I'm trying to look at the

21:19

show notes, what it could

21:21

possibly be. Well, these two, let's

21:23

see, this one has a colon and this one has

21:25

an ampersand. I

21:28

think a lot of them have colons and I don't think

21:30

the colon's the problem. So you're right, I bet it's something

21:32

in the show notes itself. Mm-hmm. You

21:35

can encode it, but then you got all those problems

21:37

as well. Yep. So

21:40

bugs to work out, bugs to work out, but

21:42

for the most part, I got four here saving

21:44

and it's working. You'll be able to very soon

21:46

and I'm going to say by the time you're

21:48

listening to this episode, this interface will be tweaked

21:50

and this will be available for you. But you'll

21:52

be able to store this files locally on your

21:54

computer to play offline or your phone or whatever.

21:56

What about if we had something where you went

21:58

to the shows a filter for

22:01

offline saved. Are you able to

22:03

pull out and loop over

22:05

and show those? Or how does that work?

22:07

Let's check the cache API.

22:10

I would imagine you do keys here. I'm

22:12

not positive. I have not thought about that. But

22:15

keys, yeah, you open and you get the

22:17

keys. Hey, bingo bango, Wes, that's it. Yeah,

22:20

nice. Yeah, so we'll be able to

22:23

do that for sure. Another thing I'm going

22:25

to be working on in the same regard is queuing.

22:28

So if you add an episode to the queue,

22:30

I'm going to have it automatically saved to your

22:32

cache. So that way,

22:35

it's like preloading essentially

22:37

for MP3 files. Pretty neat. Awesome.

22:40

One last thing we want to talk about

22:42

is just persistent storage. I

22:44

was always curious about this as to

22:46

when does it get sort of pushed

22:48

out. When we talked about the browser,

22:51

once it gets full, it starts to sort of

22:53

purge. And I found some interesting stuff

22:55

online about this. I'm just going to read through it.

22:58

Each origin gets a higher

23:00

storage limit. By default, the browser will

23:02

evict data by origin, which is a

23:05

domain name. When

23:07

the total usage of all origins is

23:09

bigger than a certain value, the overall

23:11

quota is calculated based on disk space.

23:14

So again, it says, all right, well,

23:16

now Chrome is taking too much of disk space.

23:19

What do I do about that? However,

23:22

at that point, the browser

23:24

says, all right, what do I

23:27

delete? Do I just start deleting

23:29

random stuff? Because some of it will be, yeah, you cache

23:31

a CSS file. It's

23:34

fine. We'll just go download that again. And some of

23:36

it will be more important stuff.

23:38

Like, oh, yeah, I

23:41

saved a recording that hasn't uploaded to the

23:43

cloud yet. And the only place it exists

23:45

is in the browser cache right

23:48

now. So that's pretty important, right? So

23:50

there is an API called navigator.storage.

23:52

It is the API that will allow

23:55

you to see how much

23:57

space is available for you to store stuff.

24:00

navigator.storage.persist is

24:03

the API that will... it used

24:06

to pop up a thing and says, hey, can

24:08

we store stuff in Chrome? And now

24:11

it's just based on flags,

24:13

like how often you visited the website,

24:16

if you've bookmarked it, there's all these

24:18

things. Kind of the same idea of

24:20

when you want to autoplay video. You're

24:23

not allowed to autoplay video unless the

24:25

user has interacted with the website a whole bunch... there's

24:27

a whole bunch of stuff

24:30

that goes into calculating the score

24:33

of a website. So I

24:35

had... now you can just

24:38

say navigator.storage.persist and it's kind

24:40

of like a pretty please, can

24:43

we have elevated storage?

24:45

Like, don't delete us

24:47

first, please. It doesn't pop anything open

24:50

and it simply was returned true or

24:52

false. So I ran it on Chrome

24:54

on Riverside and it returned true. Why?

24:57

Because I'm here often, I spend a lot

24:59

of time on this website, I interact with

25:01

the website, I bookmarked it, and

25:03

then I tried it on a website I've never been

25:05

to and it obviously says no automatically.

25:07

So I don't know what those flags

25:10

are by browser. I think it's up

25:12

to the browser to decide what

25:15

is important and what is not. But

25:17

I thought that was kind of interesting. If

25:20

that feels mysterious, let me tell you, as

25:22

somebody who's had to maintain an

25:24

autoplay feature on a

25:27

website, man, that

25:29

is one annoying system

25:32

to work into because you'll think

25:34

that you have it working, it works for you,

25:36

it works for most people and then you'll get

25:38

a bit of air. Autoplay does not do anything.

25:40

I'm like, okay, great. How am I supposed

25:42

to debug this when it's

25:44

not like it's throwing an air or anything?

25:46

It could just be that they

25:49

have not interacted with the site enough.

25:51

The one thing is that the user has

25:53

to interact with the site before autoplay

25:56

works. I wonder, I wonder

25:59

how much Google, I'm

26:01

not trying to do any conspiracy thinking

26:03

here, but YouTube has no problems with

26:05

autoplay. Is that

26:08

because YouTube and Chrome are owned by the same

26:10

company? I have no idea. No, you can look

26:12

it up. It's called MediaScore. Let me just find

26:14

it. How do you look it up? All right.

26:16

So I'm in Chrome/or

26:19

colon slash slash media

26:21

dash engagement. And

26:23

this will actually give you

26:25

the information about

26:27

how much your user has interacted with it

26:29

and it will give you whether

26:31

it is a high media engagement score

26:34

or not. And if

26:36

you have a high media engagement score,

26:38

that is one of the ways that

26:40

you are allowed to autoplay videos. So

26:42

look at this YouTube 16 sessions, six

26:45

of them. I actually played something

26:47

last time I played something was

26:50

January 1st because I don't use Chrome

26:53

for anything other than recording this podcast.

26:56

But it is a high media engagement score. And

26:59

then all of these other websites

27:02

here are just like

27:05

domains or origins that I

27:07

have interacted with. And

27:09

it has a low media engagement score. I'm kind

27:11

of curious if I look

27:14

it up. I switched to Microsoft Edge. This

27:19

still kind of makes me

27:21

annoyed. How am I going

27:24

to debug somebody else's? Like

27:26

somebody, a user says, I have

27:29

my autoplay doesn't work. You

27:32

can catch the error. So a

27:35

play method has switched to a promise.

27:38

So what you can do is you say await

27:41

video.play or audio.play.

27:44

And if you're not allowed to play, you catch

27:46

it. So just put a dot catch on the

27:48

end and then you can say,

27:50

oh, it's not done. The real trick

27:52

though is just listen for

27:55

any click at all on the

27:57

website and play something at that point. And then

27:59

you're in. I hate

28:01

that I hate all of this because like somebody

28:03

comes to me and they say hey I

28:06

click the toggle that says auto play your

28:08

videos don't autoplay the sites broken like I gotta

28:10

send an email or I gotta send a

28:12

response or You

28:14

know catch that or whatever at the moment

28:16

and say oh you haven't engaged enough with

28:19

the site for auto Polito work even though

28:21

you clicked the toggle that said please let

28:23

me autoplay like there has to be a

28:25

better permissions model than Yeah,

28:28

you know what give me give me just

28:30

a straight-up permission slide But

28:32

once you click the button that turns

28:34

on autoplay, there's your click. Yeah,

28:37

but what if I'm afraid Refresh the

28:39

page what if they refresh the topic? Doesn't

28:43

then then they have well,

28:45

no it's a good point. I Tested

28:49

it when I was doing my

28:51

autoplay and it was very easy to get

28:53

a High enough

28:55

media engagement score. I think

28:58

I think the user had to watch a

29:02

Couple minutes But

29:04

even with like a high enough engagement

29:06

store score upon loading a page

29:09

the browser still doesn't like it to immediately

29:12

start playing media when a

29:15

Page has been opened without some sort of click

29:17

or some sort of anything No,

29:20

you can do it if your media engagement score. No,

29:22

I know but it doesn't like it I'm

29:25

telling you doesn't like it the browser the

29:27

browser gets angry. It says no. Thank you.

29:29

Yeah No,

29:31

you're no you're wrong about that. Your

29:34

media engagement score is higher and I'm reading

29:36

it right now Of

29:38

media must be greater than seven

29:40

seconds So as long as

29:42

you can play something for seven seconds

29:44

that is an unmuted state You

29:48

can you could do that and I

29:50

bet you could get around that by playing a permission

29:52

flag. Just give nothing Yes, give me a yeah

29:55

Yes, true. Are you are you going

29:57

to allow this? Honestly, there's most websites

30:00

I don't want autoplay on unless

30:02

it is actually a video website

30:04

like Like

30:06

YouTube or a court my course platform and

30:09

guess what? I'm a big boy if that pops up

30:11

and says would you like the site to autoplay video?

30:13

I click no and feel good about that

30:17

Yeah, the browser making choices for me about

30:19

which sites I can autoplay videos. It's true

30:21

I think also people hate that though because

30:24

Another pop with permissions like you see this on

30:26

iOS all the time They pop a permission up

30:28

and they try to do like a fake permission

30:31

because if you're gonna click no They

30:33

don't want to show you the real one because then

30:36

you got to tell the user how to go into

30:38

your settings and and Turn it off. Like once they

30:40

hit no you're it's over. There's no normal people are

30:42

not turning that setting back on Yep,

30:45

man, no fun stuff,

30:47

huh permissions is a hard thing. Yeah. All right.

30:49

I think that's good enough for today Hopefully

30:52

you enjoyed that we will catch you later

30:55

Please peace You

Rate

Join Podchaser to...

  • Rate podcasts and episodes
  • Follow podcasts and creators
  • Create podcast and episode lists
  • & much more

Episode Tags

Do you host or manage this podcast?
Claim and edit this page to your liking.
,

Unlock more with Podchaser Pro

  • Audience Insights
  • Contact Information
  • Demographics
  • Charts
  • Sponsor History
  • and More!
Pro Features