jwf-common-python 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. jwf_common_python/__init__.py +14 -0
  2. jwf_common_python/db_utils/__init__.py +6 -0
  3. jwf_common_python/db_utils/clickhouse.py +124 -0
  4. jwf_common_python/db_utils/elasticsearch.py +196 -0
  5. jwf_common_python/db_utils/mysql.py +64 -0
  6. jwf_common_python/eudic/__init__.py +5 -0
  7. jwf_common_python/eudic/wordbook.py +211 -0
  8. jwf_common_python/file_storage/__init__.py +2 -0
  9. jwf_common_python/file_storage/file_interface.py +29 -0
  10. jwf_common_python/file_storage/local.py +50 -0
  11. jwf_common_python/file_storage/tencent_cos.py +65 -0
  12. jwf_common_python/geography/__init__.py +8 -0
  13. jwf_common_python/geography/district_amap.py +181 -0
  14. jwf_common_python/geography/search_amap.py +84 -0
  15. jwf_common_python/github/__init__.py +5 -0
  16. jwf_common_python/github/webhooks.py +87 -0
  17. jwf_common_python/language_utils/__init__.py +34 -0
  18. jwf_common_python/language_utils/core.py +203 -0
  19. jwf_common_python/language_utils/files.py +52 -0
  20. jwf_common_python/language_utils/web.py +117 -0
  21. jwf_common_python/llm/__init__.py +1 -0
  22. jwf_common_python/llm/aliyun_qwen.py +10 -0
  23. jwf_common_python/llm/azure_gpt.py +66 -0
  24. jwf_common_python/llm/baidu_ernie.py +112 -0
  25. jwf_common_python/message_queue/__init__.py +7 -0
  26. jwf_common_python/message_queue/interface.py +49 -0
  27. jwf_common_python/message_queue/kafka.py +145 -0
  28. jwf_common_python/message_queue/rabbitmq.py +113 -0
  29. jwf_common_python/oauth2/__init__.py +0 -0
  30. jwf_common_python/oauth2/google.py +158 -0
  31. jwf_common_python/parse_subtitle/__init__.py +6 -0
  32. jwf_common_python/parse_subtitle/aa.vtt +2364 -0
  33. jwf_common_python/parse_subtitle/parse_srt_file.py +60 -0
  34. jwf_common_python/pdf/__init__.py +0 -0
  35. jwf_common_python/pdf/aaa.py +38 -0
  36. jwf_common_python/pdf/local_parse.py +259 -0
  37. jwf_common_python/sms/__init__.py +1 -0
  38. jwf_common_python/sms/interface.py +7 -0
  39. jwf_common_python/sms/tencent_sms.py +117 -0
  40. jwf_common_python/translate/__init__.py +152 -0
  41. jwf_common_python/translate/_youdao.py +234 -0
  42. jwf_common_python/translate/microsoft.py +696 -0
  43. jwf_common_python/translate/tencent.py +194 -0
  44. jwf_common_python/tts/__init__.py +0 -0
  45. jwf_common_python/tts/microsoft.py +87 -0
  46. jwf_common_python/utils/__init__.py +0 -0
  47. jwf_common_python/utils/image_utils.py +18 -0
  48. jwf_common_python/utils/tencent_utils.py +51 -0
  49. jwf_common_python/utils/utils.py +46 -0
  50. jwf_common_python/video/__init__.py +5 -0
  51. jwf_common_python/video/merge.py +276 -0
  52. jwf_common_python/weather/__init__.py +0 -0
  53. jwf_common_python/weather/amap.py +127 -0
  54. jwf_common_python/weather/wanwei.py +58 -0
  55. jwf_common_python/youdao/__init__.py +13 -0
  56. jwf_common_python/youdao/wordbook.py +88 -0
  57. jwf_common_python-1.0.0.dist-info/METADATA +669 -0
  58. jwf_common_python-1.0.0.dist-info/RECORD +60 -0
  59. jwf_common_python-1.0.0.dist-info/WHEEL +4 -0
  60. jwf_common_python-1.0.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,2364 @@
