-
-
Notifications
You must be signed in to change notification settings - Fork 6
/
autoclear-chatgpt-history.user.js
940 lines (855 loc) · 57.1 KB
/
autoclear-chatgpt-history.user.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
// ==UserScript==
// @name Autoclear ChatGPT History
// @name:af Verwyder ChatGPT Geskiedenis 🕶️
// @name:am በተሻለ ChatGPT ጉዳዮ ማግኘት 🕶️
// @name:ar مسح تاريخ ChatGPT 🕶️
// @name:az ChatGPT Tarixini Təmizləyin 🕶️
// @name:be Ачысціць гісторыю ChatGPT 🕶️
// @name:bem Lekeni ChatGPT History 🕶️
// @name:bg Изчистете ChatGPT История 🕶️
// @name:bn চ্যাটজিপিটি ইতিহাস মুছে ফেলুন 🕶️
// @name:bo ChatGPT སྐད་དོན་ཚར་བཟོ། 🕶️
// @name:bs Obriši ChatGPT historiju 🕶️
// @name:ca Esborra l'historial de ChatGPT 🕶️
// @name:ceb Autoclear ChatGPT Kasaysayan 🕶️
// @name:ckb بسڕەوەی مێژووی ChatGPT 🕶️
// @name:cs Vymazat ChatGPT Historii 🕶️
// @name:cy Clirio Hanes ChatGPT 🕶️
// @name:da Ryd ChatGPT Historik 🕶️
// @name:de ChatGPT-Verlauf löschen 🕶️
// @name:dv ChatGPT ހިސްތުކުރުން ފުހެވޭނީ 🕶️
// @name:dz ChatGPT སྐད་ཆ་འབད་བཅུ་ 🕶️
// @name:el Διαγραφή Ιστορικού ChatGPT 🕶️
// @name:eo Forviŝi ChatGPT Historion 🕶️
// @name:es Borrar Historial de ChatGPT 🕶️
// @name:et Kustuta ChatGPT Ajalugu 🕶️
// @name:eu Ezabatu ChatGPT Historia 🕶️
// @name:fa پاک کردن تاریخچه ChatGPT 🕶️
// @name:fi Poista ChatGPT:n historia 🕶️
// @name:fo Strika ChatGPT Søgu 🕶️
// @name:fr Effacer l'historique de ChatGPT 🕶️
// @name:fr-CA Effacer l'historique de ChatGPT 🕶️
// @name:gd Lùghdaich Eachdraidh ChatGPT 🕶️
// @name:gl Limpar Historial de ChatGPT 🕶️
// @name:gu આપો ChatGPT ઇતિહાસ 🕶️
// @name:haw Kāpaki Kākoʻo i ka Moʻolelo o ChatGPT 🕶️
// @name:he מחק את היסטוריית ChatGPT 🕶️
// @name:hi ChatGPT इतिहास को हटाएं 🕶️
// @name:hr Izbriši ChatGPT Povijest 🕶️
// @name:ht Efase ChatGPT Istwa 🕶️
// @name:hu ChatGPT Előzmények Törlése 🕶️
// @name:hy Ջնջել ChatGPT-ի Պատմությունը 🕶️
// @name:id Hapus Riwayat ChatGPT 🕶️
// @name:is Eyða ChatGPT Saga 🕶️
// @name:it Cancella Cronologia ChatGPT 🕶️
// @name:ja ChatGPT の履歴を削除する 🕶️
// @name:jv Hapus Riwayat ChatGPT 🕶️
// @name:ka ChatGPT-ის ისტორიის გასუფთავება 🕶️
// @name:kab Sken ChatGPT Tamɣarit 🕶️
// @name:kk ChatGPT Тарихын Жою 🕶️
// @name:km លុបប្រវត្តិសាស្រ្ត ChatGPT 🕶️
// @name:kn ChatGPT ಇತಿಹಾಸವನ್ನು ಅಳಿಸಿ 🕶️
// @name:ko ChatGPT 기록 지우기 🕶️
// @name:ku Çavkaniya ChatGPTê Paqij bike 🕶️
// @name:ky ChatGPT Тарыхын Жок Кыл 🕶️
// @name:la Eximitte Historiam ChatGPT 🕶️
// @name:lb Läschen ChatGPT Geschicht 🕶️
// @name:lo ລຶບບັນດາຕິນມັກສະບັບ ChatGPT 🕶️
// @name:lt Išvalyti ChatGPT Istoriją 🕶️
// @name:lv Notīrīt ChatGPT Vēsturi 🕶️
// @name:mg Mamafa ny ChatGPT Historique 🕶️
// @name:mi Muku ChatGPT Hītori 🕶️
// @name:mk Избриши го Историјата на ChatGPT 🕶️
// @name:ml ചാറ്റ്ജിപിടി ചരിത്രം മായ്ക്കുക 🕶️
// @name:mn ChatGPT Түүхийг устгах 🕶️
// @name:ms Padam Sejarah ChatGPT 🕶️
// @name:mt Ħassar It-Twaħħil ChatGPT 🕶️
// @name:my ဆက်လက် ChatGPT သမိုင်းကို ဖျက်ပစ်နေပါသည် 🕶️
// @name:ne Autoclear ChatGPT इतिहास 🕶️
// @name:nl Wis ChatGPT Geschiedenis 🕶️
// @name:no Autoclear ChatGPT Historie 🕶️
// @name:ny Tikalonso ChatGPT Chisulo 🕶️
// @name:pa ਚੈਟਜੀਪੀਟੀ ਇਤਿਹਾਸ ਮਿਟਾਓ 🕶️
// @name:pap Bula Historia di ChatGPT 🕶️
// @name:pl Wyczyść Historię ChatGPT 🕶️
// @name:ps د ChatGPT د تاریخ پاکول 🕶️
// @name:pt Limpar Histórico do ChatGPT 🕶️
// @name:pt-BR Limpar Histórico do ChatGPT 🕶️
// @name:rn Kwihesha ChatGPT Byinshi 🕶️
// @name:ro Ștergeți Istoricul ChatGPT 🕶️
// @name:ru Очистить Историю ChatGPT 🕶️
// @name:rw Fata ChatGPT Itangazo 🕶️
// @name:sg Mbama ChatGPT Makumbe 🕶️
// @name:si නැවත සංවේදී ChatGPT ඉතිරිකිරීම 🕶️
// @name:sk Vymažte ChatGPT Históriu 🕶️
// @name:sl Počisti Zgodovino ChatGPT 🕶️
// @name:sm Masi ChatGPT Faʻaipoipoga 🕶️
// @name:sn Tirisa ChatGPT Chiremba 🕶️
// @name:so Ka Saar Tareenka ChatGPT 🕶️
// @name:sr Обриши историју ChatGPT-а 🕶️
// @name:sv Rensa ChatGPT Historik 🕶️
// @name:sw Futa Historia ya ChatGPT 🕶️
// @name:ta தானாகவே அழிக்க சேட்ஜிபிடி வரலாற்றை 🕶️
// @name:te ChatGPT చరిత్రను తొలగించు 🕶️
// @name:tg Тозаиши корҳои ChatGPT 🕶️
// @name:th ล้างประวัติศาสตร์ ChatGPT 🕶️
// @name:ti ምርግጋጽ ChatGPT ኣጸዓይ ፈጥር 🕶️
// @name:tk ChatGPT Tarixini Aýyr 🕶️
// @name:tn Futa ChatGPT Tlhahlobo 🕶️
// @name:to Fakatonu ChatGPT History 🕶️
// @name:tpi Kolim ChatGPT Stori 🕶️
// @name:tr ChatGPT Geçmişi Temizle 🕶️
// @name:uk Очистити Історію ChatGPT 🕶️
// @name:ur ChatGPT کی تاریخ صاف کریں 🕶️
// @name:uz ChatGPT Tarixini Tozalash 🕶️
// @name:vi Xóa Lịch Sử ChatGPT 🕶️
// @name:xh Qhipha ChatGPT Isaziso 🕶️
// @name:yi ויסמעקן טשאַטגפּט געשיכטע 🕶️
// @name:zh 自动清除 ChatGPT 历史记录 🕶️
// @name:zh-CN 自动清除 ChatGPT 历史记录 🕶️
// @name:zh-HK 自动清除 ChatGPT 历史记录 🕶️
// @name:zh-SG 自动清除 ChatGPT 历史记录 🕶️
// @name:zh-TW 自动清除 ChatGPT 历史记录 🕶️
// @name:zu Sula ChatGPT Isifundo 🕶️
// @description Auto-clears chat history when visiting chatgpt.com
// @description:af Skoonmaak Chat Geskiedenis wanneer jy chatgpt.com besoek
// @description:am የ chatgpt.com ጸሃይ ታክሲን በማግኘት ታከለው
// @description:ar يقوم تلقائيًا بمسح سجل المحادثات عند زيارة chatgpt.com
// @description:az chatgpt.com-a gedəndə avtomatik olaraq söhbət tarixini təmizləyir
// @description:be Аўтаматычна ачышчае гісторыю чата пры наведванні chatgpt.com
// @description:bem Chibwezache Mphindi Zochitika Pamene Kumatemba chatgpt.com
// @description:bg Автоматично изчиства чат историята при посещение на chatgpt.com
// @description:bn যখন chatgpt.com পরিদর্শন করা হলে অটোমেটিকভাবে চ্যাট ইতিহাস মুছে ফেলে
// @description:bo དཔེར་ན་ chatgpt.com འགྲེལ་བཤད་འདི་ལུ་ སྤྱོད་ཡོད་མི་འདི་བལྟ་མི་བཟོ།
// @description:bs Automatski briše istoriju chata prilikom posjete chatgpt.com
// @description:ca S'elimina automàticament l'historial de xats en visitar chatgpt.com
// @description:ceb Automatic gidut-ana sa kasaysayan sa chat sa pagbisita sa chatgpt.com
// @description:ckb دهستکاریکردنی مێژووی گفتوگۆکان خۆکارانه بۆ سەردانی chatgpt.com
// @description:cs Automaticky vymaže historii chatu při návštěvě chatgpt.com
// @description:cy Mae'n glirio hanes sgwrs yn awtomatig wrth ymweld â chatgpt.com
// @description:da Renser automatisk chatloggen ved besøg på chatgpt.com
// @description:de Löscht den Chatverlauf automatisch beim Besuch von chatgpt.com
// @description:dv chatgpt.com އެކައުންމަދުގެ ޗެކުމު ހުރިހައްދަވާނެ ޗައިންކުރޭ
// @description:dz འཛུགས་མིག་འདི་ལུ་ chatgpt.com འགྲེལ་བཤད་རོགས་བསྐྱེད་ཡོད།
// @description:el Αυτόματη διαγραφή ιστορικού συνομιλίας κατά την επίσκεψη στο chatgpt.com
// @description:eo Memorigo de la babilado aŭtomate malaperas dum vizito ĉe chatgpt.com
// @description:es Borra automáticamente el historial de chat al visitar chatgpt.com
// @description:et Kustutab automaatselt vestluse ajaloo, kui külastate saiti chatgpt.com
// @description:eu Berezgaitasunez ezabatzen du txataren historia chatgpt.com bisitatzen denean
// @description:fa پاک کردن خودکار تاریخچه چت در هنگام بازدید از chatgpt.com
// @description:fi Poistaa keskusteluhistorian automaattisesti käydessä chatgpt.comissa
// @description:fo Auto-rensar spjall søguna tá tú vitjar chatgpt.com
// @description:fr Efface automatiquement l'historique des discussions lors de la visite de chatgpt.com
// @description:fr-CA Efface automatiquement l'historique des discussions lors de la visite de chatgpt.com
// @description:gd Thoir aire bheagachaidh air eachdraidh na còmhraidh nuair a tha thu a' tadhal air chatgpt.com
// @description:gl Limpa automáticamente o historial do chat ao visitar chatgpt.com
// @description:gu chatgpt.com મુકે છે નાતીજે જ્ઞાનવર્ધક ચેટ નો ઇતિહાસ
// @description:haw Mālama haku ʻinoʻino pāhana hoʻohānau mai ana i chatgpt.com
// @description:he מנקה באופן אוטומטי את היסטוריית הצ'אט בעת ביקור ב-chatgpt.com
// @description:hi chatgpt.com पर आवर्तित होने पर चैट इतिहास को स्वचालित रूप से साफ करता है
// @description:hr Automatski briše povijest razgovora prilikom posjeta chatgpt.com
// @description:ht Auto-efase istwa chat la lè vizite chatgpt.com
// @description:hu Automatikusan törli a csevegés előzményeit a chatgpt.com látogatásakor
// @description:hy Պատմությունը ինքնաշխատանքային մաքրում է chatgpt.com այցելելուն դեպի
// @description:id Menghapus otomatis riwayat obrolan saat mengunjungi chatgpt.com
// @description:is Hreinsar sjálfvirkt spjallshönnun þegar heimsókn er gerð á chatgpt.com
// @description:it Cancella automaticamente la cronologia della chat durante la visita a chatgpt.com
// @description:ja chatgpt.com を访れる际に自动的にチャット履歴を消去します
// @description:jv Otomatis ngapus riwayat obrolan nalika ngunjungi chatgpt.com
// @description:ka თავისითად წაშლის ჩათის ისტორიას chatgpt.com-ზე მომსახურების დროს
// @description:kab Ireɣsan Ayren Tisstrir ChatGPT I yur-s achatgpt.com
// @description:kk chatgpt.com-ды көруге бастап автоматты түрде чат тарихын жою
// @description:km លុបសេវាកម្មប្រវត្តិការណ៍ជជែកពីព័ត៌មានមនុស្សកន្លងទៅកាន់ chatgpt.com
// @description:kn chatgpt.com ಸಂದರ್ಶಿಸಿದಾಗ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಚಾಟ್ ಇತಿಹಾಸವನ್ನು ಅಳಿಸುತ್ತದೆ
// @description:ko chatgpt.com 방문 시 채팅 기록을 자동으로 지웁니다
// @description:ku Çêkirina historyaya chatê di hembêzkirina chatgpt.com de
// @description:ky chatgpt.com барысында түр кат жазмаларын автоматтык түрде жок этиш
// @description:la Automate chat historia clearum cum chatgpt.com adibvisam
// @description:lb Läscht automatesch d'Chat-Geschicht wéini een chatgpt.com besicht
// @description:lo ລຶບປະວັດການສົນທະນາໃນຖ້າເຂົ້າຊົມ chatgpt.com
// @description:lt Automatiškai išvalo pokalbių istoriją apsilankius chatgpt.com
// @description:lv Automātiski notīra čata vēsturi, apmeklējot chatgpt.com
// @description:mg Mamafa tsy ampy lalao ny tetikasa vaovao rehefa mitovy amin'ny chatgpt.com
// @description:mi Auto-kōmata e whakakore i te hītori whakawhiti kōrero i te toro ki te chatgpt.com
// @description:mk Автоматски брише историја на разговорот при посета на chatgpt.com
// @description:ml chatgpt.com സന്ദർശിക്കുമ്പോൾ ചാറ്റ് ചരിത്രം ഓട്ടോ-പിന്തുണച്ച് അഴിച്ചുവയ്ക്കുന്നു
// @description:mn chatgpt.com-оос орж ирэх үед чатын түүхийг автоматаар цэвэрлэнэ
// @description:ms Membersihkan sejarah perbualan secara automatik apabila melawat chatgpt.com
// @description:mt Jħassar awtomatikament il-kronoloġija tal-chat meta żżur chatgpt.com
// @description:my chatgpt.com ကိုသွားဖို့အတွက် စကားဝှက်မှတ်တမ်းကို အလိုလိုရွေးချယ်ရန် အလွယ်တကူပြန်ဖွင့်ထားသည်
// @description:ne chatgpt.com मा आएकोमा च्याट इतिहास स्वचालित रूपमा हटाउँछ
// @description:nl Wis automatisch de chatgeschiedenis bij een bezoek aan chatgpt.com
// @description:no Sletter automatisk samtalehistorikk ved besøk på chatgpt.com
// @description:ny Kwatsa makina m'chipatala cha chat pamene kuwona chatgpt.com
// @description:pa chatgpt.com ਦੇ ਦੌਰਾਨ ਚੈਟ ਇਤਿਹਾਸ ਆਟੋਮੈਟਿਕ ਕਲੀਅਰ ਹੋ ਜਾਂਦਾ ਹੈ
// @description:pap Limpieza automático di historial di chat na bishita chatgpt.com
// @description:pl Automatycznie czyści historię czatu podczas odwiedzania chatgpt.com
// @description:ps خودکار تاریخچه چت پاک کول په chatgpt.com کښې
// @description:pt Limpa automaticamente o histórico de bate-papo ao visitar chatgpt.com
// @description:pt-BR Limpa automaticamente o histórico de bate-papo ao visitar chatgpt.com
// @description:rn Guteza inkuru y'ikarita y'imibare igihe utanga chatgpt.com
// @description:ro Șterge automat istoricul chat-ului la vizitarea chatgpt.com
// @description:ru Автоматически очищает историю чата при посещении chatgpt.com
// @description:rw Inyunganira amakuru ya chat inyuma yuko umaze guhamagara chatgpt.com
// @description:sg Auto-kura kolibatalu ya misamba wakari karika kutɔbɔ chatgpt.com
// @description:si chatgpt.com වෙත පැය සඳහා ස්වයංක්රීයතාවයින් චැට් ඉතිරිකිරීම මකා දැමුම
// @description:sk Automaticky vymazáva históriu chatu pri návšteve chatgpt.com
// @description:sl Samodejno izbriše zgodovino klepeta ob obisku spletnega mesta chatgpt.com
// @description:sm Automa i le malologa o le sootaga i luma i le chatgpt.com
// @description:sn Inongorora chat history chinayo ipapo uchi chiri kunochinja chatgpt.com
// @description:so Wax ka qaad chatka markii la booqdo chatgpt.com
// @description:sr Аутоматски брише историју чата при посети chatgpt.com
// @description:sv Rensar automatiskt chattens historik vid besök på chatgpt.com
// @description:sw Inaondoa historia ya mazungumzo moja kwa moja wakati wa kutembelea chatgpt.com
// @description:ta chatgpt.com அடுத்தடுத்தப்படும் நேரத்தில் உரையாடல் வரலாறை தானியங்கே நீக்குகிறது
// @description:te chatgpt.com సందర్శించినప్పుడు స్వయంచాలకంగా చాట్ చరిత్రను తొలగిస్తుంది
// @description:tg Тарихи чатро худкор ҷоба кунед, ки chatgpt.com равед
// @description:th ล้างประวัติการสนทนาโดยอัตโนมัติเมื่อเข้าชม chatgpt.com
// @description:ti ኮምፕዩተር እየጠበቀ ጊዜ chatgpt.com የተሰኘውን ችግርን አስፈልጋል
// @description:tk chatgpt.com-a ugradykda çat görnüşini awtomatiki biçimde boşaltýar
// @description:tn Emucisha chat chinyakanyaka nga uwonawo chatgpt.com
// @description:to 'Oku fa'a kovi 'e he ngaahi sipoti fakamatala 'i he falelotu ki he chatgpt.com
// @description:tpi Autometik klia chat histeri long bisitim long chatgpt.com
// @description:tr chatgpt.com'u ziyaret ettiğinizde sohbet geçmişini otomatik olarak temizler
// @description:uk Автоматично очищає історію чату при відвідуванні chatgpt.com
// @description:ur chatgpt.com کے دورے پر چیٹ تاریخ خودکار طور پر صاف کرتا ہے
// @description:uz chatgpt.com saytini tashrif buyurganda chat tarixini avtomatik ravishda o'chiradi
// @description:vi Xóa lịch sử trò chuyện tự động khi ghé thăm chatgpt.com
// @description:xh Ingqalasela ihisitela le-chat uma uzithola chatgpt.com
// @description:yi רומט די פֿונען דער שאַט היסטאָריע ביי בעזוך בקוקן chatgpt.com
// @description:zh 访问 chatgpt.com 时自动清除聊天记录
// @description:zh-CN 访问 chatgpt.com 时自动清除聊天记录
// @description:zh-HK 访问 chatgpt.com 时自动清除聊天记录
// @description:zh-SG 访问 chatgpt.com 时自动清除聊天记录
// @description:zh-TW 访问 chatgpt.com 时自动清除聊天记录
// @description:zu Ziba itshala lokucabanga okuzoshintshwa ngokuzenzakalelayo uma ukubuka chatgpt.com
// @author Adam Lui
// @namespace https://github.com/adamlui
// @version 2024.12.26.3
// @license MIT
// @icon https://media.autoclearchatgpt.com/images/icons/openai/black/icon48.png?a8868ef
// @icon64 https://media.autoclearchatgpt.com/images/icons/openai/black/icon64.png?a8868ef
// @compatible chrome
// @compatible edge
// @compatible firefox
// @compatible opera
// @compatible brave
// @compatible vivaldi
// @compatible librewolf
// @compatible ghost
// @compatible qq
// @match *://chatgpt.com/*
// @match *://chat.openai.com/*
// @connect cdn.jsdelivr.net
// @connect update.greasyfork.org
// @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.4.0/dist/chatgpt.min.js#sha256-LfB3mqeB6Xiq2BDub1tn3BtvEiMcaWEp+I094MFpA+Q=
// @resource brsCSS https://assets.aiwebextensions.com/styles/rising-stars/dist/black.min.css?v=0cde30f9ae3ce99ae998141f6e7a36de9b0cc2e7#sha256-4nbm81/JSas4wmxFIdliBBzoEEHRZ057TpzNX1PoQIs=
// @resource wrsCSS https://assets.aiwebextensions.com/styles/rising-stars/dist/white.min.css?v=0cde30f9ae3ce99ae998141f6e7a36de9b0cc2e7#sha256-pW8xWWV6tm8Q6Ms+HWZv6+QzzTLJPyL1DyE18ywpVaE=
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM_getResourceText
// @grant GM_xmlhttpRequest
// @grant GM.xmlHttpRequest
// @noframes
// @downloadURL https://update.greasyfork.org/scripts/460805/autoclear-chatgpt-history.user.js
// @updateURL https://update.greasyfork.org/scripts/460805/autoclear-chatgpt-history.meta.js
// @homepageURL https://www.autoclearchatgpt.com
// @supportURL https://support.autoclearchatgpt.com
// @contributionURL https://github.com/sponsors/adamlui
// ==/UserScript==
// Documentation: https://docs.autoclearchatgpt.com
// NOTE: This script relies on the powerful chatgpt.js library @ https://chatgpt.js.org
// © 2023–2024 KudoAI & contributors under the MIT license.
(async () => {
// Init ENV context
const env = {
browser: { language: chatgpt.getUserLanguage(), isMobile: chatgpt.browser.isMobile() },
scriptManager: {
name: (() => { try { return GM_info.scriptHandler } catch (err) { return 'unknown' }})(),
version: (() => { try { return GM_info.version } catch (err) { return 'unknown' }})()
},
ui: { scheme: getScheme() }
}
env.browser.isPortrait = env.browser.isMobile && (window.innerWidth < window.innerHeight)
env.scriptManager.supportsTooltips = env.scriptManager.name == 'Tampermonkey'
&& parseInt(env.scriptManager.version.split('.')[0]) >= 5
const xhr = typeof GM != 'undefined' && GM.xmlHttpRequest || GM_xmlhttpRequest
// Init APP data
const app = {
version: GM_info.script.version, configKeyPrefix: 'autoclearChatGPThistory',
chatgptJSver: /chatgpt\.js@([\d.]+)/.exec(GM_info.scriptMetaStr)[1], urls: {},
latestAssetCommitHash: '7dae88a' // for cached app.json + messages.json + navicon in toggles.sidebar.insert()
}
app.urls.assetHost = `https://cdn.jsdelivr.net/gh/adamlui/autoclear-chatgpt-history@${app.latestAssetCommitHash}`
const remoteAppData = await new Promise(resolve => xhr({
method: 'GET', url: `${app.urls.assetHost}/app.json`, onload: resp => resolve(JSON.parse(resp.responseText)) }))
Object.assign(app, { ...remoteAppData, urls: { ...app.urls, ...remoteAppData.urls }})
app.urls.update = app.urls.greasyFork.replace('https://', 'https://update.')
.replace(/(\d+)-?([a-z-]*)$/i, (_, id, name) => `${id}/${ name || 'script' }.meta.js`)
app.msgs = {
appName: app.name,
appAuthor: app.author.name,
appDesc: 'Auto-clears chat history when visiting chatgpt.com',
menuLabel_autoclear: 'Autoclear Chats',
menuLabel_clearNow: 'Clear Chats Now',
menuLabel_toggleVis: 'Toggle Visibility',
menuLabel_modeNotifs: 'Mode Notifications',
menuLabel_about: 'About',
menuLabel_donate: 'Please send a donation',
about_author: 'Author',
about_and: '&',
about_contributors: 'contributors',
about_version: 'Version',
about_poweredBy: 'Powered by',
about_openSourceCode: 'Open source code',
mode_autoclear: 'Auto-Clear',
helptip_clearNow: 'Clear chat history now',
helptip_toggleVis: 'Show Auto-Clear toggle in sidebar',
helptip_modeNotifs: 'Show notifications when toggling modes/settings',
notif_chatsCleared: 'Chat history cleared',
alert_choosePlatform: 'Choose a platform',
alert_updateAvail: 'Update available',
alert_newerVer: 'An update to',
alert_isAvail: 'is available',
alert_upToDate: 'Up-to-date',
alert_isUpToDate: 'is up-to-date',
alert_showYourSupport: 'Show your support',
alert_isOSS: 'is open-source software built & maintained for free through 100% volunteer efforts',
alert_despiteAffliction: 'Despite being severely afflicted by',
alert_longCOVID: 'long COVID',
alert_since2020: 'since 2020',
alert_byDonatingResults: 'by donating, you help me to continue improving, fixing bugs, adding new features, and making the software even better',
alert_yourContrib: 'Your contribution',
alert_noMatterSize: 'no matter the size',
alert_directlySupports: 'directly supports my unpaid efforts to ensure this project remains free and open for all to use',
alert_tyForSupport: 'Thank you for your support',
btnLabel_moreAIextensions: 'More AI Extensions',
btnLabel_rateUs: 'Rate Us',
btnLabel_getSupport: 'Get Support',
btnLabel_checkForUpdates: 'Check for Updates',
btnLabel_update: 'Update',
btnLabel_dismiss: 'Dismiss',
link_viewChanges: 'View changes',
state_enabled: 'enabled',
state_disabled: 'disabled',
state_on: 'on',
state_off: 'off'
}
// LOCALIZE app.msgs for non-English users
if (!env.browser.language.startsWith('en')) {
const localizedMsgs = await new Promise(resolve => {
const msgHostDir = app.urls.assetHost + '/greasemonkey/_locales/',
msgLocaleDir = ( env.browser.language ? env.browser.language.replace('-', '_') : 'en' ) + '/'
let msgHref = msgHostDir + msgLocaleDir + 'messages.json', msgXHRtries = 0
function fetchMsgs() { xhr({ method: 'GET', url: msgHref, onload: handleMsgs })}
function handleMsgs(resp) {
try { // to return localized messages.json
const msgs = JSON.parse(resp.responseText), flatMsgs = {}
for (const key in msgs) // remove need to ref nested keys
if (typeof msgs[key] == 'object' && 'message' in msgs[key])
flatMsgs[key] = msgs[key].message
resolve(flatMsgs)
} catch (err) { // if bad response
msgXHRtries++ ; if (msgXHRtries == 3) return resolve({}) // try original/region-stripped/EN only
msgHref = env.browser.language.includes('-') && msgXHRtries == 1 ? // if regional lang on 1st try...
msgHref.replace(/([^_]+_[^_]+)_[^/]*(\/.*)/, '$1$2') // ...strip region before retrying
: ( msgHostDir + 'en/messages.json' ) // else use default English messages
fetchMsgs()
}
}
fetchMsgs()
})
Object.assign(app.msgs, localizedMsgs)
}
// Init SETTINGS
const config = {}
const settings = {
controls: { // displays top-to-bottom in toolbar menu
autoclear: { type: 'toggle',
label: app.msgs.menuLabel_autoclear, helptip: app.msgs.appDesc },
clearNow: { type: 'action', symbol: '🧹',
label: app.msgs.menuLabel_clearNow, helptip: app.msgs.helptip_clearNow },
toggleHidden: { type: 'toggle',
label: app.msgs.menuLabel_toggleVis, helptip: app.msgs.helptip_toggleVis },
notifDisabled: { type: 'toggle',
label: app.msgs.menuLabel_modeNotifs, helptip: app.msgs.helptip_modeNotifs }
},
load(...keys) {
if (Array.isArray(keys[0])) keys = keys[0] // use 1st array arg, else all comma-separated ones
keys.forEach(key => config[key] = GM_getValue(app.configKeyPrefix + '_' + key, false))
},
save(key, val) { GM_setValue(app.configKeyPrefix + '_' + key, val) ; config[key] = val }
}
settings.load('autoclear', 'notifDisabled', 'toggleHidden')
// Define MENU functions
const menu = {
ids: [], state: {
symbols: ['❌', '✔️'], separator: env.scriptManager.name == 'Tampermonkey' ? ' — ' : ': ',
words: [app.msgs.state_off.toUpperCase(), app.msgs.state_on.toUpperCase()]
},
register() {
// Add toggles
Object.keys(settings.controls).forEach(key => {
const settingIsEnabled = config[key] ^ /disabled|hidden/i.test(key)
const menuLabel = `${ settings.controls[key].symbol || menu.state.symbols[+settingIsEnabled] } `
+ settings.controls[key].label
+ ( settings.controls[key].type == 'toggle' ? menu.state.separator
+ menu.state.words[+settingIsEnabled] : '' )
menu.ids.push(GM_registerMenuCommand(menuLabel, () => {
if (settings.controls[key].type == 'toggle') {
settings.save(key, !config[key]) ; syncConfigToUI({ updatedKey: key })
notify(`${settings.controls[key].label}: ${
menu.state.words[+(config[key] ^ /disabled|hidden/i.test(key))]}`)
} else // Clear Now action
clearChatsAndGoHome()
}, env.scriptManager.supportsTooltips ? { title: settings.controls[key].helptip || ' ' } : undefined))
});
// Add About/Donate entries
['about', 'donate'].forEach(entryType => menu.ids.push(GM_registerMenuCommand(
`${ entryType == 'about' ? '💡' : '💖' }`
+ ` ${app.msgs[`menuLabel_${entryType}`]} ${ entryType == 'about' ? app.msgs.appName : '' }`,
() => modals.open(entryType), env.scriptManager.supportsTooltips ? { title: ' ' } : undefined
)))
},
refresh() {
if (typeof GM_unregisterMenuCommand == 'undefined') return
for (const id of menu.ids) { GM_unregisterMenuCommand(id) } menu.register()
}
}
function updateCheck() {
xhr({
method: 'GET', url: app.urls.update + '?t=' + Date.now(),
headers: { 'Cache-Control': 'no-cache' },
onload: resp => {
// Compare versions, alert if update found
app.latestVer = /@version +(.*)/.exec(resp.responseText)[1]
for (let i = 0 ; i < 4 ; i++) { // loop thru subver's
const currentSubVer = parseInt(app.version.split('.')[i], 10) || 0,
latestSubVer = parseInt(app.latestVer.split('.')[i], 10) || 0
if (currentSubVer > latestSubVer) break // out of comparison since not outdated
else if (latestSubVer > currentSubVer) // if outdated
return modals.open('update', 'available')
}
// Alert to no update found, nav back to About
modals.open('update', 'unavailable')
}})
}
// Define FEEDBACK functions
function notify(msg, pos = '', notifDuration = '', shadow = '') {
if (config.notifDisabled && !msg.includes(app.msgs.menuLabel_modeNotifs)) return
// Strip state word to append colored one later
const foundState = menu.state.words.find(word => msg.includes(word))
if (foundState) msg = msg.replace(foundState, '')
// Show notification
chatgpt.notify(`${app.symbol} ${msg}`, pos, notifDuration, shadow || env.ui.scheme == 'dark' ? '' : 'shadow')
const notif = document.querySelector('.chatgpt-notif:last-child')
// Append styled state word
if (foundState) {
const styledStateSpan = document.createElement('span')
styledStateSpan.style.cssText = `color: ${
foundState == menu.state.words[0] ? '#ef4848 ; text-shadow: rgba(255, 169, 225, 0.44) 2px 1px 5px'
: '#5cef48 ; text-shadow: rgba(255, 250, 169, 0.38) 2px 1px 5px' }`
styledStateSpan.append(foundState) ; notif.append(styledStateSpan)
}
}
// Define MODAL functions
const modals = {
stack: [], // of types of undismissed modals
class: `${app.cssPrefix}-modal`,
alert(title = '', msg = '', btns = '', checkbox = '', width = '') { // generic one from chatgpt.alert()
const alertID = chatgpt.alert(title, msg, btns, checkbox, width),
alert = document.getElementById(alertID).firstChild
this.init(alert) // add classes + starry bg
return alert
},
open(modalType, modalSubType) {
const modal = modalSubType ? this[modalType][modalSubType]() : this[modalType]() // show modal
this.stack.unshift(modalSubType ? `${modalType}_${modalSubType}` : modalType) // add to stack
this.init(modal) // add classes + starry bg
this.observeRemoval(modal, modalType, modalSubType) // to maintain stack for proper nav
},
init(modal) {
if (!this.styles) this.stylize() // to init/append stylesheet
modal.classList.add(this.class) ; modal.parentNode.classList.add(`${this.class}-bg`) // add classes
fillStarryBG(modal) // add starry bg
},
stylize() {
if (!this.styles) {
this.styles = document.createElement('style') ; this.styles.id = `${this.class}-styles`
document.head.append(this.styles)
}
this.styles.innerText = (
`.${this.class} {` // modals
+ 'font-family: -apple-system, system-ui, BlinkMacSystemFont, Segoe UI, Roboto,'
+ 'Oxygen-Sans, Ubuntu, Cantarell, Helvetica Neue, sans-serif ;'
+ 'padding: 20px 25px 24px 25px !important ; font-size: 20px ;'
+ `color: ${ env.ui.scheme == 'dark' ? 'white' : 'black' } !important ;`
+ `background-image: linear-gradient(180deg, ${
env.ui.scheme == 'dark' ? '#99a8a6 -200px, black 200px' : '#b6ebff -296px, white 171px' }) }`
+ `.${this.class} [class*=modal-close-btn] {`
+ 'position: absolute !important ; float: right ; top: 14px !important ; right: 16px !important ;'
+ 'cursor: pointer ; width: 33px ; height: 33px ; border-radius: 20px }'
+ `.${this.class} [class*=modal-close-btn] svg { height: 10px }`
+ `.${this.class} [class*=modal-close-btn] path {`
+ `${ env.ui.scheme == 'dark' ? 'stroke: white ; fill: white' : 'stroke: #9f9f9f ; fill: #9f9f9f' }}`
+ ( env.ui.scheme == 'dark' ? // invert dark mode hover paths
`.${this.class} [class*=modal-close-btn]:hover path { stroke: black ; fill: black }` : '' )
+ `.${this.class} [class*=modal-close-btn]:hover { background-color: #f2f2f2 }` // hover underlay
+ `.${this.class} [class*=modal-close-btn] svg { margin: 11.5px }` // center SVG for hover underlay
+ `.${this.class} a { color: #${ env.ui.scheme == 'dark' ? '00cfff' : '1e9ebb' } !important }`
+ `.${this.class} h2 { font-weight: bold }`
+ `.${this.class} button {`
+ 'font-size: 14px ; text-transform: uppercase ;' // shrink/uppercase labels
+ 'border-radius: 0 !important ;' // square borders
+ 'transition: transform 0.1s ease-in-out, box-shadow 0.1s ease-in-out ;' // smoothen hover fx
+ 'cursor: pointer !important ;' // add finger cursor
+ `border: 1px solid ${ env.ui.scheme == 'dark' ? 'white' : 'black' } !important ;`
+ 'padding: 8px !important ; min-width: 102px }' // resize
+ `.${this.class} button:hover {` // add zoom, re-scheme
+ 'transform: scale(1.055) ; color: black !important ;'
+ `background-color: #${ env.ui.scheme == 'dark' ? '00cfff' : '9cdaff' } !important }`
+ ( !env.browser.isMobile ? `.${this.class} .modal-buttons { margin-left: -13px !important }` : '' )
+ `.about-em { color: ${ env.ui.scheme == 'dark' ? 'white' : 'green' } !important }`
)
},
observeRemoval(modal, modalType, modalSubType) { // to maintain stack for proper nav
const modalBG = modal.parentNode
new MutationObserver(([mutation], obs) => {
mutation.removedNodes.forEach(removedNode => { if (removedNode == modalBG) {
if (modals.stack[0].includes(modalSubType || modalType)) { // new modal not launched so nav back
modals.stack.shift() // remove this modal type from stack 1st
const prevModalType = modals.stack[0]
if (prevModalType) { // open it
modals.stack.shift() // remove type from stack since re-added on open
modals.open(prevModalType)
}
}
obs.disconnect()
}})
}).observe(modalBG.parentNode, { childList: true, subtree: true })
},
about() {
// Show modal
const aboutModal = modals.alert(
`${app.symbol} ${app.msgs.appName}`, // title
`🧠 ${app.msgs.about_author}: ` // msg
+ `<a href="${app.author.url}">${app.msgs.appAuthor}</a> ${app.msgs.about_and}`
+ ` <a href="${app.urls.contributors}">${app.msgs.about_contributors}</a>\n`
+ `🏷️ ${app.msgs.about_version}: <span class="about-em">${app.version}</span>\n`
+ `📜 ${app.msgs.about_openSourceCode}: `
+ `<a href="${app.urls.gitHub}" target="_blank" rel="nopener">`
+ app.urls.gitHub + '</a>\n'
+ `⚡ ${app.msgs.about_poweredBy}: `
+ `<a href="${app.urls.chatgptJS}" target="_blank" rel="noopener">chatgpt.js</a>`
+ ` v${app.chatgptJSver}`,
[ // buttons
function checkForUpdates() { updateCheck() },
function getSupport(){},
function rateUs() {},
function moreAIextensions(){}
], '', 745 // set width
)
// Format text
aboutModal.querySelector('h2').style.cssText = (
'text-align: center ; font-size: 51px ; line-height: 46px ; padding: 15px 0' )
aboutModal.querySelector('p').style.cssText = (
'text-align: center ; overflow-wrap: anywhere ;'
+ `margin: ${ env.browser.isPortrait ? '6px 0 -16px' : '3px 0 29px' }` )
// Hack buttons
aboutModal.querySelectorAll('button').forEach(btn => {
btn.style.cssText = 'height: 58px ; min-width: 136px ; text-align: center'
// Replace link buttons w/ clones that don't dismiss modal
if (/support|rate|extensions/i.test(btn.textContent)) {
const btnClone = btn.cloneNode(true)
btn.parentNode.replaceChild(btnClone, btn) ; btn = btnClone
btn.onclick = () => modals.safeWinOpen(
btn.textContent.includes(app.msgs.btnLabel_getSupport) ? app.urls.support
: btn.textContent.includes(app.msgs.btnLabel_rateUs) ? app.urls.review.greasyFork
: app.urls.relatedExtensions
)
}
// Prepend emoji + localize labels
if (/updates/i.test(btn.textContent))
btn.textContent = `🚀 ${app.msgs.btnLabel_checkForUpdates}`
else if (/support/i.test(btn.textContent))
btn.textContent = `🧠 ${app.msgs.btnLabel_getSupport}`
else if (/rate/i.test(btn.textContent))
btn.textContent = `⭐ ${app.msgs.btnLabel_rateUs}`
else if (/extensions/i.test(btn.textContent))
btn.textContent = `🤖 ${app.msgs.btnLabel_moreAIextensions}`
// Hide Dismiss button
else btn.style.display = 'none' // hide Dismiss button
})
return aboutModal
},
donate() {
// Show modal
const donateModal = modals.alert(
`💖 ${app.msgs.alert_showYourSupport}`, // title
`<p>${app.msgs.appName} ${app.msgs.alert_isOSS}.</p>`
+ `<p>${app.msgs.alert_despiteAffliction} `
+ '<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Long_COVID">'
+ `${app.msgs.alert_longCOVID}</a> `
+ `${app.msgs.alert_since2020}, ${app.msgs.alert_byDonatingResults}.</p>`
+ `<p>${app.msgs.alert_yourContrib}, <b>${app.msgs.alert_noMatterSize}</b>, `
+ `${app.msgs.alert_directlySupports}.</p>`
+ `<p>${app.msgs.alert_tyForSupport}!</p>`
+ '<img src="https://cdn.jsdelivr.net/gh/adamlui/adamlui/images/siggie/'
+ `${ env.ui.scheme == 'dark' ? 'white' : 'black' }.png" `
+ 'style="height: 54px ; margin: 5px 0 -2px 5px"></img>'
+ `<p>—<b><a target="_blank" rel="noopener" href="${app.author.url}">`
+ `${app.msgs.appAuthor}</a></b>, ${app.msgs.about_author.toLowerCase()}</p>`,
[ // buttons
function paypal(){},
function githubSponsors(){},
function cashApp(){},
function rateUs(){}
], '', 478 // set width
)
// Format text
donateModal.querySelectorAll('p').forEach(p => // v-pad text, shrink line height
p.style.cssText = 'padding: 8px 0 ; line-height: 20px')
// Hack buttons
const btns = donateModal.querySelectorAll('button')
btns.forEach((btn, idx) => {
// Replace link buttons w/ clones that don't dismiss modal
if (!/dismiss/i.test(btn.textContent)) {
const btnClone = btn.cloneNode(true)
btn.parentNode.replaceChild(btnClone, btn) ; btn = btnClone
btn.onclick = () => modals.safeWinOpen(
btn.textContent == 'Cash App' ? app.urls.donate.cashApp
: btn.textContent == 'Github Sponsors' ? app.urls.donate.gitHub
: btn.textContent == 'Paypal' ? app.urls.donate.payPal
: app.urls.review.greasyFork
)
}
// Format buttons
if (idx == 0) btn.style.display = 'none' // hide Dismiss button
else {
btn.style.cssText = 'padding: 8px 6px !important ; margin-top: -14px ;'
+ ' width: 107px ; line-height: 14px'
if (idx == btns.length -1) // de-emphasize right-most button
btn.classList.remove('primary-modal-btn')
else if (/rate/i.test(btn.textContent)) // localize 'Rate Us' label
btn.textContent = app.msgs.btnLabel_rateUs
}
})
return donateModal
},
update: {
width: 377,
available() {
// Show modal
const updateAvailModal = modals.alert(`🚀 ${app.msgs.alert_updateAvail}!`, // title
`${app.msgs.alert_newerVer} ${app.msgs.appName} ` // msg
+ `(v${app.latestVer}) ${app.msgs.alert_isAvail}! `
+ '<a target="_blank" rel="noopener" style="font-size: 0.7rem" href="'
+ app.urls.update.replace(/.+\/([^/]+)meta\.js/,
`${app.urls.gitHub}/commits/main/greasemonkey/$1user.js`)
+ `">${app.msgs.link_viewChanges}</a>`,
function update() { // button
modals.safeWinOpen(app.urls.update.replace('meta.js', 'user.js') + '?t=' + Date.now())
}, '', modals.update.width
)
// Localize button labels if needed
if (!env.browser.language.startsWith('en')) {
const updateBtns = updateAvailModal.querySelectorAll('button')
updateBtns[1].textContent = app.msgs.btnLabel_update
updateBtns[0].textContent = app.msgs.btnLabel_dismiss
}
return updateAvailModal
},
unavailable() {
return modals.alert(`${app.msgs.alert_upToDate}!`, // title
`${app.msgs.appName} (v${app.version}) ${app.msgs.alert_isUpToDate}!`, // msg
'', '', modals.update.width
)
}
},
safeWinOpen(url) { open(url, '_blank', 'noopener') } // to prevent backdoor vulnerabilities
}
// Define UI functions
function syncConfigToUI(options) {
if (options?.updatedKey == 'autoclear' && config.autoclear) clearChatsAndGoHome()
if (/autoclear|toggleHidden/.test(options?.updatedKey)) toggles.sidebar.update.state()
menu.refresh() // prefixes/suffixes
}
function getScheme() {
return document.documentElement.className
|| (window.matchMedia?.('(prefers-color-scheme: dark)')?.matches ? 'dark' : 'light')
}
function createStyle(content) {
const style = document.createElement('style')
if (content) style.innerText = content
return style
}
function fillStarryBG(targetNode) { // requires https://assets.aiwebextensions.com/styles/rising-stars/css/<black|white>.min.css
if (targetNode.querySelector('[id*=stars]')) return
const starsDivsContainer = document.createElement('div')
starsDivsContainer.style.cssText = 'position: absolute ; top: 0 ; left: 0 ;' // hug targetNode's top-left corner
+ 'height: 100% ; width: 100% ; border-radius: 15px ; overflow: clip ;' // bound innards exactly by targetNode
+ 'z-index: -1'; // allow interactive elems to be clicked
['sm', 'med', 'lg'].forEach(starSize => {
const starsDiv = document.createElement('div')
starsDiv.id = `${ env.ui.scheme == 'dark' ? 'white' : 'black' }-stars-${starSize}`
starsDivsContainer.append(starsDiv)
})
targetNode.prepend(starsDivsContainer)
}
const toggles = {
sidebar: {
ids: { navicon: `${app.cssPrefix}-toggle-navicon`, knobSpan: `${app.cssPrefix}-toggle-knob-span` },
create() {
this.div = document.createElement('div')
// Create/ID/size/position navicon
const navicon = document.createElement('img') ; navicon.id = this.ids.navicon
navicon.style.cssText = 'width: 1.25rem ; height: 1.25rem ; margin-left: 2px ; margin-right: 4px'
// Create/disable/hide checkbox
const toggleInput = document.createElement('input')
Object.assign(toggleInput, { type: 'checkbox', disabled: true })
toggleInput.style.display = 'none'
// Create/stylize switch
const switchSpan = document.createElement('span')
Object.assign(switchSpan.style, {
position: 'relative', left: `${ env.browser.isMobile ? 169 : !env.ui.firstLink ? 160 : 154 }px`,
bottom: `${ !env.ui.firstLink ? -0.15 : 0 }em`, width: '30px', height: '15px',
backgroundColor: config.autoclear ? '#ccc' : '#AD68FF', // init opposite final color
'-webkit-transition': '.4s', transition: '0.4s', borderRadius: '28px'
})
// Create/stylize knob, append to switch
const knobSpan = document.createElement('span') ; knobSpan.id = toggles.sidebar.ids.knobSpan
Object.assign(knobSpan.style, {
position: 'absolute', left: '3px', bottom: '1.25px',
width: '12px', height: '12px', content: '""', borderRadius: '28px',
transform: config.autoclear ? // init opposite final pos
'translateX(0)' : 'translateX(13px) translateY(0)',
backgroundColor: 'white', '-webkit-transition': '0.4s', transition: '0.4s'
}) ; switchSpan.append(knobSpan)
// Create/stylize/fill label
const toggleLabel = document.createElement('label')
if (!env.ui.firstLink) // add font size/weight since no env.ui.firstLink to borrow from
toggleLabel.style.cssText = 'font-size: 0.875rem, font-weight: 600'
Object.assign(toggleLabel.style, {
marginLeft: `-${ !env.ui.firstLink ? 23 : 41 }px`, // left-shift to navicon
cursor: 'pointer', // add finger cursor on hover
width: `${ env.browser.isMobile ? 201 : 148 }px`, // to truncate overflown text
overflow: 'hidden', textOverflow: 'ellipsis' // to truncate overflown text
})
// Append elements
this.div.append(navicon, toggleInput, switchSpan, toggleLabel)
// Stylize/classify master div
this.div.style.cssText += (
'max-height: 37px ; margin: 2px 0 ; user-select: none ; cursor: pointer'
+ 'flex-grow: unset' // overcome OpenAI .grow
)
if (env.ui.firstLink) { // borrow/assign classes from sidebar elems
const firstIcon = env.ui.firstLink.querySelector('div:first-child'),
firstLabel = env.ui.firstLink.querySelector('div:nth-child(2)')
this.div.classList.add(...env.ui.firstLink.classList, ...(firstLabel?.classList || []))
this.div.querySelector('img')?.classList.add(...(firstIcon?.classList || []))
}
// Update color/state
this.update.color() ; this.update.state() // to opposite init state for animation on 1st load
// Add listeners
this.div.onmouseover = this.div.onmouseout = event =>
this.div.style.setProperty('--item-background-color',
`var(--sidebar-surface-${event.type == 'mouseover' ? 'secondary' : 'primary'})`)
this.div.onclick = () => {
settings.save('autoclear', !toggleInput.checked) ; syncConfigToUI({ updatedKey: 'autoclear' })
notify(`${app.msgs.mode_autoclear}: ${menu.state.words[+config.autoclear]}`)
}
},
insert() {
if (this.status?.startsWith('insert') || document.getElementById(this.ids.navicon)) return
const sidebar = document.querySelectorAll('nav')[env.browser.isMobile ? 1 : 0] ; if (!sidebar) return
this.status = 'inserting' ; if (!this.div) this.create()
sidebar.insertBefore(this.div, sidebar.children[1]) ; this.status = 'inserted'
},
update: {
color() {
const knobSpan = toggles.sidebar.div.querySelector(`#${toggles.sidebar.ids.knobSpan}`),
navicon = toggles.sidebar.div.querySelector(`#${toggles.sidebar.ids.navicon}`)
knobSpan.style.boxShadow = 'rgba(0, 0, 0, .3) 0 1px 2px 0'
+ ( env.ui.scheme == 'dark' ? ', rgba(0, 0, 0, .15) 0 3px 6px 2px' : '' )
navicon.src = `${app.urls.mediaHost}/images/icons/incognito/${
env.ui.scheme == 'dark' ? 'white' : 'black' }/icon32.png?${app.latestAssetCommitHash}`
},
state() {
if (!toggles.sidebar.div) return // since toggle never created = sidebar missing
const toggleLabel = toggles.sidebar.div.querySelector('label'),
toggleInput = toggles.sidebar.div.querySelector('input'),
switchSpan = toggles.sidebar.div.querySelector('span'),
knobSpan = switchSpan.firstChild
toggles.sidebar.div.style.display = config.toggleHidden ? 'none' : 'flex'
toggleInput.checked = config.autoclear
toggleLabel.innerText = `${app.msgs.mode_autoclear} ${
app.msgs['state_' + ( toggleInput.checked ? 'enabled' : 'disabled' )]}`
setTimeout(() => {
switchSpan.style.backgroundColor = toggleInput.checked ? '#ad68ff' : '#ccc'
switchSpan.style.boxShadow = toggleInput.checked ? '2px 1px 9px #d8a9ff' : 'none'
knobSpan.style.transform = `translateX(${ toggleInput.checked ? 13 : 0 }px)`
}, 1) // min delay to trigger transition fx
}
}
}
}
function clearChatsAndGoHome() {
chatgpt.clearChats()
// Hide history from DOM since chatgpt.clearChats() works back-end only (front-end updates on reload otherwise)
new Promise(resolve => setTimeout(resolve, 1000)).then(() => {
document.querySelectorAll('nav ol').forEach(ol => {
ol.previousElementSibling.style.display = 'none' // hide temporal heading
ol.querySelectorAll('li').forEach(li => li.style.display = 'none') // hide chat entry
})
if (!clearChatsAndGoHome.historyObserver) { // monitor sidebar to restore temporal headings on new chats
clearChatsAndGoHome.historyObserver = new MutationObserver(mutations => mutations.forEach(mutation => {
if (mutation.type == 'childList') mutation.addedNodes.forEach(node => {
if (node.tagName == 'LI') node.closest('ol').previousElementSibling.style.display = 'inherit'
})}))
clearChatsAndGoHome.historyObserver.observe(
document.querySelector('nav'), { childList: true, subtree: true })
}
})
chatgpt.startNewChat() // return home from potential ghost chat
notify(app.msgs.notif_chatsCleared, 'bottom-right', 2.5)
}
// Run MAIN routine
menu.register() // create browser toolbar menu
// Init UI props
await Promise.race([chatgpt.isLoaded(), new Promise(resolve => setTimeout(resolve, 5000))]) // initial UI loaded
await chatgpt.sidebar.isLoaded()
env.ui.firstLink = chatgpt.getNewChatLink();
// Add STARS styles
['brs', 'wrs'].forEach(cssType => document.head.append(createStyle(GM_getResourceText(`${cssType}CSS`))))
toggles.sidebar.insert()
// AUTO-CLEAR on first visit if enabled
if (config.autoclear) clearChatsAndGoHome()
// Monitor NODE CHANGES to maintain sidebar toggle visibility
new MutationObserver(() => {
if (!config.toggleHidden && !document.getElementById(toggles.sidebar.ids.navicon)
&& toggles.sidebar.status != 'inserting') {
toggles.sidebar.status = 'missing' ; toggles.sidebar.insert() }
}).observe(document.body, { attributes: true, subtree: true })
// Monitor SCHEME PREF changes to update sidebar toggle + modal colors
new MutationObserver(handleSchemePrefChange).observe( // for site scheme pref changes
document.documentElement, { attributes: true, attributeFilter: ['class'] })
window.matchMedia('(prefers-color-scheme: dark)').addEventListener( // for browser/system scheme pref changes
'change', () => requestAnimationFrame(handleSchemePrefChange))
function handleSchemePrefChange() {
const displayedScheme = getScheme()
if (env.ui.scheme != displayedScheme) {
env.ui.scheme = displayedScheme ; toggles.sidebar.update.color() ; modals.stylize() }
}
// Disable distracting SIDEBAR CLICK-ZOOM effect
if (!document.documentElement.hasAttribute('sidebar-click-zoom-observed')) {
new MutationObserver(mutations => mutations.forEach(({ target }) => {
if (target.closest('[class*=sidebar]') // include sidebar divs
&& !target.id.endsWith('-knob-span') // exclude our toggles.sidebar
&& target.style.transform != 'none' // click-zoom occurred
) target.style.transform = 'none'
})).observe(document.body, { attributes: true, subtree: true, attributeFilter: ['style'] })
document.documentElement.setAttribute('sidebar-click-zoom-observed', true)
}
})()