1
+ import { UfsGlobal } from "./content-scripts/ufs_global.js" ;
1
2
import { BADGES } from "./helpers/badge.js" ;
2
3
3
4
export default {
@@ -7,60 +8,35 @@ export default {
7
8
vi : "Tải video/audio youtube" ,
8
9
} ,
9
10
description : {
10
- en : "Bypass age restriction, without login" ,
11
- vi : "Tải cả video giới hạn độ tuổi, không cần đăng nhập" ,
11
+ en : `Bypass age restriction, without login
12
+ <ul>
13
+ <li>Click once to download current video</li>
14
+ <li>Enable autorun to render download button</li>
15
+ </ul>` ,
16
+ vi : `Tải cả video giới hạn độ tuổi, không cần đăng nhập
17
+ <ul>
18
+ <li>Bấm 1 lần để tải video hiện tại</li>
19
+ <li>Bật tự chạy để hiển thị nút tải</li>
20
+ </ul>` ,
21
+ img : "/scripts/youtube_downloadVideo.png" ,
12
22
} ,
13
- badges : [ BADGES . hot ] ,
23
+ badges : [ BADGES . new ] ,
24
+
25
+ whiteList : [ "https://*.youtube.com/*" ] ,
14
26
15
27
contentScript : {
16
28
onClick : function ( ) {
17
- let options = [
18
- {
19
- name : "y2mate.com" ,
20
- func : ( url ) => url . replace ( "youtube.com" , "youtubepp.com" ) ,
21
- } ,
22
- {
23
- name : "yt1s.com" ,
24
- func : ( url ) => "https://yt1s.com/vi/youtube-to-mp4?q=" + url ,
25
- } ,
26
- {
27
- name : "yt5s.com" ,
28
- func : ( url ) => url . replace ( "youtube.com" , "youtube5s.com" ) ,
29
- } ,
30
- {
31
- name : "tubemp3.to" ,
32
- func : ( url ) => "https://tubemp3.to/" + url ,
33
- } ,
34
- {
35
- name : "10downloader.com" ,
36
- func : ( url ) => "https://10downloader.com/download?v=" + url ,
37
- } ,
38
- {
39
- name : "9xbuddy.com" ,
40
- func : ( url ) => "https://9xbuddy.com/process?url=" + url ,
41
- } ,
42
- {
43
- name : "getlinks.vip" ,
44
- func : ( url ) =>
45
- "https://getlinks.vip/vi/youtube/" + getIdFromYoutubeURL ( url ) ,
46
- } ,
47
- {
48
- name : "ymp4.com" ,
49
- func : ( url ) => "https://ymp4.download/en50/?url=" + url ,
50
- } ,
51
- ] ;
52
-
53
29
let choose = prompt (
54
30
"Tải video youtube: \n\n" +
55
- options . map ( ( _ , i ) => `${ i } : ${ _ . name } ` ) . join ( "\n" ) +
31
+ providers . map ( ( _ , i ) => `${ i } : ${ _ . name } ` ) . join ( "\n" ) +
56
32
"\n\nNhập lựa chọn:" ,
57
33
0
58
34
) ;
59
35
60
- if ( choose != null && choose >= 0 && choose < options . length ) {
36
+ if ( choose != null && choose >= 0 && choose < providers . length ) {
61
37
let url = prompt ( "Nhập link youtube:" , location . href ) ;
62
38
if ( url ) {
63
- url = options [ choose ] . func ( url ) ;
39
+ url = providers [ choose ] . func ( url ) ;
64
40
let myWin = window . open (
65
41
url ,
66
42
"Download Youtube Video" ,
@@ -69,12 +45,140 @@ export default {
69
45
}
70
46
}
71
47
} ,
48
+
49
+ onDocumentIdle : ( ) => {
50
+ const downloadIcon = `
51
+ <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" focusable="false" style="pointer-events:none;display:inherit;width:100%;height:100%;">
52
+ <path d="M17 18v1H6v-1h11zm-.5-6.6-.7-.7-3.8 3.7V4h-1v10.4l-3.8-3.8-.7.7 5 5 5-4.9z"></path>
53
+ </svg>` ;
54
+
55
+ injectCss ( ) ;
56
+
57
+ let intervalId = setInterval ( function ( ) {
58
+ const container = document . querySelector ( "#above-the-fold #title > h1" ) ;
59
+ if ( ! container ) return ;
60
+
61
+ clearInterval ( intervalId ) ;
62
+
63
+ document . addEventListener ( "click" , ( e ) => {
64
+ const el = document . querySelector ( "#ufs-ytDownloadBtn__dropdown" ) ;
65
+ if ( e . target !== el || ( el && el . style . display === "flex" ) )
66
+ el . style . display = "none" ;
67
+ } ) ;
68
+
69
+ const links = providers . map (
70
+ ( provider ) => /* html */ `
71
+ <a data-provider="${ provider . name } " class="ufs-ytDownloadVideo__btn">
72
+ ${ provider . name }
73
+ </a>`
74
+ ) ;
75
+
76
+ const div = document . createElement ( "div" ) ;
77
+ div . id = "ufs-ytDownloadBtn__container" ;
78
+ div . innerHTML = /* html */ `
79
+ <button
80
+ class="yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-leading"
81
+ style="position:relative; margin:6px 0;"
82
+ >
83
+ <div class="yt-spec-button-shape-next__icon">
84
+ ${ downloadIcon }
85
+ </div>
86
+
87
+ <div class="yt-spec-button-shape-next__button-text-content">
88
+ <span class="yt-core-attributed-string yt-core-attributed-string--white-space-no-wrap" role="text">
89
+ Tải video
90
+ </span>
91
+ </div>
92
+
93
+ <div id="ufs-ytDownloadBtn__dropdown" class="ufs-ytDownloadVideo__dropdown">
94
+ ${ links . join ( "" ) }
95
+ </div>
96
+ </button>` ;
97
+
98
+ const button = div . querySelector ( "button" ) ;
99
+ button . addEventListener ( "click" , ( e ) => {
100
+ e . stopPropagation ( ) ;
101
+ const el = document . querySelector ( "#ufs-ytDownloadBtn__dropdown" ) ;
102
+ if ( ! el ) return ;
103
+ el . style . display = el . style . display == "flex" ? "none" : "flex" ;
104
+ } ) ;
105
+
106
+ const options = div . querySelectorAll ( "a" ) ;
107
+ options . forEach ( ( option ) => {
108
+ option . addEventListener ( "click" , ( e ) => {
109
+ e . stopPropagation ( ) ;
110
+ const providerName = option . getAttribute ( "data-provider" ) ;
111
+ const provider = providers . find ( ( p ) => p . name === providerName ) ;
112
+ if ( ! provider ) return ;
113
+ const url = provider . func ( window . location . href ) ;
114
+ window . open ( url , "_blank" ) ;
115
+ } ) ;
116
+ } ) ;
117
+
118
+ container . insertAdjacentElement ( "afterend" , div ) ;
119
+ } , 500 ) ;
120
+ } ,
72
121
} ,
73
122
} ;
74
123
75
124
// https://stackoverflow.com/a/8260383/11898496
76
125
export function getIdFromYoutubeURL ( url ) {
77
- let regExp = / .* (?: y o u t u .b e \/ | v \/ | u \/ \w \/ | e m b e d \/ | w a t c h \? v = ) ( [ ^ # \& \? ] * ) .* / ;
78
- let match = url . match ( regExp ) ;
126
+ const regExp = / .* (?: y o u t u .b e \/ | v \/ | u \/ \w \/ | e m b e d \/ | w a t c h \? v = ) ( [ ^ # \& \? ] * ) .* / ;
127
+ const match = url . match ( regExp ) ;
79
128
return match && match [ 1 ] . length == 11 ? match [ 1 ] : false ;
80
129
}
130
+
131
+ const providers = [
132
+ {
133
+ name : "y2mate.com" ,
134
+ func : ( url ) => url . replace ( "youtube" , "youtubepp" ) ,
135
+ } ,
136
+ {
137
+ name : "yt5s.com" ,
138
+ func : ( url ) => url . replace ( "youtube" , "youtube5s" ) ,
139
+ } ,
140
+ {
141
+ name : "yt1s.com" ,
142
+ func : ( url ) => "https://yt1s.com/vi/youtube-to-mp4?q=" + url ,
143
+ } ,
144
+ {
145
+ name : "tubemp3.to" ,
146
+ func : ( url ) => "https://tubemp3.to/" + url ,
147
+ } ,
148
+ {
149
+ name : "10downloader.com" ,
150
+ func : ( url ) => "https://10downloader.com/download?v=" + url ,
151
+ } ,
152
+ {
153
+ name : "9xbuddy.com" ,
154
+ func : ( url ) => "https://9xbuddy.com/process?url=" + url ,
155
+ } ,
156
+ {
157
+ name : "ymp4.com" ,
158
+ func : ( url ) => "https://ymp4.download/?url=" + url ,
159
+ } ,
160
+ {
161
+ name : "savefrom.net" ,
162
+ func : ( url ) => url . replace ( "youtube" , "ssyoutube" ) ,
163
+ } ,
164
+ {
165
+ name : "10downloader.com" ,
166
+ func : ( url ) => url . replace ( "youtube" , "000tube" ) ,
167
+ } ,
168
+ {
169
+ name : "getlinks.vip" ,
170
+ func : ( url ) =>
171
+ "https://getlinks.vip/vi/youtube/" + getIdFromYoutubeURL ( url ) ,
172
+ } ,
173
+ ] ;
174
+
175
+ function injectCss (
176
+ path = "/scripts/youtube_downloadVideo.css" ,
177
+ id = "ufs-yt_downloadVideo-css"
178
+ ) {
179
+ if ( ! document . querySelector ( "#" + id ) ) {
180
+ UfsGlobal . Extension . getURL ( path ) . then ( ( url ) => {
181
+ UfsGlobal . DOM . injectCssFile ( url , id ) ;
182
+ } ) ;
183
+ }
184
+ }
0 commit comments