1
+ WEBVTT
2
+ Kind: captions
3
+ Language: en
4
+
5
+ 00:00:00.160 --> 00:00:03.360
6
+ If you want to create your own Chrome 
7
+ extension, you're in the right place.  
8
+
9
+ 00:00:03.920 --> 00:00:08.640
10
+ In this course, Raman will teach you how 
11
+ to create a Chrome extension using the new  
12
+
13
+ 00:00:08.640 --> 00:00:15.920
14
+ iteration of the web extensions platform, which is 
15
+ called Manifest v3. Rahman is a great instructor.  
16
+
17
+ 00:00:16.640 --> 00:00:23.120
18
+ And he works for pieces that app pieces that app 
19
+ provided a grant that made this course possible,  
20
+
21
+ 00:00:23.120 --> 00:00:27.680
22
+ but you don't have to use their extension to 
23
+ follow along share in the comments what type  
24
+
25
+ 00:00:27.680 --> 00:00:32.240
26
+ of Chrome extension you want to make. Now the 
27
+ reason I want to teach about this particular  
28
+
29
+ 00:00:32.240 --> 00:00:38.320
30
+ topic is I've created two web extensions in my 
31
+ career. The first is for a previous company,  
32
+
33
+ 00:00:38.320 --> 00:00:43.760
34
+ where my extension generated a significant amount 
35
+ of revenue for the company. And the second for my  
36
+
37
+ 00:00:43.760 --> 00:00:49.120
38
+ current company pieces, where our web extensions 
39
+ play a critical part of our product stack,  
40
+
41
+ 00:00:49.120 --> 00:00:52.560
42
+ and help developers across the 
43
+ globe boost their productivity.  
44
+
45
+ 00:00:53.520 --> 00:00:58.320
46
+ I'm going to be using the pieces web extensions 
47
+ and integrations quite a bit in this video. So if  
48
+
49
+ 00:00:58.320 --> 00:01:03.520
50
+ you're interested in downloading an AI coding 
51
+ assistant that helps you save and reuse code  
52
+
53
+ 00:01:03.520 --> 00:01:10.560
54
+ snippets, convert screenshots to code, and more, 
55
+ go ahead and download pieces in the description.  
56
+
57
+ 00:01:10.560 --> 00:01:14.880
58
+ And you can totally follow along. So during 
59
+ my journey as a Chrome extension developer,  
60
+
61
+ 00:01:14.880 --> 00:01:20.640
62
+ I did often notice that tutorials and 
63
+ StackOverflow answers were using outdated versions  
64
+
65
+ 00:01:20.640 --> 00:01:26.000
66
+ of the web extensions platform. My hope for you 
67
+ after you leave this video is that you have a  
68
+
69
+ 00:01:26.000 --> 00:01:30.240
70
+ resource to create a modern Chrome extension, 
71
+ and you understand the difference between  
72
+
73
+ 00:01:30.800 --> 00:01:36.480
74
+ the newer version of the web extensions 
75
+ platform manifest v3, and older versions. Now,  
76
+
77
+ 00:01:36.480 --> 00:01:39.840
78
+ before we get started, there's going to 
79
+ be three prerequisites to this course,  
80
+
81
+ 00:01:40.640 --> 00:01:44.960
82
+ the first is required, and it's that you have 
83
+ a basic understanding of JavaScript and DOM  
84
+
85
+ 00:01:44.960 --> 00:01:50.160
86
+ manipulation. The second is optional. If you 
87
+ want to follow along with this video and code  
88
+
89
+ 00:01:50.160 --> 00:01:55.440
90
+ alongside with me, you can go to the description 
91
+ below, I'm gonna have a link to my GitHub repo,  
92
+
93
+ 00:01:55.440 --> 00:02:00.960
94
+ go ahead and get cloned that and you'll be able 
95
+ to follow along. The third is also optional.  
96
+
97
+ 00:02:00.960 --> 00:02:06.880
98
+ If you totally want to follow along, you can go 
99
+ ahead to pieces dot app and install a pieces IDE  
100
+
101
+ 00:02:06.880 --> 00:02:12.240
102
+ integration along with the pieces Web Extension, 
103
+ and you'll be able to use pieces exactly the way I  
104
+
105
+ 00:02:12.240 --> 00:02:17.680
106
+ do in this video. With that, let's get started. So 
107
+ as I mentioned before, the extension we're going  
108
+
109
+ 00:02:17.680 --> 00:02:22.960
110
+ to create as a YouTube bookmarker. Basically, 
111
+ anytime you navigate to a YouTube video page,  
112
+
113
+ 00:02:22.960 --> 00:02:28.000
114
+ an icon will show up on your YouTube video player 
115
+ to allow you to bookmark a particular timestamp on  
116
+
117
+ 00:02:28.000 --> 00:02:33.280
118
+ any video. So let me show you how that's gonna 
119
+ work. If you're on a YouTube video page, you're  
120
+
121
+ 00:02:33.280 --> 00:02:39.760
122
+ gonna see this item at the bottom right, you can 
123
+ go ahead and click that. And if you navigate to  
124
+
125
+ 00:02:39.760 --> 00:02:43.920
126
+ your chrome extension icon at the top, right, 
127
+ I've pinned, so it's showing in the toolbar,  
128
+
129
+ 00:02:45.680 --> 00:02:51.520
130
+ you're going to see a new timestamp already had 
131
+ one timestamp for 15 minutes, I added one with  
132
+
133
+ 00:02:51.520 --> 00:02:58.240
134
+ an hour 18. I can go ahead and delete this one 
135
+ because I just decided I don't want it. And our  
136
+
137
+ 00:02:58.240 --> 00:03:04.400
138
+ extension is going to give us that ability to do 
139
+ that. Now if I want to go back to my 15 minute  
140
+
141
+ 00:03:04.400 --> 00:03:10.960
142
+ timestamp, you can click the play button. And it 
143
+ goes directly back to that particular timestamp.  
144
+
145
+ 00:03:12.160 --> 00:03:16.240
146
+ I can also delete this one too. And 
147
+ when there's no bookmarks to show,  
148
+
149
+ 00:03:16.240 --> 00:03:17.840
150
+ it's going to say there's no bookmarks to show.  
151
+
152
+ 00:03:19.520 --> 00:03:24.640
153
+ Now we're going to add one, just so we have one on 
154
+ this video, and I can show you how storage works.  
155
+
156
+ 00:03:24.640 --> 00:03:30.480
157
+ I'm going to navigate to a new video. And in 
158
+ this video, we have no bookmarks. So it says  
159
+
160
+ 00:03:30.480 --> 00:03:35.360
161
+ there's no bookmarks to show. But if we go back 
162
+ to our previous video where we saved a bookmark,  
163
+
164
+ 00:03:36.320 --> 00:03:41.840
165
+ it's going to load that previous bookmark. 
166
+ Now the last thing is if you navigate to a  
167
+
168
+ 00:03:41.840 --> 00:03:47.920
169
+ non YouTube video page, it's going to say this 
170
+ is not a YouTube video page in the extension UI.  
171
+
172
+ 00:03:49.120 --> 00:03:54.000
173
+ And that's basically all the capabilities of this 
174
+ chrome extension we're going to build out here,  
175
+
176
+ 00:03:54.000 --> 00:03:57.120
177
+ there's going to be a lot more 
178
+ you can do on your own afterwards.  
179
+
180
+ 00:03:57.120 --> 00:04:01.600
181
+ Now I also want to mention the reason we're 
182
+ working on creating this extension in particular,  
183
+
184
+ 00:04:01.600 --> 00:04:05.360
185
+ is because it's going to show you all the 
186
+ major parts of creating a Chrome extension,  
187
+
188
+ 00:04:05.360 --> 00:04:09.280
189
+ it's going to show you how to work with 
190
+ a content script to manipulate the DOM.  
191
+
192
+ 00:04:09.280 --> 00:04:13.760
193
+ It's going to show you how to create a UI for your 
194
+ extension. And it's going to show you how to use  
195
+
196
+ 00:04:13.760 --> 00:04:19.760
197
+ service workers as background scripts, which 
198
+ is a major part of the ship from manifest v2  
199
+
200
+ 00:04:19.760 --> 00:04:26.320
201
+ to manifest v3. And to start working on 
202
+ the extension. Once you get cloned my repo,  
203
+
204
+ 00:04:26.320 --> 00:04:32.080
205
+ you can go ahead and click on the puzzle piece in 
206
+ your Chrome browser at the top right click Manage  
207
+
208
+ 00:04:32.080 --> 00:04:38.640
209
+ extensions. I'm going to go ahead and remove my 
210
+ extension show I can show you how it works. And  
211
+
212
+ 00:04:38.640 --> 00:04:43.920
213
+ you're going to see this developer mode option at 
214
+ the top right go ahead and toggle that so it's on  
215
+
216
+ 00:04:44.800 --> 00:04:52.000
217
+ click Load unpacked, then go to the repo that 
218
+ you get cloned in mind with the boilerplate code.  
219
+
220
+ 00:04:53.600 --> 00:05:00.640
221
+ Go ahead and load that. And we're going to see 
222
+ our extension here. If we Click on this puzzle  
223
+
224
+ 00:05:00.640 --> 00:05:07.200
225
+ piece and pin it. What we're going to see is this 
226
+ basic UI, it's just going to say your bookmarks  
227
+
228
+ 00:05:07.200 --> 00:05:13.280
229
+ for this video with no bookmarks, and it's just 
230
+ going to show up everywhere. This is the default  
231
+
232
+ 00:05:13.280 --> 00:05:18.240
233
+ messaging in the boilerplate code I supplied 
234
+ and the boilerplate code will also contain all  
235
+
236
+ 00:05:18.240 --> 00:05:23.120
237
+ the files you need to follow along. The best 
238
+ place to start with creating our extension  
239
+
240
+ 00:05:23.120 --> 00:05:28.720
241
+ is the manifest dot JSON file. This file is a 
242
+ JSON file where we can specify what version of  
243
+
244
+ 00:05:28.720 --> 00:05:33.840
245
+ the extensions platform we will use, among other 
246
+ information that is going to serve as default for  
247
+
248
+ 00:05:33.840 --> 00:05:39.280
249
+ loading in our extensions. Also, every extension 
250
+ you would want to create whether it's Safari,  
251
+
252
+ 00:05:39.280 --> 00:05:45.040
253
+ Mozilla, or any chromium base extension will need 
254
+ a manifest dot JSON file. And it's probably the  
255
+
256
+ 00:05:45.040 --> 00:05:50.400
257
+ single most important file in your extension, 
258
+ because it simply just won't work without it.  
259
+
260
+ 00:05:51.360 --> 00:05:57.040
261
+ In our boilerplate code already added the manifest 
262
+ dot json file, so we don't have to spend too long  
263
+
264
+ 00:05:57.040 --> 00:06:00.960
265
+ writing it out, I think it would be especially 
266
+ helpful if I just point out some of the things  
267
+
268
+ 00:06:00.960 --> 00:06:07.280
269
+ that you should note, in case you're creating your 
270
+ own extension. So let's take a look here, as you'd  
271
+
272
+ 00:06:07.280 --> 00:06:13.840
273
+ suspect, there's a name, there's a version number 
274
+ and a description. And basically, the version  
275
+
276
+ 00:06:13.840 --> 00:06:18.720
277
+ number is going to populate when you loaded in the 
278
+ extension, the name you see is also going to be  
279
+
280
+ 00:06:18.720 --> 00:06:22.960
281
+ the name of the extension when you load it in. And 
282
+ the description is pretty self explanatory. It's  
283
+
284
+ 00:06:22.960 --> 00:06:28.000
285
+ just a description of what the extension does. Now 
286
+ things get more interesting with the permissions.  
287
+
288
+ 00:06:29.200 --> 00:06:32.880
289
+ The permissions will be different depending 
290
+ on whatever Chrome extension you're building.  
291
+
292
+ 00:06:33.440 --> 00:06:36.640
293
+ For this particular extension, we're 
294
+ going to request two permissions,  
295
+
296
+ 00:06:37.600 --> 00:06:43.440
297
+ which is going to be the permission to use the 
298
+ Chrome dot storage API, and the chrome dot tabs  
299
+
300
+ 00:06:43.440 --> 00:06:49.680
301
+ API. The chrome dot storage API is to store things 
302
+ in the user's browser for the extension. And the  
303
+
304
+ 00:06:49.680 --> 00:06:56.160
305
+ second permission, which is a chrome dot tabs API, 
306
+ is what helps us access our browser's tab system.  
307
+
308
+ 00:06:56.720 --> 00:07:01.680
309
+ So we can read the tab for the extension. This is 
310
+ basically going to help us identify what browser  
311
+
312
+ 00:07:01.680 --> 00:07:07.280
313
+ tab the user is currently using, and grab the URL 
314
+ to see if they are in a YouTube video page for  
315
+
316
+ 00:07:07.280 --> 00:07:12.160
317
+ our extension. Now, the host permissions just give 
318
+ you the ability to send cause requests to certain  
319
+
320
+ 00:07:12.160 --> 00:07:17.440
321
+ host names. Our extension only deals with YouTube 
322
+ pages. So I have a match pattern written here just  
323
+
324
+ 00:07:17.440 --> 00:07:22.720
325
+ for YouTube. The service worker, as I mentioned 
326
+ before, there's a big change between extensions,  
327
+
328
+ 00:07:22.720 --> 00:07:29.680
329
+ v2, and v3. And one of the big changes is the 
330
+ use of a service worker. As you can see here, the  
331
+
332
+ 00:07:29.680 --> 00:07:34.320
333
+ other is the ability to use promises. But let's 
334
+ just focus on service workers. For right now.  
335
+
336
+ 00:07:35.440 --> 00:07:39.920
337
+ Service workers are just a JavaScript file that 
338
+ runs separately from the main browser thread.  
339
+
340
+ 00:07:40.720 --> 00:07:44.880
341
+ This means that your service worker would 
342
+ not have access to content of a webpage,  
343
+
344
+ 00:07:44.880 --> 00:07:49.840
345
+ since it is separate from main processes. 
346
+ However, your service worker does have  
347
+
348
+ 00:07:49.840 --> 00:07:56.240
349
+ capabilities to speak to your extension using the 
350
+ extensions messaging system, which we will see  
351
+
352
+ 00:07:56.240 --> 00:08:01.440
353
+ and use in our bookmarking extension. The next 
354
+ thing I want to point out is the content scripts.  
355
+
356
+ 00:08:02.080 --> 00:08:06.800
357
+ The content scripts are just files that 
358
+ run in context of the webpages we're on.  
359
+
360
+ 00:08:07.600 --> 00:08:12.480
361
+ We're going to use this to manipulate the DOM 
362
+ of our webpage that our extension is looking at.  
363
+
364
+ 00:08:13.120 --> 00:08:18.560
365
+ And here we're just specifying that our 
366
+ content script is represented by our content  
367
+
368
+ 00:08:18.560 --> 00:08:25.200
369
+ script J S file. As you can see, with the J s 
370
+ colon content script dot j s, the last thing I  
371
+
372
+ 00:08:25.200 --> 00:08:33.040
373
+ want to point out is the pop up dot HTML file down 
374
+ here, under default pop up, this just specifies  
375
+
376
+ 00:08:33.040 --> 00:08:38.480
377
+ which file was served as our UI. In our case, 
378
+ we've specified the pop up dot HTML file, and  
379
+
380
+ 00:08:38.480 --> 00:08:43.360
381
+ in that file, we specify that the corresponding 
382
+ file that helps it with its interactivity is a  
383
+
384
+ 00:08:43.360 --> 00:08:48.240
385
+ pop up.js file. With all that out of the way, 
386
+ let's get to coding the actual extension.  
387
+
388
+ 00:08:48.880 --> 00:08:52.640
389
+ We're now finally going to start 
390
+ writing code to make our extension work.  
391
+
392
+ 00:08:53.280 --> 00:08:57.920
393
+ For us even test the extension, we have to add the 
394
+ button of the YouTube player that will allow us to  
395
+
396
+ 00:08:57.920 --> 00:09:03.720
397
+ save bookmarks with timestamps. So in order for 
398
+ us to add a button on the YouTube video player  
399
+
400
+ 00:09:03.720 --> 00:09:08.480
401
+ will have to manipulate the DOM of the web 
402
+ page we are on. What that means is we'll have  
403
+
404
+ 00:09:08.480 --> 00:09:13.760
405
+ to write our logic in our content script file, 
406
+ which operates in the context of the webpage,  
407
+
408
+ 00:09:13.760 --> 00:09:20.240
409
+ as I mentioned before, so let's go ahead and add 
410
+ some code to our content script file. We're going  
411
+
412
+ 00:09:20.240 --> 00:09:31.280
413
+ to go ahead and add the following variables 
414
+ YouTube, left, controls, and YouTube player  
415
+
416
+ 00:09:32.960 --> 00:09:36.880
417
+ one is going to be for accessing the 
418
+ YouTube player one is going to be for  
419
+
420
+ 00:09:36.880 --> 00:09:41.680
421
+ accessing the controls. And this is going 
422
+ to allow us to manipulate each of these.  
423
+
424
+ 00:09:42.640 --> 00:09:49.680
425
+ But before we continue writing the logic to do DOM 
426
+ manipulation in the context strip, we also have to  
427
+
428
+ 00:09:49.680 --> 00:09:54.480
429
+ think about how our extension is even going to 
430
+ know when we've navigated to a new web page.  
431
+
432
+ 00:09:54.480 --> 00:10:00.400
433
+ And we need to know this so the content script 
434
+ knows to execute logic to add the plus i Call to  
435
+
436
+ 00:10:00.400 --> 00:10:05.200
437
+ add bookmarks for our extension. Let's go 
438
+ ahead and go in our background.js file now.  
439
+
440
+ 00:10:06.000 --> 00:10:12.960
441
+ And what we want to do here is listen to any 
442
+ updates in our tab system and find the most  
443
+
444
+ 00:10:12.960 --> 00:10:19.760
445
+ recent tab or the tab that we're on currently 
446
+ and see if it's a YouTube page. So we're going  
447
+
448
+ 00:10:19.760 --> 00:10:24.240
449
+ to have a listener, that's going to 
450
+ listen to tabs. And if you remember,  
451
+
452
+ 00:10:24.240 --> 00:10:31.840
453
+ we got permissions to access the Chrome tabs API. 
454
+ And we're going to listen for an update to tabs.  
455
+
456
+ 00:10:34.880 --> 00:10:38.000
457
+ The parameters were given is a tab ID and a tab.  
458
+
459
+ 00:10:43.600 --> 00:10:49.680
460
+ What we're going to do from here is see if 
461
+ there's a tab URL, and if there is a tab Euro.  
462
+
463
+ 00:10:50.880 --> 00:11:00.640
464
+ Let's see if that Euro includes 
465
+ youtube.com/watch. The way I came up with that  
466
+
467
+ 00:11:02.080 --> 00:11:07.680
468
+ is if you look at our YouTube video, every 
469
+ individual video has YouTube slash watch.  
470
+
471
+ 00:11:08.320 --> 00:11:14.160
472
+ And we just want to make sure we're on a 
473
+ page that has that specifically as a URL,  
474
+
475
+ 00:11:14.160 --> 00:11:20.160
476
+ then what we want to do is set our query 
477
+ parameters. And we're going to use query  
478
+
479
+ 00:11:20.160 --> 00:11:26.400
480
+ parameters as a unique ID for each video. So we 
481
+ can grab it from storage, you'll see what I mean  
482
+
483
+ 00:11:26.400 --> 00:11:32.640
484
+ in a second, and I'll show you. So we're going 
485
+ to do that by using the JavaScript split method.  
486
+
487
+ 00:11:35.600 --> 00:11:42.720
488
+ What that means is basically after this question 
489
+ mark query parameter, we're going to grab  
490
+
491
+ 00:11:42.720 --> 00:11:48.320
492
+ this value. And this is going to be our unique 
493
+ video value this right here after the equal  
494
+
495
+ 00:11:48.320 --> 00:11:55.440
496
+ sign. And every video on YouTube has a different 
497
+ value right here. So it's a pretty unique key that  
498
+
499
+ 00:11:55.440 --> 00:12:03.360
500
+ will help us store videos uniquely as well in our 
501
+ storage, and it's consistent. So then we're going  
502
+
503
+ 00:12:03.360 --> 00:12:13.440
504
+ to add your URL parameters. And this is just an 
505
+ interface to work with URLs URL search params.  
506
+
507
+ 00:12:17.520 --> 00:12:22.720
508
+ And the final thing we want to do is there's 
509
+ a messaging system that happens between  
510
+
511
+ 00:12:22.720 --> 00:12:26.080
512
+ the extension, we're going to send a message  
513
+
514
+ 00:12:26.080 --> 00:12:33.760
515
+ to our content script that basically says a new 
516
+ video is loaded. And this is the video ID of  
517
+
518
+ 00:12:33.760 --> 00:12:40.240
519
+ that video, and the video ID being that unique 
520
+ video value that we saw in the URL on YouTube.  
521
+
522
+ 00:12:46.400 --> 00:12:52.960
523
+ And this tab, Id send message usage that I'm doing 
524
+ right here is all directly from documentation.  
525
+
526
+ 00:12:53.520 --> 00:12:59.760
527
+ The Send Message takes a tab ID, it takes a 
528
+ unique object. So right now I'm going to type  
529
+
530
+ 00:12:59.760 --> 00:13:05.840
531
+ type. And this is a type of event is a new 
532
+ video event. And then a video ID value,  
533
+
534
+ 00:13:07.440 --> 00:13:18.720
535
+ which is going to be URL, parameters, dot get v. 
536
+ So if we're doing URL dot get D, it's going to  
537
+
538
+ 00:13:18.720 --> 00:13:25.120
539
+ grab this right here. And that's basically going 
540
+ to be the code for that send message takes a tab  
541
+
542
+ 00:13:25.120 --> 00:13:30.560
543
+ ID, it takes an object and then it can also take a 
544
+ callback function. This object right here doesn't  
545
+
546
+ 00:13:30.560 --> 00:13:38.000
547
+ have to be type or video ID, it could also be 
548
+ something random, like I could literally pass this  
549
+
550
+ 00:13:38.000 --> 00:13:45.440
551
+ and the content script will have access to 
552
+ random, and then the string random. In our case,  
553
+
554
+ 00:13:45.440 --> 00:13:50.400
555
+ the only thing that's applicable is the 
556
+ type of the event and then the video ID,  
557
+
558
+ 00:13:50.400 --> 00:13:55.520
559
+ which is a content script needs. Now in our 
560
+ content script, we're going to add a listener that  
561
+
562
+ 00:13:56.240 --> 00:14:01.120
563
+ is going to listen to any of those incoming 
564
+ messages, we need to be able to listen to that  
565
+
566
+ 00:14:01.120 --> 00:14:06.480
567
+ background.js message. So to do that, we're 
568
+ going to end up writing the following code  
569
+
570
+ 00:14:07.840 --> 00:14:15.840
571
+ to add that listener, so we're going to say on 
572
+ message add listener. And this is going to accept  
573
+
574
+ 00:14:17.040 --> 00:14:24.160
575
+ three parameters. So an object a sender, 
576
+ and a response. And the response is,  
577
+
578
+ 00:14:24.160 --> 00:14:30.000
579
+ when a message is being sent to the content 
580
+ script, we can also send a response back where  
581
+
582
+ 00:14:30.000 --> 00:14:35.520
583
+ the message is coming from. So I'm going 
584
+ to destructure those values we're getting  
585
+
586
+ 00:14:40.400 --> 00:14:47.040
587
+ and if you remember, the way I'm deconstructing 
588
+ Type value video ID is basically we're given a  
589
+
590
+ 00:14:47.040 --> 00:14:54.800
591
+ video ID right here. Later on, we're going to grab 
592
+ a value as well, and I'm just destructuring. So  
593
+
594
+ 00:14:55.520 --> 00:15:02.400
595
+ each of these are its own variable. 
596
+ So it's a If type is equal to new,  
597
+
598
+ 00:15:02.400 --> 00:15:09.040
599
+ so if the type of event is new video loaded, 
600
+ which we're getting from the background.js file,  
601
+
602
+ 00:15:09.600 --> 00:15:17.440
603
+ we want to be able to set current video, which 
604
+ will be a global variable in the content script  
605
+
606
+ 00:15:18.640 --> 00:15:25.120
607
+ as the video ID, and then we want to 
608
+ call a function to handle any actions  
609
+
610
+ 00:15:25.680 --> 00:15:29.760
611
+ with new video. So we're going to 
612
+ call a new video loaded function.  
613
+
614
+ 00:15:32.240 --> 00:15:41.520
615
+ And let's go ahead and set current video as a 
616
+ top level variable. And that's just going to  
617
+
618
+ 00:15:41.520 --> 00:15:47.760
619
+ be an empty string. But it's going to be set as 
620
+ the string set from the background at js file,  
621
+
622
+ 00:15:48.480 --> 00:15:54.320
623
+ once the message is received on this end, so let's 
624
+ go ahead and actually see if this works at all.  
625
+
626
+ 00:15:55.520 --> 00:16:01.600
627
+ I'm gonna go ahead and just 
628
+ console dot log your parameters.  
629
+
630
+ 00:16:06.960 --> 00:16:16.320
631
+ I'm gonna give this a reload. Open this, let's 
632
+ inspect it. And we ever URL search parameters.  
633
+
634
+ 00:16:16.320 --> 00:16:24.000
635
+ So we know we're getting our URL search parameters 
636
+ now. Great. So so far, things look good.  
637
+
638
+ 00:16:25.600 --> 00:16:31.360
639
+ Now, what we want to do from here is 
640
+ create that new video loaded function.  
641
+
642
+ 00:16:32.080 --> 00:16:35.840
643
+ And after we create this function and 
644
+ all the functionality surrounding it,  
645
+
646
+ 00:16:36.400 --> 00:16:43.280
647
+ we should see the YouTube player button on the 
648
+ YouTube video. So let's go ahead and do that.  
649
+
650
+ 00:16:43.280 --> 00:16:49.840
651
+ So what we're going to do is create this function 
652
+ that we have right here called New Video loaded.  
653
+
654
+ 00:16:55.840 --> 00:17:02.240
655
+ And what we probably want to do is check 
656
+ if a bookmark button already exists,  
657
+
658
+ 00:17:02.240 --> 00:17:06.880
659
+ I know the class name that this item 
660
+ has, it's called Bookmark button  
661
+
662
+ 00:17:06.880 --> 00:17:11.760
663
+ because I wrote the CSS code that's 
664
+ going to style this whole extension.  
665
+
666
+ 00:17:11.760 --> 00:17:21.120
667
+ So you could just copy this part right here. But 
668
+ this is just some native Dom, slash JavaScript  
669
+
670
+ 00:17:23.280 --> 00:17:30.960
671
+ methods that we can use. It's actually MB by 
672
+ class name. And it's going to return an HTML  
673
+
674
+ 00:17:30.960 --> 00:17:36.240
675
+ collection. So what we're going to do is grab 
676
+ the first element that matches this class name,  
677
+
678
+ 00:17:36.240 --> 00:17:41.760
679
+ bookmark button. And it's just going to 
680
+ exist on every single YouTube video page.  
681
+
682
+ 00:17:43.680 --> 00:17:52.400
683
+ So if we want to test that, we could just say 
684
+ console dot log bookmark exists. And let's reload  
685
+
686
+ 00:17:52.400 --> 00:18:02.080
687
+ this page and inspect it. Actually, let's reload 
688
+ our extension as well. reload this page inspect,  
689
+
690
+ 00:18:03.520 --> 00:18:09.440
691
+ we're probably going to get undefined 
692
+ this is exactly what I expected.  
693
+
694
+ 00:18:10.240 --> 00:18:15.280
695
+ Because we don't have any logic surrounding the 
696
+ Bookmark button yet. And also, we're not even  
697
+
698
+ 00:18:15.280 --> 00:18:21.760
699
+ setting a bookmark button right now. So if the 
700
+ Bookmark button did exist, we would get true,  
701
+
702
+ 00:18:21.760 --> 00:18:26.640
703
+ it does exist, but we're getting undefined right 
704
+ now. So what we want to do if we're getting  
705
+
706
+ 00:18:26.640 --> 00:18:36.080
707
+ that undefined or false value that a bookmark 
708
+ button does not exist, is add some logic to say,  
709
+
710
+ 00:18:36.080 --> 00:18:43.440
711
+ hey, let's add this bookmark button to any YouTube 
712
+ player. So we're going to create an image element.  
713
+
714
+ 00:18:45.120 --> 00:18:55.840
715
+ That is going to be the image we 
716
+ click on for bookmark buttons.  
717
+
718
+ 00:19:00.000 --> 00:19:03.360
719
+ As part is in, we're going to 
720
+ add a couple of attributes.  
721
+
722
+ 00:19:07.840 --> 00:19:12.960
723
+ The first thing we're going to want to do 
724
+ is pull the image that we're using, which is  
725
+
726
+ 00:19:15.120 --> 00:19:20.560
727
+ our assets slash bookmark. PNG, you already 
728
+ have this if you're following along with the  
729
+
730
+ 00:19:20.560 --> 00:19:30.400
731
+ boilerplate code. The second thing we want to do 
732
+ is add a class. And the way we're going to add  
733
+
734
+ 00:19:30.400 --> 00:19:37.840
735
+ this class is basically make it pretty dynamic 
736
+ here. So we're gonna add a YouTube button class  
737
+
738
+ 00:19:41.120 --> 00:19:52.320
739
+ with a space and then we're going to add a 
740
+ bookmark button class in quotes. And this  
741
+
742
+ 00:19:52.320 --> 00:19:56.800
743
+ is again, just some styling I have that 
744
+ you don't need to worry about right now.  
745
+
746
+ 00:19:57.680 --> 00:20:02.480
747
+ And the last thing we want to do is basically 
748
+ on hover, we want to make a title show.  
749
+
750
+ 00:20:03.840 --> 00:20:06.800
751
+ So we're just gonna say the 
752
+ title is click to bookmark,  
753
+
754
+ 00:20:07.520 --> 00:20:11.840
755
+ current timestamp. And this is just 
756
+ a UI thing. You'll see this in a bit.  
757
+
758
+ 00:20:14.320 --> 00:20:21.440
759
+ Next, what we want to show is a way to 
760
+ grab the YouTube controls. So these are  
761
+
762
+ 00:20:21.440 --> 00:20:26.800
763
+ the YouTube controls over here, we want 
764
+ to be able to grab these left controls,  
765
+
766
+ 00:20:26.800 --> 00:20:33.840
767
+ so we can add a bookmark button right here. 
768
+ So let's go ahead and find out how to do that.  
769
+
770
+ 00:20:35.440 --> 00:20:41.200
771
+ I already know how to grab this. So I'm going 
772
+ to show you how this works. You can inspect  
773
+
774
+ 00:20:41.200 --> 00:20:47.120
775
+ elements right here and find what elements they 
776
+ exactly are. But basically, we're going to use  
777
+
778
+ 00:20:47.120 --> 00:20:52.160
779
+ native JavaScript methods like we have done 
780
+ previously to grab those controls and insert  
781
+
782
+ 00:20:52.160 --> 00:21:04.320
783
+ our button. If I do document dot get elements 
784
+ by class name. And I grab YouTube left controls,  
785
+
786
+ 00:21:07.040 --> 00:21:13.040
787
+ we should get an element back, which is 
788
+ going to be this div class over here.  
789
+
790
+ 00:21:14.320 --> 00:21:19.680
791
+ And you can see that it gives us all the left 
792
+ controls over here, where we're going to add  
793
+
794
+ 00:21:19.680 --> 00:21:25.040
795
+ our button. And the second thing we're going to 
796
+ want to do is grab the YouTube player as well.  
797
+
798
+ 00:21:25.040 --> 00:21:31.280
799
+ And that's one of the global variables we set 
800
+ in our content script. And we can also do that  
801
+
802
+ 00:21:33.360 --> 00:21:44.960
803
+ by writing document dot get elements by class 
804
+ name. And then there's this video stream class.  
805
+
806
+ 00:21:46.800 --> 00:21:55.360
807
+ And we're going to grab the one at the zero with 
808
+ index. And it grabs a whole YouTube component  
809
+
810
+ 00:21:55.360 --> 00:22:02.000
811
+ right there. So now we know the two elements in 
812
+ the DOM we need to manipulate. But let's set those  
813
+
814
+ 00:22:02.000 --> 00:22:10.040
815
+ elements. First, we're going to do exactly what 
816
+ we saw in our content over there. Document get,  
817
+
818
+ 00:22:10.640 --> 00:22:15.760
819
+ actually, I'm just gonna go back and copy 
820
+ these way easier, so don't make a mistake.  
821
+
822
+ 00:22:20.640 --> 00:22:25.840
823
+ And then the second one is going to be 
824
+ YouTube player. Go back and copy that.  
825
+
826
+ 00:22:32.320 --> 00:22:38.320
827
+ Okay, so after this, what we're going to 
828
+ want to do is add that bookmark button and  
829
+
830
+ 00:22:38.320 --> 00:22:44.240
831
+ we grabbed the controls, you saw that row in 
832
+ the player, we want to add it to that row. So  
833
+
834
+ 00:22:44.240 --> 00:22:49.600
835
+ we're going to type out YouTube left controls to 
836
+ get those left controls we stored in a variable.  
837
+
838
+ 00:22:50.320 --> 00:22:57.200
839
+ And to use this native JavaScript method we can 
840
+ use called append child, which is going to append  
841
+
842
+ 00:22:58.640 --> 00:23:01.120
843
+ this bookmark element inside that row.  
844
+
845
+ 00:23:03.680 --> 00:23:08.000
846
+ And then the second thing we're going to want 
847
+ to do is probably add a listener to listen to  
848
+
849
+ 00:23:08.000 --> 00:23:14.000
850
+ any clicks on our icon. So there's a correction I 
851
+ want to make to this portion of the video, before  
852
+
853
+ 00:23:14.000 --> 00:23:19.760
854
+ we continue, it's going to be very important in 
855
+ order for your extension to work functionally.  
856
+
857
+ 00:23:20.720 --> 00:23:26.000
858
+ And it's only one line of code, but it's going 
859
+ to make such a big difference. I'm also going to  
860
+
861
+ 00:23:26.000 --> 00:23:30.960
862
+ explain an important concept of Chrome extensions 
863
+ that I neglected while I was writing this,  
864
+
865
+ 00:23:31.520 --> 00:23:38.000
866
+ which is that in our manifest json file, we 
867
+ have a match pattern for our content script.  
868
+
869
+ 00:23:38.000 --> 00:23:44.320
870
+ And basically the match pattern, we currently 
871
+ have checks if any youtube.com video is loaded.  
872
+
873
+ 00:23:44.320 --> 00:23:49.840
874
+ And if it is, we're injecting our content script 
875
+ into the context of that web page. So basically,  
876
+
877
+ 00:23:49.840 --> 00:23:55.840
878
+ what that means is, anytime a youtube.com 
879
+ page shows up, we're running a bunch of logic  
880
+
881
+ 00:23:56.400 --> 00:24:04.000
882
+ using our content script. But the problem right 
883
+ now is that our background.js file is telling  
884
+
885
+ 00:24:04.000 --> 00:24:09.440
886
+ us when a new video is loaded. And the 
887
+ event listener we're using is on updated,  
888
+
889
+ 00:24:09.440 --> 00:24:15.520
890
+ which is just checking if this URL is updated. If 
891
+ you refresh this page, the URL is not updated. So  
892
+
893
+ 00:24:15.520 --> 00:24:21.760
894
+ this button actually isn't going to show up. And 
895
+ if you continue coding without this fix right  
896
+
897
+ 00:24:21.760 --> 00:24:27.840
898
+ here, you're gonna see some edge cases that you 
899
+ might not like. So let's go ahead and fix this,  
900
+
901
+ 00:24:27.840 --> 00:24:34.320
902
+ we're going to do a super simple fix. It's not the 
903
+ best fix in the world, but it will fix the problem  
904
+
905
+ 00:24:34.320 --> 00:24:41.360
906
+ here. We're just going to call a new video loaded 
907
+ anytime our content script matches youtube.com.  
908
+
909
+ 00:24:42.080 --> 00:24:47.280
910
+ And what this is going to do is call this 
911
+ new video loaded function anytime we hit  
912
+
913
+ 00:24:47.280 --> 00:24:55.520
914
+ that match pattern. The downside of this is now 
915
+ if the background script sees it as a new video  
916
+
917
+ 00:24:55.520 --> 00:25:01.520
918
+ using the on updated event listener, and there's 
919
+ a condition that content script is injected,  
920
+
921
+ 00:25:01.520 --> 00:25:06.480
922
+ we're going to hit this or call this new video 
923
+ loaded function twice, you can fix this pretty  
924
+
925
+ 00:25:06.480 --> 00:25:10.800
926
+ easily by just adding a conditional make sure 
927
+ that doesn't happen. But to make sure everyone  
928
+
929
+ 00:25:10.800 --> 00:25:14.960
930
+ is able to follow along with this correction, 
931
+ I will not be doing that here. And we'll just  
932
+
933
+ 00:25:14.960 --> 00:25:19.600
934
+ only be inserting this one line of code calling 
935
+ the new video loaded function. Luckily, the only  
936
+
937
+ 00:25:19.600 --> 00:25:24.640
938
+ thing our new video loaded function is doing is 
939
+ adding the Bookmark button to the YouTube player.  
940
+
941
+ 00:25:24.640 --> 00:25:29.200
942
+ So there's going to be no negative implications to 
943
+ calling it twice. Since we have a condition that  
944
+
945
+ 00:25:29.200 --> 00:25:33.040
946
+ checks if the button is already on the player. 
947
+ It's just not the most efficient implementation,  
948
+
949
+ 00:25:33.040 --> 00:25:42.160
950
+ which is fine for the sake of this tutorial. With 
951
+ that, let's continue with the rest of the video.  
952
+
953
+ 00:25:42.160 --> 00:25:47.520
954
+ There we go, we have the button right there. 
955
+ But right now, if we click the button,  
956
+
957
+ 00:25:49.040 --> 00:25:55.680
958
+ it's not doing anything. And there's a reason for 
959
+ that. The reason is that we don't have any event  
960
+
961
+ 00:25:55.680 --> 00:26:02.640
962
+ listener listening to click on this particular 
963
+ byte. Let's go ahead and add the code for that.  
964
+
965
+ 00:26:05.200 --> 00:26:10.080
966
+ So what we're going to do is add an event 
967
+ listener to listen to a click for the button.  
968
+
969
+ 00:26:11.440 --> 00:26:16.560
970
+ And we're literally going to use the add 
971
+ event listener method, listen for a click,  
972
+
973
+ 00:26:17.360 --> 00:26:26.400
974
+ and then call a function called add new bookmark 
975
+ event handler. And this is a function we have not  
976
+
977
+ 00:26:26.400 --> 00:26:33.360
978
+ coded yet. So to make this function work, we're 
979
+ going to have to do the following. We're probably  
980
+
981
+ 00:26:33.360 --> 00:26:40.800
982
+ going to have to figure out the timestamp of the 
983
+ video at which point someone presses the button.  
984
+
985
+ 00:26:40.800 --> 00:26:45.440
986
+ This is basically going to help us figure 
987
+ out what our bookmark should be saved as in  
988
+
989
+ 00:26:45.440 --> 00:26:50.000
990
+ storage according to its timestamp. So how 
991
+ are we going to do that? How are we going  
992
+
993
+ 00:26:50.000 --> 00:26:55.520
994
+ to figure out the YouTube video timestamp. 
995
+ Again, YouTube makes this pretty accessible,  
996
+
997
+ 00:26:56.080 --> 00:27:02.160
998
+ it can be found as an attribute. So what we're 
999
+ going to want to do is grab the YouTube player.  
1000
+
1001
+ 00:27:03.120 --> 00:27:08.960
1002
+ And we already have a global variable that has 
1003
+ it. But I'm just going to grab it again. So we can  
1004
+
1005
+ 00:27:08.960 --> 00:27:16.240
1006
+ see how to do this in the console, I'm going to 
1007
+ create a YouTube player variable in our console.  
1008
+
1009
+ 00:27:16.240 --> 00:27:23.760
1010
+ Okay, now we have it saved. And then on YouTube 
1011
+ player, there's going to be a property called  
1012
+
1013
+ 00:27:23.760 --> 00:27:32.480
1014
+ current time. And it's going to give us the 
1015
+ current time in seconds. And in order for us to  
1016
+
1017
+ 00:27:32.480 --> 00:27:39.360
1018
+ save our bookmark, according to hours, minutes 
1019
+ seconds, we're probably going to also have to  
1020
+
1021
+ 00:27:39.360 --> 00:27:47.840
1022
+ create a function that converts seconds into a 
1023
+ standard time of how it's displayed in YouTube.  
1024
+
1025
+ 00:27:49.120 --> 00:27:54.960
1026
+ So let's go ahead and start with all those 
1027
+ things. We're gonna go ahead and add the function,  
1028
+
1029
+ 00:27:54.960 --> 00:28:06.000
1030
+ add new bookmark event handler. And we're going 
1031
+ to use the exact property we saw in our console,  
1032
+
1033
+ 00:28:07.360 --> 00:28:13.440
1034
+ YouTube player dot current time, which is going to 
1035
+ give us the current time. And we're going to say  
1036
+
1037
+ 00:28:13.440 --> 00:28:20.000
1038
+ okay, now, this is only called when a new bookmark 
1039
+ is made. So let's create a new bookmark variable.  
1040
+
1041
+ 00:28:21.920 --> 00:28:28.800
1042
+ And this is going to be an object that has 
1043
+ the time of the bookmark and a description.  
1044
+
1045
+ 00:28:29.760 --> 00:28:34.880
1046
+ And the description is just going to end up 
1047
+ being the title that's going to be displayed  
1048
+
1049
+ 00:28:35.600 --> 00:28:41.840
1050
+ in the Chrome extension. So it's going to be 
1051
+ a dynamic description and skins a bookmark at  
1052
+
1053
+ 00:28:43.440 --> 00:28:49.920
1054
+ current time. However, the problem is that 
1055
+ this is in seconds, as we said before,  
1056
+
1057
+ 00:28:49.920 --> 00:28:54.320
1058
+ so we're going to have to convert this. So 
1059
+ we're going to use a function called get time.  
1060
+
1061
+ 00:28:56.720 --> 00:29:01.680
1062
+ I'm just going to insert it using pieces. So I'm 
1063
+ going to do is go over to this time function here.  
1064
+
1065
+ 00:29:02.960 --> 00:29:11.360
1066
+ Insert snippet. And there it is. So now I'm 
1067
+ able to convert my seconds into time. And then  
1068
+
1069
+ 00:29:11.360 --> 00:29:14.800
1070
+ the last thing I want to do here 
1071
+ is sync it to Chrome Storage.  
1072
+
1073
+ 00:29:16.000 --> 00:29:23.200
1074
+ And what this is going to do is set Chrome storage 
1075
+ with each bookmark. So basically, each video,  
1076
+
1077
+ 00:29:23.200 --> 00:29:27.040
1078
+ according to its video identification 
1079
+ number that we're grabbing from the URL  
1080
+
1081
+ 00:29:28.080 --> 00:29:35.440
1082
+ will also map back to a set up bookmarks in Chrome 
1083
+ Storage. So to do that, we're going to do Chrome  
1084
+
1085
+ 00:29:35.440 --> 00:29:39.840
1086
+ storage sync. And again, if you're interested in 
1087
+ this, you can look in documentation to find out  
1088
+
1089
+ 00:29:41.040 --> 00:29:47.280
1090
+ what this function takes. Current video, it's 
1091
+ important to remember that things need to be  
1092
+
1093
+ 00:29:47.280 --> 00:29:57.680
1094
+ stored in JSON in Chrome Storage. So I'm going to 
1095
+ do JSON stringify. All my current video bookmarks,  
1096
+
1097
+ 00:29:57.680 --> 00:30:04.000
1098
+ so I'm actually going to add it A variable up here 
1099
+ that's going to store all current video bookmarks  
1100
+
1101
+ 00:30:07.040 --> 00:30:14.080
1102
+ in an array. And I'm going 
1103
+ to spread that. So we can  
1104
+
1105
+ 00:30:15.920 --> 00:30:22.240
1106
+ add a new bookmark to those set of current video 
1107
+ bookmarks. And then the last thing I want to do  
1108
+
1109
+ 00:30:22.240 --> 00:30:27.120
1110
+ here is sort bookmarks by their save 
1111
+ timestamp in our Chrome Storage.  
1112
+
1113
+ 00:30:29.120 --> 00:30:36.560
1114
+ So we're going to sort by time, and this is just 
1115
+ coming from this right here, every bookmark is  
1116
+
1117
+ 00:30:36.560 --> 00:30:44.640
1118
+ going to have a time and a description. So we're 
1119
+ going to look at that and sort accordingly. Great.  
1120
+
1121
+ 00:30:46.880 --> 00:30:52.640
1122
+ Now, if we reload our extension, we're going 
1123
+ to see if it works as expected. And the way  
1124
+
1125
+ 00:30:52.640 --> 00:31:01.680
1126
+ to see that is basically console dot log, this new 
1127
+ bookmark, let's do it. Great. That time it worked,  
1128
+
1129
+ 00:31:01.680 --> 00:31:07.120
1130
+ we just had to give it another reload. And 
1131
+ we got a time in seconds and a description.  
1132
+
1133
+ 00:31:08.400 --> 00:31:13.360
1134
+ Now the final thing I want to do is complete this 
1135
+ file before we go to the UI. And we want to make  
1136
+
1137
+ 00:31:13.360 --> 00:31:18.320
1138
+ this fully functional to fetch all bookmarks when 
1139
+ a new video is loaded. To do this, we're going  
1140
+
1141
+ 00:31:18.320 --> 00:31:24.160
1142
+ to grab asynchronously, all bookmarks from Chrome 
1143
+ storage, which means I'm going to write a promise  
1144
+
1145
+ 00:31:24.160 --> 00:31:28.560
1146
+ that resolves once we retrieve all bookmarks. 
1147
+ So that code is going to look like this.  
1148
+
1149
+ 00:31:29.920 --> 00:31:36.720
1150
+ I'm going to create it at the top here. 
1151
+ And I'm going to say const fetch bookmarks.  
1152
+
1153
+ 00:31:41.920 --> 00:31:48.880
1154
+ And I want to return a promise. So 
1155
+ we can resolve this asynchronously.  
1156
+
1157
+ 00:31:52.240 --> 00:31:56.240
1158
+ And within that promise, I'm going 
1159
+ to fetch from Chrome Storage. So  
1160
+
1161
+ 00:31:57.520 --> 00:32:01.520
1162
+ I'm going to do a Chrome storage 
1163
+ sync and we did a set before to  
1164
+
1165
+ 00:32:01.520 --> 00:32:06.480
1166
+ set Chrome Storage, we're going 
1167
+ to get this time our current video  
1168
+
1169
+ 00:32:10.320 --> 00:32:15.600
1170
+ it takes an object. And we're going to resolve  
1171
+
1172
+ 00:32:23.840 --> 00:32:34.080
1173
+ to find any bookmarks when indexing 
1174
+ using our current video. So  
1175
+
1176
+ 00:32:38.480 --> 00:32:44.640
1177
+ basically look in storage to see if our current 
1178
+ video has any bookmarks, or if it exists in  
1179
+
1180
+ 00:32:44.640 --> 00:32:50.560
1181
+ storage. That's what's happening right here. If 
1182
+ it does exist, we're going to JSON dot parse it  
1183
+
1184
+ 00:32:50.560 --> 00:32:56.960
1185
+ because we JSON dot Stringify before, 
1186
+ if it doesn't, what we want to do is  
1187
+
1188
+ 00:32:59.680 --> 00:33:07.600
1189
+ return an empty array. And this should work. 
1190
+ And we're really only going to add these in  
1191
+
1192
+ 00:33:07.600 --> 00:33:14.000
1193
+ two places, which will be in our new video 
1194
+ loaded function. So we're going to make this  
1195
+
1196
+ 00:33:14.000 --> 00:33:22.240
1197
+ async. And we're gonna add a fetch bookmarks. 
1198
+ So actually, we're just going to add this to  
1199
+
1200
+ 00:33:22.240 --> 00:33:29.120
1201
+ our current video bookmarks variable. 
1202
+ And call a weight fetch bookmarks.  
1203
+
1204
+ 00:33:31.440 --> 00:33:33.600
1205
+ async await is going to resolve this promise.  
1206
+
1207
+ 00:33:35.920 --> 00:33:40.560
1208
+ And then the second place we want to add this 
1209
+ is to our add new bookmarks event handler.  
1210
+
1211
+ 00:33:42.400 --> 00:33:47.760
1212
+ To basically handle this case, and make 
1213
+ sure we're always using the most up to date  
1214
+
1215
+ 00:33:49.600 --> 00:33:51.840
1216
+ set of bookmarks when destructuring.  
1217
+
1218
+ 00:33:54.000 --> 00:34:03.840
1219
+ So we're gonna do current video bookmarks equals 
1220
+ the weight, veg bookmarks. And also make this  
1221
+
1222
+ 00:34:03.840 --> 00:34:12.800
1223
+ async. Awesome. So for right now, we finished 
1224
+ everything we need for our content script file,  
1225
+
1226
+ 00:34:12.800 --> 00:34:16.800
1227
+ obviously, things aren't going to show in the 
1228
+ UI. And we could check that out right here.  
1229
+
1230
+ 00:34:18.000 --> 00:34:22.960
1231
+ And as you can see, there's nothing in the UI 
1232
+ because everything we've been doing so far has  
1233
+
1234
+ 00:34:22.960 --> 00:34:29.520
1235
+ been manipulating the DOM right here to add 
1236
+ the icon. Add some logic to get us ready to  
1237
+
1238
+ 00:34:29.520 --> 00:34:35.520
1239
+ create a UI for our extension. Let's go ahead and 
1240
+ start making some UI components show starting out  
1241
+
1242
+ 00:34:35.520 --> 00:34:39.680
1243
+ with some bookmarks from clicking that addition 
1244
+ button in the YouTube player that we added.  
1245
+
1246
+ 00:34:40.800 --> 00:34:46.000
1247
+ Now, the first thing we need to figure out on any 
1248
+ given page is if it's a YouTube video page or not,  
1249
+
1250
+ 00:34:46.000 --> 00:34:50.480
1251
+ if it is, we're going on one of fetch any 
1252
+ bookmarks we may have from Chrome Storage.  
1253
+
1254
+ 00:34:51.120 --> 00:34:56.320
1255
+ And if it's not, we'll just want to display 
1256
+ some messaging saying it's not a YouTube page.  
1257
+
1258
+ 00:34:56.320 --> 00:35:01.680
1259
+ If you open the Chrome extension on a 
1260
+ page that is not YouTube. So to do this,  
1261
+
1262
+ 00:35:01.680 --> 00:35:08.080
1263
+ we're going to add a utility function that's 
1264
+ going to allow us to decipher that logic.  
1265
+
1266
+ 00:35:08.080 --> 00:35:14.000
1267
+ So we're actually going to grab our utility 
1268
+ function to find the active tab that the user is  
1269
+
1270
+ 00:35:14.000 --> 00:35:20.640
1271
+ on through Google Chrome documentation. I'm going 
1272
+ to go ahead and use this example right here, which  
1273
+
1274
+ 00:35:21.200 --> 00:35:26.960
1275
+ helps us retrieved a currently focused tab 
1276
+ from the Chrome documentation. And since I  
1277
+
1278
+ 00:35:26.960 --> 00:35:31.520
1279
+ have the google chrome pieces extension over 
1280
+ every codeblock, whether it's in documentation  
1281
+
1282
+ 00:35:31.520 --> 00:35:36.880
1283
+ or Stack Overflow, I'm able to directly 
1284
+ save on pieces with this icon that shows up  
1285
+
1286
+ 00:35:37.440 --> 00:35:41.840
1287
+ at the top right of any code block, I'm going 
1288
+ to go ahead and save it. And then I'm going  
1289
+
1290
+ 00:35:41.840 --> 00:35:48.320
1291
+ to go back to my VS code and refresh my pieces 
1292
+ tree, I can go ahead and insert this snippet,  
1293
+
1294
+ 00:35:48.320 --> 00:35:54.240
1295
+ which is the newest one, and I'm just going 
1296
+ to rename this snippet to active tab Chrome.  
1297
+
1298
+ 00:35:56.400 --> 00:36:02.320
1299
+ Amazing and pieces automatically classified this 
1300
+ as JavaScript, because it was able to decipher  
1301
+
1302
+ 00:36:02.320 --> 00:36:08.320
1303
+ that from some machine learning. I'm gonna go 
1304
+ ahead and delete this background.js comment.  
1305
+
1306
+ 00:36:09.440 --> 00:36:15.840
1307
+ And awesome, we now have a function that grabs 
1308
+ the current tab. But also, I want to make sure  
1309
+
1310
+ 00:36:15.840 --> 00:36:21.120
1311
+ I'm exporting this function. So I'm going 
1312
+ to add export. And then what I want to do is  
1313
+
1314
+ 00:36:21.120 --> 00:36:26.720
1315
+ open up the pop up.js file. And over here, 
1316
+ we're going to want to import that function  
1317
+
1318
+ 00:36:26.720 --> 00:36:34.240
1319
+ at the very top. So we can use it here. 
1320
+ So I'm going to import Get active tab URL  
1321
+
1322
+ 00:36:36.720 --> 00:36:43.440
1323
+ from utils dot j, s, and I actually 
1324
+ don't think the documentation called  
1325
+
1326
+ 00:36:43.440 --> 00:36:47.760
1327
+ it this. So I'm going to go ahead and 
1328
+ change the function name, so it matches.  
1329
+
1330
+ 00:36:49.760 --> 00:36:58.800
1331
+ So go to utils.js. Change that thought, 
1332
+ awesome. Now, the event we want to listen  
1333
+
1334
+ 00:36:58.800 --> 00:37:03.920
1335
+ to when opening the pop up.js file is the DOM 
1336
+ content loaded event, which is right here.  
1337
+
1338
+ 00:37:04.720 --> 00:37:10.480
1339
+ This event is a native window event that fires 
1340
+ when an HTML document has initially been loaded.  
1341
+
1342
+ 00:37:10.480 --> 00:37:15.120
1343
+ It's essentially when we want to load all our 
1344
+ bookmarks and show them. So we're going to  
1345
+
1346
+ 00:37:15.120 --> 00:37:21.840
1347
+ type the following to do so what we're going 
1348
+ to do is grab our active tab function first.  
1349
+
1350
+ 00:37:22.400 --> 00:37:30.080
1351
+ And we're going to look at the user's current 
1352
+ active tab, which we already have the function  
1353
+
1354
+ 00:37:30.080 --> 00:37:37.680
1355
+ for from in the utiles. It's an async function. 
1356
+ So we're going to async await this. And then after  
1357
+
1358
+ 00:37:37.680 --> 00:37:43.680
1359
+ that, we're going to grab the query parameters 
1360
+ to help us identify the video. If you remember,  
1361
+
1362
+ 00:37:44.720 --> 00:37:51.280
1363
+ each YouTube video has a unique identifier. After 
1364
+ the question mark, where the query parameter,  
1365
+
1366
+ 00:37:52.960 --> 00:37:59.760
1367
+ we're going to grab that, we're going to use a 
1368
+ URL search params to be able to get the unique  
1369
+
1370
+ 00:37:59.760 --> 00:38:09.120
1371
+ identifier for each video. And to get the 
1372
+ unique identifier, we're going to create it  
1373
+
1374
+ 00:38:09.120 --> 00:38:17.360
1375
+ current video variable and do URL parameters 
1376
+ dot get V. And this is just based off of  
1377
+
1378
+ 00:38:17.360 --> 00:38:22.880
1379
+ what the YouTube video URLs look 
1380
+ like. Now, our active tab URL  
1381
+
1382
+ 00:38:24.880 --> 00:38:34.160
1383
+ should have youtube.com/watch Because any specific 
1384
+ YouTube video always has this in its URL. And  
1385
+
1386
+ 00:38:34.160 --> 00:38:39.680
1387
+ we want to make sure we're watching a YouTube 
1388
+ video when our Chrome Extension has any logic  
1389
+
1390
+ 00:38:39.680 --> 00:38:44.480
1391
+ with bookmarks. And we want to make sure 
1392
+ this current video variable is truthy  
1393
+
1394
+ 00:38:44.480 --> 00:38:51.120
1395
+ meaning is get actually returned something 
1396
+ other than undefined or any falsie value.  
1397
+
1398
+ 00:38:54.160 --> 00:39:00.160
1399
+ And then what we want to do is we want 
1400
+ to get any current video bookmarks from  
1401
+
1402
+ 00:39:00.160 --> 00:39:06.000
1403
+ Chrome storage. If you remember, we're setting 
1404
+ Chrome storage with the current video as a key  
1405
+
1406
+ 00:39:06.720 --> 00:39:12.640
1407
+ and then all the bookmarks as a value that is 
1408
+ JSON ified. And in order for us to retrieve those  
1409
+
1410
+ 00:39:12.640 --> 00:39:17.760
1411
+ bookmarks, we need to use a Chrome Storage API 
1412
+ to get them. So to do that, we're going to grab  
1413
+
1414
+ 00:39:19.280 --> 00:39:26.640
1415
+ the video bookmarks using Chrome storage sync get. 
1416
+ And we're going to get it with the current video  
1417
+
1418
+ 00:39:26.640 --> 00:39:32.160
1419
+ unique identifier, which is the YouTube 
1420
+ videos unique identifier in the URL.  
1421
+
1422
+ 00:39:34.480 --> 00:39:41.440
1423
+ And then, we are going to set a current video 
1424
+ bookmarks variable which is going to contain  
1425
+
1426
+ 00:39:41.440 --> 00:39:46.800
1427
+ all those JSON ified current videos. And in 
1428
+ order for us to pass this to any function  
1429
+
1430
+ 00:39:46.800 --> 00:39:55.360
1431
+ or write some custom logic to show bookmarks, 
1432
+ we're going to have to JSON dot parse any  
1433
+
1434
+ 00:39:55.360 --> 00:39:59.760
1435
+ bookmarks that are saved in Chrome Storage since 
1436
+ it's in JSON, and we can't really work with that.  
1437
+
1438
+ 00:40:00.960 --> 00:40:07.760
1439
+ But if there are no bookmarks or chrome searches 
1440
+ and return anything, we're just going to want to  
1441
+
1442
+ 00:40:07.760 --> 00:40:14.880
1443
+ return an empty array. Now, we're going to have 
1444
+ to pass this over to the view bookmarks function,  
1445
+
1446
+ 00:40:15.680 --> 00:40:20.320
1447
+ which is basically going to help us 
1448
+ view any bookmarks in our extension,  
1449
+
1450
+ 00:40:21.040 --> 00:40:26.880
1451
+ that Chrome Storage dot get returns. But before 
1452
+ that, I'm just going to put a comment right  
1453
+
1454
+ 00:40:26.880 --> 00:40:32.960
1455
+ here. So we remember, we want to handle this 
1456
+ else condition, which basically is for the  
1457
+
1458
+ 00:40:32.960 --> 00:40:39.520
1459
+ scenario where we're not on a youtube.com video 
1460
+ page, or current video returns a falsie value.  
1461
+
1462
+ 00:40:40.560 --> 00:40:46.320
1463
+ So what we're going to want to do is add a message 
1464
+ that says this is not a YouTube video page.  
1465
+
1466
+ 00:40:47.200 --> 00:40:52.080
1467
+ And let's just go back to chrome to 
1468
+ look at what that might look like.  
1469
+
1470
+ 00:40:54.000 --> 00:41:02.480
1471
+ So this is our UI Currently, we have this 
1472
+ container class right here that encapsulates  
1473
+
1474
+ 00:41:03.040 --> 00:41:08.320
1475
+ and will eventually encapsulate all the bookmarks 
1476
+ we have, it has this container class name in it,  
1477
+
1478
+ 00:41:09.600 --> 00:41:15.040
1479
+ what we're going to want to do is get that class 
1480
+ name. So we're just going to do this in the  
1481
+
1482
+ 00:41:15.040 --> 00:41:22.560
1483
+ console before we actually do in code just to make 
1484
+ sure it works. The class was called container. And  
1485
+
1486
+ 00:41:22.560 --> 00:41:27.440
1487
+ that's just from the CSS in the boilerplate, 
1488
+ so you don't have to worry about it, or the  
1489
+
1490
+ 00:41:27.440 --> 00:41:34.000
1491
+ HTML or other. So when we wrote this document that 
1492
+ get elements by class name container, and then  
1493
+
1494
+ 00:41:34.000 --> 00:41:43.280
1495
+ grab the first element in the HTML collection, we 
1496
+ get this element right here, which is containing  
1497
+
1498
+ 00:41:43.280 --> 00:41:51.360
1499
+ all these other elements within it. And what we 
1500
+ want to do here is basically specify in the HTML  
1501
+
1502
+ 00:41:54.800 --> 00:41:59.280
1503
+ on pages that are not youtube.com. So 
1504
+ this is actually a YouTube video page.  
1505
+
1506
+ 00:42:00.000 --> 00:42:03.360
1507
+ We don't want to display this message. But I 
1508
+ just want to show how this is going to look,  
1509
+
1510
+ 00:42:04.400 --> 00:42:06.240
1511
+ we're going to want to put a new div class  
1512
+
1513
+ 00:42:11.760 --> 00:42:14.400
1514
+ that says, This is not a YouTube video page.  
1515
+
1516
+ 00:42:15.600 --> 00:42:19.680
1517
+ And let's just see if that works. Will this 
1518
+ change the extension the way we want it to?  
1519
+
1520
+ 00:42:24.560 --> 00:42:27.600
1521
+ Container is not. So what we need to do over here  
1522
+
1523
+ 00:42:29.440 --> 00:42:33.920
1524
+ is actually encapsulate this in a variable. 
1525
+ We're gonna set this equal to container.  
1526
+
1527
+ 00:42:35.520 --> 00:42:41.760
1528
+ And now let's try that. And change the extension 
1529
+ to show that this is not a YouTube video page.  
1530
+
1531
+ 00:42:42.720 --> 00:42:45.760
1532
+ So the way we're going to do 
1533
+ this dynamically in our code  
1534
+
1535
+ 00:42:45.760 --> 00:42:49.840
1536
+ is basically put all the code we just 
1537
+ put in our console to test this out  
1538
+
1539
+ 00:42:50.400 --> 00:42:55.920
1540
+ within our else conditions. So every time we're 
1541
+ not on a YouTube video page, or this returns a  
1542
+
1543
+ 00:42:55.920 --> 00:43:01.680
1544
+ falsie value, we want to show that this is 
1545
+ not a YouTube video page when we try to open  
1546
+
1547
+ 00:43:01.680 --> 00:43:06.880
1548
+ up the Chrome extension in those scenarios. So 
1549
+ we're gonna say const container equals document  
1550
+
1551
+ 00:43:06.880 --> 00:43:15.040
1552
+ dot get elements by class name, right there. 
1553
+ Grab that container class, first element.  
1554
+
1555
+ 00:43:17.760 --> 00:43:25.200
1556
+ And then set the inner HTML, set that equal to div 
1557
+ class equals title, title, just add some styling,  
1558
+
1559
+ 00:43:25.760 --> 00:43:28.560
1560
+ that's going to make it look 
1561
+ slightly nicer. There's nothing  
1562
+
1563
+ 00:43:29.120 --> 00:43:31.280
1564
+ super special about the styling I have.  
1565
+
1566
+ 00:43:35.360 --> 00:43:40.240
1567
+ And since we tested it, there shouldn't be 
1568
+ really any surprises here, it should pretty much  
1569
+
1570
+ 00:43:40.240 --> 00:43:45.760
1571
+ work as expected. So let's go ahead 
1572
+ and give this extension a reload.  
1573
+
1574
+ 00:43:47.600 --> 00:43:52.880
1575
+ It shouldn't show the message for this page. 
1576
+ It doesn't. But if we go to a non YouTube page,  
1577
+
1578
+ 00:43:53.520 --> 00:43:58.000
1579
+ it's gonna say this is not a YouTube 
1580
+ video page. Amazing. So let's go back to  
1581
+
1582
+ 00:43:59.520 --> 00:44:03.280
1583
+ our code. And we're going to want to 
1584
+ write this view bookmarks function.  
1585
+
1586
+ 00:44:03.280 --> 00:44:09.520
1587
+ So if it does meet the conditions of being on 
1588
+ a youtube.com/watch page, and as you can see,  
1589
+
1590
+ 00:44:10.640 --> 00:44:19.320
1591
+ that's from any page that has a video page, 
1592
+ it has youtube.com/watch on it. And your  
1593
+
1594
+ 00:44:19.840 --> 00:44:27.840
1595
+ URL params dot get the return something so it's 
1596
+ a truthy value, we're going to want to view the  
1597
+
1598
+ 00:44:27.840 --> 00:44:33.040
1599
+ bookmarks associated with that video. So let's 
1600
+ go ahead and call the view bookmarks function  
1601
+
1602
+ 00:44:34.320 --> 00:44:39.680
1603
+ and pass it all the current video bookmarks. 
1604
+ And we're gonna go ahead and write the logic  
1605
+
1606
+ 00:44:39.680 --> 00:44:44.720
1607
+ that's going to help us populate the UI with all 
1608
+ the bookmarks we grabbed from Chrome Storage.  
1609
+
1610
+ 00:44:46.240 --> 00:44:50.720
1611
+ So to do that, we're going 
1612
+ to pass it current bookmarks.  
1613
+
1614
+ 00:44:54.000 --> 00:44:58.560
1615
+ And we're going to set a default argument of an 
1616
+ empty array just in case nothing is passed to it.  
1617
+
1618
+ 00:44:59.120 --> 00:45:08.480
1619
+ It's just going To return or show no bookmarks, 
1620
+ and we're going to grab a bookmark element.  
1621
+
1622
+ 00:45:10.880 --> 00:45:17.200
1623
+ Again, this is just from the HTML that I have 
1624
+ given you. So it's not anything you need to  
1625
+
1626
+ 00:45:17.200 --> 00:45:23.280
1627
+ worry about. If you want to try this out on your 
1628
+ own, you could try it out in the console. Just  
1629
+
1630
+ 00:45:23.280 --> 00:45:27.360
1631
+ to save some time here, I'm just going to write 
1632
+ the code here. And you can go ahead and copy it.  
1633
+
1634
+ 00:45:28.560 --> 00:45:33.680
1635
+ But again, it's just knowing how to work with 
1636
+ the DOM and inspecting the elements to figure out  
1637
+
1638
+ 00:45:34.400 --> 00:45:35.120
1639
+ how to do this.  
1640
+
1641
+ 00:45:37.840 --> 00:45:43.600
1642
+ What I'm doing right here is basically saying, 
1643
+ Okay, if there are any bookmarks, let's just set  
1644
+
1645
+ 00:45:43.600 --> 00:45:49.280
1646
+ it to nothing. So we're not displaying anything, 
1647
+ we're going to reset the whole thing, since we're  
1648
+
1649
+ 00:45:49.280 --> 00:45:54.240
1650
+ calling this function to view bookmarks. And we're 
1651
+ going to have new bookmarks being passed in, which  
1652
+
1653
+ 00:45:54.240 --> 00:46:00.480
1654
+ is the current bookmarks. And we're gonna say if 
1655
+ the current bookmarks length is greater than zero,  
1656
+
1657
+ 00:46:00.480 --> 00:46:05.920
1658
+ meaning if there are current bookmarks, 
1659
+ and it's just not an empty array.  
1660
+
1661
+ 00:46:08.160 --> 00:46:11.360
1662
+ Let's go ahead and iterate 
1663
+ over all those bookmarks,  
1664
+
1665
+ 00:46:11.360 --> 00:46:18.400
1666
+ and show them in our UI. So to do that, we're 
1667
+ going to iterate over every bookmark in a loop.  
1668
+
1669
+ 00:46:22.960 --> 00:46:28.160
1670
+ And then, we're going to grab the bookmark 
1671
+ through indexing, so current bookmarks.  
1672
+
1673
+ 00:46:29.920 --> 00:46:35.760
1674
+ With whatever iteration we are in the loop. And 
1675
+ then what we're going to have to do from here  
1676
+
1677
+ 00:46:36.480 --> 00:46:41.840
1678
+ is call another function, add new bookmark, 
1679
+ which is going to add a new bookmark row to  
1680
+
1681
+ 00:46:42.720 --> 00:46:48.400
1682
+ our pop up, I'm going to go ahead and remove this 
1683
+ comment. And we're going to add a new bookmark,  
1684
+
1685
+ 00:46:49.600 --> 00:46:52.480
1686
+ we're going to pass it the bookmark 
1687
+ element up here, which is going to  
1688
+
1689
+ 00:46:52.480 --> 00:46:56.400
1690
+ populate all our bookmarks, well, it's 
1691
+ going to be where we add each of our rows.  
1692
+
1693
+ 00:46:59.120 --> 00:47:03.680
1694
+ And I'm going to pass it each specific bookmark. 
1695
+ So we're going to add one bookmark at a time and  
1696
+
1697
+ 00:47:03.680 --> 00:47:09.760
1698
+ call this function every time we're adding a 
1699
+ bookmark. But before that, what we want to do  
1700
+
1701
+ 00:47:09.760 --> 00:47:14.960
1702
+ is if there are no bookmarks to show meaning, 
1703
+ current bookmarks is just an empty array.  
1704
+
1705
+ 00:47:17.280 --> 00:47:20.720
1706
+ We're going to want a message that 
1707
+ says there are no bookmarks here.  
1708
+
1709
+ 00:47:20.720 --> 00:47:24.720
1710
+ So we're going to set a message using italics.  
1711
+
1712
+ 00:47:30.480 --> 00:47:42.640
1713
+ Saying no bookmarks. To show before we move 
1714
+ on and add individual bookmarks to our pop up,  
1715
+
1716
+ 00:47:42.640 --> 00:47:47.840
1717
+ let's go ahead and check if this condition 
1718
+ works. Where there's no bookmarks to show and  
1719
+
1720
+ 00:47:47.840 --> 00:47:51.760
1721
+ since we haven't added any bookmarks to this 
1722
+ YouTube video that I'm looking at right now,  
1723
+
1724
+ 00:47:51.760 --> 00:47:58.000
1725
+ it should work, I want to go ahead and reload my 
1726
+ extension. Yep, there it is no bookmarks to show.  
1727
+
1728
+ 00:47:59.920 --> 00:48:07.280
1729
+ Amazing. So now we're going to want to finally 
1730
+ handle the case where we have bookmarks to show  
1731
+
1732
+ 00:48:07.920 --> 00:48:14.640
1733
+ and this is going to allow us to start seeing 
1734
+ bookmarks in our UI. So the first thing we're  
1735
+
1736
+ 00:48:14.640 --> 00:48:19.840
1737
+ going to do is go to our add new bookmark 
1738
+ function. And it's going to accept bookmark  
1739
+
1740
+ 00:48:22.640 --> 00:48:29.440
1741
+ bookmarks element, and it's 
1742
+ going to accept a bookmark.  
1743
+
1744
+ 00:48:31.040 --> 00:48:36.000
1745
+ And then what we're going to do from here 
1746
+ is we're going to create two elements. So  
1747
+
1748
+ 00:48:36.000 --> 00:48:42.320
1749
+ one element is going to be for the title, which 
1750
+ is going to display in the UI of each bookmark.  
1751
+
1752
+ 00:48:43.040 --> 00:48:48.960
1753
+ And then one element is going to be the whole 
1754
+ bookmark element that will contain the title  
1755
+
1756
+ 00:48:49.520 --> 00:48:54.960
1757
+ will contain the delete button and will contain 
1758
+ the play button. So let's go ahead and create  
1759
+
1760
+ 00:48:54.960 --> 00:49:09.760
1761
+ the bookmark title element. And then after 
1762
+ this one, we're also going to create the new  
1763
+
1764
+ 00:49:09.760 --> 00:49:19.840
1765
+ bookmark element, which will encapsulate all these 
1766
+ other elements that are part of a bookmark row.  
1767
+
1768
+ 00:49:24.080 --> 00:49:29.600
1769
+ From here, for bookmark title element, we're 
1770
+ going to want to display what the bookmark  
1771
+
1772
+ 00:49:29.600 --> 00:49:35.920
1773
+ is and give it a title. So we actually already 
1774
+ created the title. The title is the description  
1775
+
1776
+ 00:49:35.920 --> 00:49:41.200
1777
+ of the bookmark. If you remember in our bookmark 
1778
+ object, there's a timestamp and a description.  
1779
+
1780
+ 00:49:41.200 --> 00:49:46.480
1781
+ So we're gonna set our text content to the 
1782
+ description, which is bookmark dot description.  
1783
+
1784
+ 00:49:48.720 --> 00:49:55.680
1785
+ And then our class name is going to be bookmark 
1786
+ title element dot class name, and that will be  
1787
+
1788
+ 00:49:55.680 --> 00:50:03.040
1789
+ set equal to bookmark title and this is just 
1790
+ going to add some In CSS, that is already in  
1791
+
1792
+ 00:50:03.040 --> 00:50:09.040
1793
+ our boilerplate code. Now for the general 
1794
+ component that is going to encapsulate all  
1795
+
1796
+ 00:50:09.040 --> 00:50:13.040
1797
+ the play button, the title, a delete 
1798
+ button, anything else you might want to add,  
1799
+
1800
+ 00:50:14.160 --> 00:50:20.880
1801
+ we're going to do a couple things, the first 
1802
+ thing we're going to do is give it an ID of  
1803
+
1804
+ 00:50:20.880 --> 00:50:28.000
1805
+ bookmark element, or bookmark with the 
1806
+ bookmark time, and this is going to guarantee a  
1807
+
1808
+ 00:50:28.960 --> 00:50:38.080
1809
+ unique ID for each element that is a row. So if 
1810
+ you save any bookmark, what's gonna happen is  
1811
+
1812
+ 00:50:38.080 --> 00:50:42.320
1813
+ there's going to be a row associated with each 
1814
+ bookmark, which is our new bookmark element.  
1815
+
1816
+ 00:50:43.280 --> 00:50:47.840
1817
+ And there's going to be an ID set for that 
1818
+ row, which will be the bookmark along with  
1819
+
1820
+ 00:50:47.840 --> 00:50:53.680
1821
+ the time and they'll help us uniquely 
1822
+ identify any specific row in the UI.  
1823
+
1824
+ 00:50:53.680 --> 00:51:00.560
1825
+ And that's later we're going to be used to delete 
1826
+ elements when we're deleting a specific bookmark.  
1827
+
1828
+ 00:51:02.640 --> 00:51:06.320
1829
+ And then we're going to set a class name, 
1830
+ which was is going to help with some styling,  
1831
+
1832
+ 00:51:07.120 --> 00:51:12.480
1833
+ that's going to be set to a bookmark 
1834
+ class. And then we're going to set  
1835
+
1836
+ 00:51:12.480 --> 00:51:18.160
1837
+ an attribute which is going to help us 
1838
+ with playing a video. Because basically,  
1839
+
1840
+ 00:51:18.160 --> 00:51:24.000
1841
+ we're going to want to know the timestamp of any 
1842
+ specific bookmark. So when we play the video,  
1843
+
1844
+ 00:51:24.800 --> 00:51:30.080
1845
+ we know where to set the video player at what 
1846
+ time we want to send it out and the attribute  
1847
+
1848
+ 00:51:30.080 --> 00:51:35.840
1849
+ of the bookmark element will help us find that. 
1850
+ And the final things we want to do here is,  
1851
+
1852
+ 00:51:35.840 --> 00:51:40.240
1853
+ since we know the new bookmark element 
1854
+ is encapsulating all these other things,  
1855
+
1856
+ 00:51:41.040 --> 00:51:50.160
1857
+ we want to append child bookmark title element, 
1858
+ so it displays within the new bookmark element.  
1859
+
1860
+ 00:51:50.160 --> 00:51:56.720
1861
+ And then we have this bookmarks element 
1862
+ that is passed in. And we're going to  
1863
+
1864
+ 00:51:56.720 --> 00:52:03.840
1865
+ append our new bookmark element, which is this 
1866
+ element that's encapsulating all the other things.  
1867
+
1868
+ 00:52:05.600 --> 00:52:11.280
1869
+ Inside that since it's a container. 
1870
+ So now if we go back to our UI,  
1871
+
1872
+ 00:52:13.600 --> 00:52:20.560
1873
+ and we give this a reload, just in case, let's 
1874
+ just go to a new video. And if I press plus,  
1875
+
1876
+ 00:52:20.560 --> 00:52:29.600
1877
+ in this video, we see a new row, it 
1878
+ says bookmark out one hour, 54 minutes.  
1879
+
1880
+ 00:52:31.040 --> 00:52:36.480
1881
+ And we could add another row if we 
1882
+ want. And it gives us that same row,  
1883
+
1884
+ 00:52:38.320 --> 00:52:41.680
1885
+ we're going to handle the case of the 
1886
+ deletion, there's an ADD, it's just going to  
1887
+
1888
+ 00:52:41.680 --> 00:52:49.600
1889
+ set at zero seconds. Bookmark it 
1890
+ 000. Awesome. So that works. So now  
1891
+
1892
+ 00:52:52.320 --> 00:52:55.600
1893
+ let's go back work on some 
1894
+ additional functionality.  
1895
+
1896
+ 00:52:56.560 --> 00:53:03.520
1897
+ Right now, we have no functionality associated 
1898
+ with each bookmark yet, so we can't play any  
1899
+
1900
+ 00:53:03.520 --> 00:53:09.440
1901
+ particular timestamped bookmark, we can't delete a 
1902
+ bookmark. And the next thing we want to add is the  
1903
+
1904
+ 00:53:09.440 --> 00:53:14.880
1905
+ play button. So to do this, we're going to add a 
1906
+ play button to each bookmark that will go directly  
1907
+
1908
+ 00:53:14.880 --> 00:53:20.080
1909
+ to this timestamp that we have saved for each 
1910
+ video. To start off, we're going to have to add  
1911
+
1912
+ 00:53:20.080 --> 00:53:25.360
1913
+ a function that is going to add an icon for 
1914
+ a play button, listen for a click and call a  
1915
+
1916
+ 00:53:25.360 --> 00:53:30.720
1917
+ function or event listener that will perform the 
1918
+ logic to set a video at a particular timestamp.  
1919
+
1920
+ 00:53:30.720 --> 00:53:35.200
1921
+ The function will end up looking something like 
1922
+ what we're going to code right here in a second.  
1923
+
1924
+ 00:53:36.400 --> 00:53:41.840
1925
+ And we're going to keep it super generic because 
1926
+ it's going to be used for both our delete  
1927
+
1928
+ 00:53:42.400 --> 00:53:49.600
1929
+ and play functionality. So the functions 
1930
+ are going to take a source attribute  
1931
+
1932
+ 00:53:50.480 --> 00:54:04.960
1933
+ an event listener. And it control parent element. 
1934
+ And when we say control elements in our code,  
1935
+
1936
+ 00:54:04.960 --> 00:54:09.840
1937
+ it means the play button, the delete button, 
1938
+ we're just calling those control elements.  
1939
+
1940
+ 00:54:12.560 --> 00:54:14.640
1941
+ So we're going to create a control element.  
1942
+
1943
+ 00:54:21.120 --> 00:54:27.120
1944
+ And this is just one particular functionality, 
1945
+ we're going to call a singular control element.  
1946
+
1947
+ 00:54:27.840 --> 00:54:32.400
1948
+ So in this specific case, we're going 
1949
+ to have a play button. But again,  
1950
+
1951
+ 00:54:32.400 --> 00:54:37.600
1952
+ this is a generic function. So think of this 
1953
+ as like a play button, a delete button we want  
1954
+
1955
+ 00:54:37.600 --> 00:54:43.760
1956
+ this singular control element will be one 
1957
+ of those. And then those control elements  
1958
+
1959
+ 00:54:46.240 --> 00:54:52.160
1960
+ will be linked to a image in our assets 
1961
+ folder. So if we want to play button,  
1962
+
1963
+ 00:54:52.880 --> 00:55:00.640
1964
+ what we're going to link to is assets slash play 
1965
+ dot PNG, and our schema super are predictable  
1966
+
1967
+ 00:55:01.440 --> 00:55:07.120
1968
+ for this. So all we're going 
1969
+ to do is assets plus SRC plus  
1970
+
1971
+ 00:55:08.000 --> 00:55:12.720
1972
+ dot png. And there's definitely a better 
1973
+ way of doing this, you can go back  
1974
+
1975
+ 00:55:12.720 --> 00:55:17.040
1976
+ and work on the code after this video. But we're 
1977
+ just going to keep it super simple for right now.  
1978
+
1979
+ 00:55:19.360 --> 00:55:26.880
1980
+ We're going to give it a title that is 
1981
+ the same as our source attribute, or what  
1982
+
1983
+ 00:55:26.880 --> 00:55:34.720
1984
+ we pass in this source. So what's going to get 
1985
+ passed in here is play, edit, delete, whatever.  
1986
+
1987
+ 00:55:34.720 --> 00:55:40.960
1988
+ And the title will be set to that. So in this 
1989
+ particular case, for play, it will be set as play,  
1990
+
1991
+ 00:55:42.960 --> 00:55:51.760
1992
+ we're going to add a event listener. And 
1993
+ that event listener will listen for a click.  
1994
+
1995
+ 00:55:53.920 --> 00:55:59.360
1996
+ And we're going to pass it a function that 
1997
+ is going to be performed on that clique. And  
1998
+
1999
+ 00:55:59.360 --> 00:56:03.600
2000
+ the last thing we want to do is there's 
2001
+ going to be a container for all control  
2002
+
2003
+ 00:56:03.600 --> 00:56:09.360
2004
+ elements. And we're passing that in into 
2005
+ this function. And we're calling it control  
2006
+
2007
+ 00:56:09.360 --> 00:56:15.840
2008
+ parent element. So we're going to append this 
2009
+ singular control element to the parent element.  
2010
+
2011
+ 00:56:18.560 --> 00:56:23.760
2012
+ And the next thing we're going to want to do is 
2013
+ add the function call that will add a play button,  
2014
+
2015
+ 00:56:23.760 --> 00:56:29.280
2016
+ a title and our event listener to each individual 
2017
+ bookmark. So in the add new bookmark function  
2018
+
2019
+ 00:56:29.280 --> 00:56:34.400
2020
+ that we coded earlier, we're going to add a couple 
2021
+ lines of code here. And these couple lines of code  
2022
+
2023
+ 00:56:34.400 --> 00:56:39.440
2024
+ are going to add those control elements. So we're 
2025
+ going to go ahead and create the element that's  
2026
+
2027
+ 00:56:39.440 --> 00:56:46.560
2028
+ going to hold all our buttons, we're going 
2029
+ to call it the controls element. And it's  
2030
+
2031
+ 00:56:46.560 --> 00:56:49.680
2032
+ going to be a div just like these other 
2033
+ ones, we're going to keep it super simple.  
2034
+
2035
+ 00:56:53.280 --> 00:56:57.840
2036
+ And then what we want to do 
2037
+ is give this some styling.  
2038
+
2039
+ 00:57:01.120 --> 00:57:04.320
2040
+ We're going to add the class name, but controls,  
2041
+
2042
+ 00:57:05.360 --> 00:57:14.000
2043
+ and you're just gonna have to trust me on 
2044
+ this it exists. Then what we want to do is  
2045
+
2046
+ 00:57:14.000 --> 00:57:21.440
2047
+ set our attributes using a set bookmark attributes 
2048
+ function that we created, we're going to pass in  
2049
+
2050
+ 00:57:21.440 --> 00:57:26.960
2051
+ play, the event listener is going to be called 
2052
+ on Play. And we're going to code that later.  
2053
+
2054
+ 00:57:26.960 --> 00:57:30.880
2055
+ And then we're going to pass in the controls 
2056
+ element, which is going to be the parent element.  
2057
+
2058
+ 00:57:31.680 --> 00:57:39.840
2059
+ And the last thing we want to do is 
2060
+ append this to our new bookmark element.  
2061
+
2062
+ 00:57:41.840 --> 00:57:47.440
2063
+ And what we should see now is, this 
2064
+ play button is going to show up in  
2065
+
2066
+ 00:57:47.440 --> 00:57:53.840
2067
+ our extension. So let's check this out. 
2068
+ Let's give this a refresh over here.  
2069
+
2070
+ 00:57:57.440 --> 00:58:01.920
2071
+ There we go. We have the play button in our 
2072
+ extension. But what we're going to notice  
2073
+
2074
+ 00:58:02.480 --> 00:58:09.040
2075
+ is it's actually not going to work. Let's go 
2076
+ ahead and play this video. And we're going to  
2077
+
2078
+ 00:58:09.040 --> 00:58:14.960
2079
+ try to get it back to 26 minutes, 51 seconds, 
2080
+ it doesn't work. And the reason it doesn't work  
2081
+
2082
+ 00:58:14.960 --> 00:58:21.840
2083
+ is we still need to code the On Play Event 
2084
+ listener. So let's go ahead and do that.  
2085
+
2086
+ 00:58:23.600 --> 00:58:30.800
2087
+ What we're going to do is we're going to target 
2088
+ the timestamp attribute that we set earlier.  
2089
+
2090
+ 00:58:33.120 --> 00:58:39.920
2091
+ So again, you could check this out in your 
2092
+ console or inspect, if you want to get a  
2093
+
2094
+ 00:58:39.920 --> 00:58:44.000
2095
+ visualization of how this is gonna work. But I'm 
2096
+ gonna go ahead and type this for the sake of time.  
2097
+
2098
+ 00:58:47.760 --> 00:58:53.360
2099
+ And we're gonna get that timestamp we set 
2100
+ earlier. And then the second thing we're  
2101
+
2102
+ 00:58:53.360 --> 00:58:58.240
2103
+ gonna want to do is grab the active tab, and 
2104
+ that's just using the active tab function.  
2105
+
2106
+ 00:59:00.080 --> 00:59:04.560
2107
+ This is an async await function. So we're going 
2108
+ to have to async await it. And I'm going to add  
2109
+
2110
+ 00:59:04.560 --> 00:59:09.600
2111
+ async to make this async function. So 
2112
+ we've actually run into a problem now,  
2113
+
2114
+ 00:59:10.400 --> 00:59:14.960
2115
+ we need to send the content script and message 
2116
+ to manipulate the YouTube player to set it at  
2117
+
2118
+ 00:59:14.960 --> 00:59:20.240
2119
+ the timestamp that the bookmark is placed on. 
2120
+ So in this file, we're going to have to add that  
2121
+
2122
+ 00:59:20.880 --> 00:59:25.280
2123
+ message. Let's go ahead and send 
2124
+ a message to the content script.  
2125
+
2126
+ 00:59:27.280 --> 00:59:34.560
2127
+ And this is going to follow the same pattern 
2128
+ of how we did it with our background script.  
2129
+
2130
+ 00:59:37.040 --> 00:59:43.360
2131
+ Missing comma there. We're going to have type 
2132
+ of play. That's going to be our event type.  
2133
+
2134
+ 00:59:44.320 --> 00:59:46.480
2135
+ And then the value is going to be bookmark time.  
2136
+
2137
+ 00:59:50.560 --> 00:59:54.160
2138
+ And then in our content script, 
2139
+ we're going to have to be able  
2140
+
2141
+ 00:59:54.160 --> 01:00:00.160
2142
+ to read this message. So what we're 
2143
+ going to do is add a condition to our  
2144
+
2145
+ 01:00:00.160 --> 01:00:04.800
2146
+ On message listener here, and we're 
2147
+ going to say if the type is play.  
2148
+
2149
+ 01:00:11.360 --> 01:00:13.840
2150
+ Let's set the YouTube player time  
2151
+
2152
+ 01:00:14.960 --> 01:00:18.960
2153
+ equal to the value that's passed in. So basically, 
2154
+ let's just take a look at this for a second.  
2155
+
2156
+ 01:00:20.080 --> 01:00:25.200
2157
+ If it's sending a message of type play, 
2158
+ and the value is the bookmark time,  
2159
+
2160
+ 01:00:25.200 --> 01:00:29.840
2161
+ then what we want to do is take that value and 
2162
+ set it to the YouTube Players Current Time,  
2163
+
2164
+ 01:00:29.840 --> 01:00:35.120
2165
+ which will make it the time of the bookmark. 
2166
+ And let's go ahead and see if this works.  
2167
+
2168
+ 01:00:37.200 --> 01:00:46.080
2169
+ I'm going to go ahead and reload my extension. 
2170
+ And let's go ahead and go to the extension,  
2171
+
2172
+ 01:00:46.080 --> 01:00:51.200
2173
+ we have a bookmark at 26 minutes, 51 seconds, 
2174
+ it's currently at 48 minutes, 30 seconds.  
2175
+
2176
+ 01:00:52.000 --> 01:00:55.840
2177
+ Let's hit that play button. It goes 
2178
+ back to 26 minutes, 51 seconds.  
2179
+
2180
+ 01:00:57.280 --> 01:01:00.320
2181
+ And now if we also hit this addition 
2182
+ button anywhere in the video,  
2183
+
2184
+ 01:01:01.280 --> 01:01:05.840
2185
+ we should get a new bookmark, we have 
2186
+ two hours, 21 minutes, 22 seconds.  
2187
+
2188
+ 01:01:07.520 --> 01:01:14.080
2189
+ Now let's go forward. Let's press play 
2190
+ here. And it goes back to that time.  
2191
+
2192
+ 01:01:14.080 --> 01:01:19.840
2193
+ Awesome. So now our Play button works. The last 
2194
+ functionality we want to build is the ability to  
2195
+
2196
+ 01:01:19.840 --> 01:01:25.360
2197
+ delete a bookmark, which will be super similar to 
2198
+ what we did for the play button. The first thing  
2199
+
2200
+ 01:01:25.360 --> 01:01:30.480
2201
+ we're going to want to do is go to our POP up.js 
2202
+ file. And we're going to add the delete button  
2203
+
2204
+ 01:01:30.480 --> 01:01:37.920
2205
+ to our controls element with the code in our add 
2206
+ new bookmark function to set bookmark attributes.  
2207
+
2208
+ 01:01:37.920 --> 01:01:44.400
2209
+ So let's go ahead and do that we're going to pass 
2210
+ in delete our on delete event listener, and then  
2211
+
2212
+ 01:01:44.400 --> 01:01:51.760
2213
+ the parent controls element. And since we set 
2214
+ the undelete function as the event listener,  
2215
+
2216
+ 01:01:51.760 --> 01:01:56.960
2217
+ we need to code some operations that are 
2218
+ going to take care of our deletion. So we  
2219
+
2220
+ 01:01:56.960 --> 01:02:02.240
2221
+ already know we're going to use this active tab 
2222
+ that we used over here. So let's go ahead and  
2223
+
2224
+ 01:02:02.240 --> 01:02:08.720
2225
+ already create this an async function ahead 
2226
+ of time. Let's grab the user's active tab.  
2227
+
2228
+ 01:02:13.680 --> 01:02:19.840
2229
+ And then what we're going to want to do is grab 
2230
+ the timestamp attribute that we set earlier.  
2231
+
2232
+ 01:02:23.920 --> 01:02:27.200
2233
+ And it's going to be the same code from up 
2234
+ here. So I'm just going to copy and paste  
2235
+
2236
+ 01:02:31.920 --> 01:02:40.400
2237
+ there we go. Then what we're going to also want 
2238
+ to do is grab the element that we want to delete.  
2239
+
2240
+ 01:02:42.400 --> 01:02:48.480
2241
+ So if you remember, I created a 
2242
+ specific ID linked to timestamps,  
2243
+
2244
+ 01:02:49.360 --> 01:02:54.080
2245
+ what we're going to want to do is grab 
2246
+ elements by the ID so we can delete them.  
2247
+
2248
+ 01:02:58.160 --> 01:03:05.120
2249
+ So bookmark. Plus the bookmark time will 
2250
+ give us the element we want to delete.  
2251
+
2252
+ 01:03:07.040 --> 01:03:09.520
2253
+ And then what we're going 
2254
+ to do is delete that element  
2255
+
2256
+ 01:03:10.320 --> 01:03:15.840
2257
+ by going to the parent node, and then removing the 
2258
+ child which will be the element we want to delete.  
2259
+
2260
+ 01:03:19.200 --> 01:03:23.360
2261
+ And then the final thing we're going to want to 
2262
+ do here is send a message to our content script.  
2263
+
2264
+ 01:03:26.000 --> 01:03:33.520
2265
+ Saying we want to perform a deletion type of  
2266
+
2267
+ 01:03:36.800 --> 01:03:45.200
2268
+ delete, and then the value is going to be bookmark 
2269
+ time. And there's one final thing we want to do  
2270
+
2271
+ 01:03:45.200 --> 01:03:51.040
2272
+ here, this Send Message function from the Chrome's 
2273
+ tabs API actually takes a callback function  
2274
+
2275
+ 01:03:51.040 --> 01:03:56.240
2276
+ optionally. And we're going to pass one in which 
2277
+ is going to be our view bookmarks function. And  
2278
+
2279
+ 01:03:56.240 --> 01:04:03.680
2280
+ that's just going to refresh our bookmarks, so any 
2281
+ deletions show up immediately, then in our content  
2282
+
2283
+ 01:04:03.680 --> 01:04:08.720
2284
+ script, we're going to add another condition, 
2285
+ which is basically you're going to ingest  
2286
+
2287
+ 01:04:08.720 --> 01:04:16.720
2288
+ that Delete message. So we're going 
2289
+ to say else if type equals Delete.  
2290
+
2291
+ 01:04:19.600 --> 01:04:25.840
2292
+ The current video bookmarks will be 
2293
+ equal to current video bookmarks.  
2294
+
2295
+ 01:04:26.960 --> 01:04:29.120
2296
+ Filter, and we're going to filter by time.  
2297
+
2298
+ 01:04:31.760 --> 01:04:35.120
2299
+ So the time is not equal to the value 
2300
+ being passed in because that's a  
2301
+
2302
+ 01:04:35.120 --> 01:04:39.840
2303
+ value we're deleting. And then the final 
2304
+ thing we want to do is sync Chrome Storage.  
2305
+
2306
+ 01:04:41.680 --> 01:04:48.000
2307
+ So if this page reloads, this 
2308
+ deleted bookmark does not show up.  
2309
+
2310
+ 01:04:52.720 --> 01:05:03.120
2311
+ We're going to JSON fi, error bookmarks and If 
2312
+ that should work, the last thing we want to do  
2313
+
2314
+ 01:05:03.120 --> 01:05:09.520
2315
+ is add a way to send the updated bookmarks back 
2316
+ to our POP up.js file in order to display the most  
2317
+
2318
+ 01:05:09.520 --> 01:05:16.480
2319
+ recent bookmarks, and we'll do the following. 
2320
+ To do that, we're going to send a response of  
2321
+
2322
+ 01:05:16.480 --> 01:05:22.560
2323
+ current video bookmarks. So now we can go ahead 
2324
+ and try out deleting a bookmark with a reload  
2325
+
2326
+ 01:05:22.560 --> 01:05:28.400
2327
+ of our extension, and it should start working. 
2328
+ So I'm going to go back to our Chrome browser,  
2329
+
2330
+ 01:05:31.840 --> 01:05:39.360
2331
+ reload our extension. And if we 
2332
+ go ahead and delete a bookmark,  
2333
+
2334
+ 01:05:40.240 --> 01:05:47.200
2335
+ we're gonna see that they're deleted. If we go 
2336
+ ahead and add a bookmark, we're gonna see there's  
2337
+
2338
+ 01:05:47.200 --> 01:05:52.320
2339
+ a new bookmark. It's at a different timestamp the 
2340
+ YouTube players a different time. So if we play,  
2341
+
2342
+ 01:05:53.600 --> 01:05:58.720
2343
+ it goes back to the timestamp of the bookmark. 
2344
+ We want to delete again, it's going to delete.  
2345
+
2346
+ 01:05:59.680 --> 01:06:03.360
2347
+ The last thing we're going to want to 
2348
+ do is distribute our extension. However,  
2349
+
2350
+ 01:06:03.360 --> 01:06:07.840
2351
+ I'm not going to quite go over that in this video, 
2352
+ because Google gives great documentation that  
2353
+
2354
+ 01:06:07.840 --> 01:06:12.960
2355
+ serves as a step by step guide on how to go about 
2356
+ publishing your chrome extension to the Google web  
2357
+
2358
+ 01:06:12.960 --> 01:06:18.400
2359
+ store for anyone to download. And with that, the 
2360
+ videos over you know everything you have to do  
2361
+
2362
+ 01:06:18.400 --> 01:06:23.920
2363
+ in order to create a modern web extension 
2364
+ using manifest v3, and I'll see you next time.