lrkmusic-ytpro 1.0.0

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.
package/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # lrkmusic-ytpro (npm package source)
2
+
3
+ Yahi folder **single source of truth** hai – isi me edit karo, isi se npm publish karo.
4
+
5
+ ## Development (LRKmusics app ke saath)
6
+
7
+ - Isi folder me **script.js**, **bgplay.js**, **innertube.js** edit karo.
8
+ - **Debug build** run karte hi app inhi files ko use karegi (Gradle auto-copy karke `AppCode/app/src/main/assets/ytpro/` me daal deta hai).
9
+ - Koi alag copy step nahi – sirf is folder me change karo, phir app **Build → Run** (Debug).
10
+
11
+ ## NPM publish (jab sab changes ready hon)
12
+
13
+ 1. **Version badhao** – `package.json` me `"version": "1.0.0"` → `"1.0.1"` (ya jaisa chaho).
14
+ 2. Isi folder me terminal kholo:
15
+ ```bash
16
+ cd "C:\xampp\htdocs\LRKmusics\easytube package published on npm"
17
+ npm login
18
+ npm publish
19
+ ```
20
+ 3. **Release build** lo – app ab npm se **lrkmusic-ytpro** load karegi.
21
+
22
+ ## Package links
23
+
24
+ - npm: https://www.npmjs.com/package/lrkmusic-ytpro
25
+ - Settings: https://www.npmjs.com/settings/lrkassociations_mguide/packages
26
+
27
+ ## Files (4)
28
+
29
+ - **script.js** – main logic (UI, Gemini, download, PIP, etc.)
30
+ - **bgplay.js** – background play (back/home par video band nahi hota – notification chalti rahti hai)
31
+ - **innertube.js** – innertube / player API
32
+ - **package.json** – name, version, main entry
33
+
34
+ ## Feature: Back / Home par video band nahi
35
+
36
+ **bgplay.js** me: jab user watch/shorts se back karke home par aata hai, tab **Android.bgStop()** nahi bulaate. Isse notification aur background service chalte rahenge; band tab hi hoga jab YouTube screen close karenge ya notification se stop karenge.
package/bgplay.js ADDED
@@ -0,0 +1,273 @@
1
+ /***** lrkmusic-ytpro bgplay *****
2
+ Author: Satya Prakash
3
+ Version: 1.0.0
4
+ */
5
+
6
+ if (typeof MediaMetadata === 'undefined') {
7
+ window.MediaMetadata = class {
8
+ constructor(data = {}) {
9
+ this.title = data.title || '';
10
+ this.artist = data.artist || '';
11
+ this.album = data.album || '';
12
+ this.artwork = data.artwork || [];
13
+ }
14
+ };
15
+
16
+ }
17
+
18
+
19
+
20
+ if (!('mediaSession' in navigator)) {
21
+
22
+ window.handlers = {};
23
+ window.serviceRunning=false;
24
+
25
+
26
+
27
+
28
+ let _state = 'none';
29
+ let _metadata = null;
30
+
31
+ Object.defineProperty(navigator, 'mediaSession', {
32
+ value: {},
33
+ configurable: true
34
+ });
35
+
36
+ Object.defineProperty(navigator.mediaSession, 'metadata', {
37
+ get() {
38
+ return _metadata;
39
+ },
40
+ set(value) {
41
+ //console.log("metadata set:", value);
42
+ bgPlay(value);
43
+ _metadata = value;
44
+ },
45
+ configurable: true
46
+ });
47
+
48
+
49
+
50
+
51
+ navigator.mediaSession.setActionHandler = (action, handler) => {
52
+
53
+ if (typeof handler === 'function') {
54
+ handlers[action] = handler;
55
+ }
56
+
57
+ //console.log(action,handler)
58
+
59
+
60
+ };
61
+
62
+
63
+
64
+
65
+
66
+
67
+ Object.defineProperty(navigator.mediaSession, 'playbackState', {
68
+ get() {
69
+ return _state;
70
+ },
71
+ set(value) {
72
+
73
+ //console.log("Custom playbackState set to:", value);
74
+
75
+
76
+ _state = value;
77
+
78
+
79
+ var ytproAud = getMediaElement();
80
+
81
+ if (value === 'playing' && ytproAud) {
82
+ setTimeout(()=>{Android.bgPlay(ytproAud.currentTime*1000);},100);
83
+ } else if (value === 'paused' && (pauseAllowed || PIPause) && ytproAud) {
84
+ setTimeout(()=>{Android.bgPause(ytproAud.currentTime*1000);},100);
85
+ }
86
+ // Do NOT call bgStop() when user goes back to home – keep video running like YouTube app.
87
+ // Service stops only when YouTube screen is closed (app onDestroy) or user stops from notification.
88
+ // Removed: else if(value === "none" && !on watch/shorts){ Android.bgStop(); serviceRunning=false; }
89
+
90
+
91
+
92
+ },
93
+ configurable: true
94
+ });
95
+
96
+
97
+
98
+ } else {
99
+ window.handlers = window.handlers || {};
100
+ window.serviceRunning = window.serviceRunning || false;
101
+ try {
102
+ var origSet = navigator.mediaSession.setActionHandler;
103
+ if (origSet) {
104
+ navigator.mediaSession.setActionHandler = function(action, handler) {
105
+ if (typeof handler === 'function') window.handlers[action] = handler;
106
+ return origSet.call(navigator.mediaSession, action, handler);
107
+ };
108
+ }
109
+ var desc = Object.getOwnPropertyDescriptor(navigator.mediaSession, 'metadata');
110
+ if (desc && desc.set) {
111
+ var origMetaSet = desc.set;
112
+ Object.defineProperty(navigator.mediaSession, 'metadata', {
113
+ get: desc.get,
114
+ set: function(v) { origMetaSet.call(navigator.mediaSession, v); bgPlay(v); },
115
+ configurable: true, enumerable: desc.enumerable
116
+ });
117
+ }
118
+ } catch (e) {}
119
+ }
120
+
121
+
122
+
123
+
124
+
125
+
126
+
127
+ function getMediaElement() {
128
+ var el = document.getElementsByClassName('video-stream')[0] || document.querySelector('video') || document.querySelector('audio');
129
+ return el || null;
130
+ }
131
+
132
+ async function bgPlay(info){
133
+
134
+
135
+ if(!(window.location.href.indexOf("youtube.com/watch") > -1 || window.location.href.indexOf("youtube.com/shorts") > -1 || window.location.href.indexOf("music.youtube.com") > -1 )) return;
136
+
137
+
138
+ if(!info) return;
139
+
140
+
141
+ var ytproAud = getMediaElement();
142
+
143
+
144
+ if(!ytproAud) return;
145
+
146
+
147
+ var iconBase64="iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=";
148
+
149
+
150
+ var img = new Image();
151
+ img.crossOrigin="anonymous";
152
+ img.src=info?.artwork?.[0]?.src;
153
+
154
+
155
+ var canvas = document.createElement('canvas');
156
+ canvas.style.width = "1600px";
157
+ canvas.style.height = "900px";
158
+ canvas.style.background="black";
159
+ var context = canvas.getContext('2d');
160
+
161
+ canvas.width = 160;
162
+ canvas.height = 90;
163
+
164
+ //var z=performance.now();
165
+
166
+
167
+ await new Promise((res,rej)=>{
168
+ img.onload=()=>res();
169
+ });
170
+
171
+
172
+ try{
173
+ context.drawImage(img, 0,0 ,160,90);
174
+ iconBase64 = canvas.toDataURL('image/png',1.0);
175
+ }catch{}
176
+
177
+
178
+
179
+
180
+
181
+
182
+
183
+
184
+
185
+
186
+
187
+
188
+ if(window.serviceRunning){
189
+ setTimeout(()=>{Android.bgUpdate(iconBase64.replace("data:image/png;base64,", ""),info.title,info.artist,ytproAud.duration*1000);},50);
190
+ setTimeout(()=>{Android.bgPlay(ytproAud.currentTime*1000);},100);
191
+ }
192
+ else{
193
+ window.serviceRunning=true;
194
+ setTimeout(()=>{Android.bgStart(iconBase64.replace("data:image/png;base64,", ""),info.title,info.artist,ytproAud.duration*1000);},50);
195
+ setTimeout(()=>{Android.bgPlay(ytproAud.currentTime*1000);},100);
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
+ /*When user hits the notification*/
228
+ function seekTo(t){
229
+ handlers.seekto({ seekTime: t/1000 });
230
+ }
231
+
232
+ /*Daamm , its play*/
233
+ function playVideo(){
234
+
235
+
236
+ if(!pauseAllowed){
237
+ window.PIPause = false;
238
+ navigator.mediaSession.playbackState = 'playing';
239
+ }
240
+
241
+ handlers.play();
242
+ }
243
+
244
+ /*Daamm , its pause*/
245
+ function pauseVideo(){
246
+
247
+
248
+
249
+ if(!pauseAllowed){
250
+ window.PIPause=true;
251
+ navigator.mediaSession.playbackState = 'paused';
252
+ }
253
+ handlers.pause();
254
+
255
+
256
+
257
+
258
+ }
259
+
260
+
261
+
262
+ /*Alexa , play da next song*/
263
+ async function playNext(){
264
+ handlers.nexttrack();
265
+ }
266
+
267
+
268
+
269
+
270
+ /*Alexa , play the f**ng song once again */
271
+ function playPrev(){
272
+ handlers.previoustrack();
273
+ }
package/innertube.js ADDED
@@ -0,0 +1,393 @@
1
+ /***** lrkmusic-ytpro innertube *****
2
+ Author: Satya Prakash
3
+ Version: 1.0.0
4
+ */
5
+
6
+ import {BG} from 'https://youtube.com/ytpro_cdn/esm/bgutils-js@3.2.0/es2022/bgutils-js.bundle.mjs';
7
+ import "https://youtube.com/ytpro_cdn/esm/acorn@8.15.0/es2022/acorn.mjs";
8
+ import Jinter from 'https://youtube.com/ytpro_cdn/esm/jintr@3.3.1/es2022/jintr.bundle.mjs';
9
+ import {Player,Innertube, ProtoUtils, UniversalCache, Utils } from 'https://youtube.com/ytpro_cdn/npm/youtubei.js@13.4.0/bundle/browser.min.js';
10
+
11
+
12
+
13
+ function write(x){
14
+
15
+ if(typeof x == "object"){
16
+ x=JSON.stringify(x,null,2)
17
+ }
18
+ var ytproDownDiv=document.getElementById("downytprodiv");
19
+
20
+ ytproDownDiv.innerHTML=x;
21
+ }
22
+
23
+
24
+
25
+
26
+
27
+ var cver="19.35.36";
28
+ var player_id;
29
+ var poToken,visitorData;
30
+ var sig_timestamp,nsig_sc,sig_sc;
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+ async function getPo(identifier){
39
+ const requestKey = 'O43z0dpjhgX20SCx4KAo';
40
+
41
+ const bgConfig = {
42
+ fetch: (input, init) => fetch(input, init),
43
+ globalObj: window,
44
+ requestKey,
45
+ identifier
46
+ };
47
+
48
+ const bgChallenge = await BG.Challenge.create(bgConfig);
49
+
50
+ if (!bgChallenge)
51
+ throw new Error('Could not get challenge');
52
+
53
+ const interpreterJavascript = bgChallenge.interpreterJavascript.privateDoNotAccessOrElseSafeScriptWrappedValue;
54
+
55
+ if (interpreterJavascript) {
56
+ new Function(interpreterJavascript)();
57
+ } else throw new Error('Could not load VM');
58
+
59
+ const poTokenResult = await BG.PoToken.generate({
60
+ program: bgChallenge.program,
61
+ globalName: bgChallenge.globalName,
62
+ bgConfig
63
+ });
64
+
65
+ return poTokenResult.poToken;
66
+
67
+ }
68
+
69
+
70
+
71
+
72
+
73
+
74
+
75
+
76
+ async function getDeciphers(){
77
+
78
+
79
+ return new Promise(async (resolve,reject)=>{
80
+
81
+
82
+
83
+ var scripts = document.getElementsByTagName('script');
84
+ for(var i=0;i<scripts.length;i++){
85
+ if(scripts[i].src.indexOf("/base.js") > 0){
86
+ player_id=scripts[i].src.match("(?<=player\/).*(?=\/player)");
87
+ }
88
+ }
89
+
90
+
91
+
92
+ visitorData = ProtoUtils.encodeVisitorData(Utils.generateRandomString(11), Math.floor(Date.now() / 1000));
93
+
94
+ write("Fetching PoTokens...");
95
+
96
+ const coldStartToken = BG.PoToken.generatePlaceholder(visitorData);
97
+ await getPo(visitorData).then((webPo) => poToken = webPo);
98
+
99
+
100
+
101
+ write("Fetching Player JS...");
102
+
103
+ var player_js=await fetch(`https://www.youtube.com/s/player/${player_id}/player_ias.vflset/en_US/base.js`).then(x => x.text());
104
+
105
+ const ast = Jinter.parseScript(player_js, { ecmaVersion: 'latest', ranges: true });
106
+
107
+
108
+
109
+ sig_timestamp = Player.extractSigTimestamp(player_js);
110
+ const global_variable = Player.extractGlobalVariable(player_js, ast);
111
+ sig_sc = Player.extractSigSourceCode(player_js, global_variable);
112
+ nsig_sc = Player.extractNSigSourceCode(player_js, ast, global_variable);
113
+
114
+
115
+ //write(nsig_sc)
116
+ //write(sig_sc)
117
+
118
+ write("Deciphering Scripts...");
119
+
120
+
121
+
122
+ const player = await Player.fromSource(player_id, sig_timestamp, null, sig_sc, nsig_sc);
123
+
124
+ //write(JSON.stringify(player,null,2))
125
+
126
+
127
+
128
+
129
+ write("Deciphered Scripts")
130
+
131
+ resolve("done");
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
+ function decipherUrl(url){
157
+
158
+ const args = new URLSearchParams(url);
159
+ const url_components = new URL(args.get('url') || url);
160
+
161
+
162
+
163
+ if(args.get('s') != null){
164
+ const signature = Utils.Platform.shim.eval(sig_sc, {
165
+ sig: args.get('s')
166
+ });
167
+ const sp = args.get('sp');
168
+ if(sp) {
169
+ url_components.searchParams.set(sp, signature);
170
+ } else {
171
+ url_components.searchParams.set('signature', signature);
172
+ }
173
+ }
174
+
175
+
176
+
177
+
178
+ const n = url_components.searchParams.get('n');
179
+ if(n != null){
180
+ var nsig = Utils.Platform.shim.eval(nsig_sc, {
181
+ nsig: n
182
+ });
183
+ url_components.searchParams.set('n', nsig);
184
+ }
185
+
186
+
187
+ url_components.searchParams.set('pot',poToken);
188
+ url_components.searchParams.set('cver',cver);
189
+ return url_components.toString();
190
+ }
191
+
192
+
193
+
194
+
195
+
196
+
197
+
198
+
199
+
200
+
201
+ window.getDownloadStreams=async ()=>{
202
+
203
+
204
+ write("Getting Deciphers...");
205
+
206
+ await getDeciphers();
207
+
208
+ write("Fethcing Video Info...");
209
+
210
+
211
+ var id="";
212
+
213
+ if(window.location.pathname.indexOf("shorts") > -1){
214
+ id=window.location.pathname.substr(8,window.location.pathname.length);
215
+ }
216
+ else{
217
+ id=new URLSearchParams(window.location.search).get("v");
218
+ }
219
+
220
+ var body={
221
+ "videoId": id,
222
+ "racyCheckOk": true,
223
+ "contentCheckOk": true,
224
+ "playbackContext": {
225
+ "contentPlaybackContext": {
226
+ "vis": 0,
227
+ "splay": false,
228
+ "lactMilliseconds": "-1",
229
+ "signatureTimestamp": sig_timestamp
230
+ }
231
+ },
232
+ "serviceIntegrityDimensions": {
233
+ "poToken": poToken
234
+ },
235
+ "context": {
236
+ "client": {
237
+ "hl": "en",
238
+ "gl": "US",
239
+ "remoteHost": "",
240
+ "screenDensityFloat": 1,
241
+ "screenHeightPoints": 7680,
242
+ "screenPixelDensity": 1,
243
+ "screenWidthPoints": 4320,
244
+ "visitorData": visitorData,
245
+ "clientName": "ANDROID",
246
+ "clientVersion": cver,
247
+ "osName": "Android",
248
+ "osVersion": "12",
249
+ "userAgent": "com.google.android.youtube/19.35.36(Linux; U; Android 13; en_US; SM-S908E Build/TP1A.220624.014) gzip",
250
+ //"platform": "DESKTOP",
251
+ "clientFormFactor": "UNKNOWN_FORM_FACTOR",
252
+ "userInterfaceTheme": "USER_INTERFACE_THEME_LIGHT",
253
+ "timeZone": "Asia/Calcutta",
254
+ "originalUrl": "https://www.youtube.com",
255
+ "deviceMake": "",
256
+ "deviceModel": "",
257
+ //"browserName": "Chrome",
258
+ //"browserVersion": "125.0.0.0",
259
+ "utcOffsetMinutes": 330,
260
+ "memoryTotalKbytes": "8000000",
261
+ /*"mainAppWebInfo": {
262
+ "graftUrl": "https://www.youtube.com",
263
+ "pwaInstallabilityStatus": "PWA_INSTALLABILITY_STATUS_UNKNOWN",
264
+ "webDisplayMode": "WEB_DISPLAY_MODE_BROWSER",
265
+ "isWebNativeShareAvailable": true
266
+ }*/
267
+ },
268
+ "user": {
269
+ "enableSafetyMode": false,
270
+ "lockedSafetyMode": false
271
+ },
272
+ "request": {
273
+ "useSsl": true,
274
+ "internalExperimentFlags": []
275
+ }
276
+ }
277
+ }
278
+
279
+
280
+
281
+
282
+ var info=await fetch("https://m.youtube.com/youtubei/v1/player?prettyPrint=false",{
283
+ method:"POST",
284
+ body:JSON.stringify(body)
285
+ }).then((res)=>res.json());
286
+
287
+
288
+
289
+
290
+ handleDownloadStreams(info);
291
+
292
+
293
+
294
+
295
+ }
296
+
297
+
298
+
299
+
300
+ function handleDownloadStreams(info){
301
+ console.log(info);
302
+
303
+
304
+
305
+
306
+ var ytproDownDiv=document.getElementById("downytprodiv");
307
+
308
+ var thumb=info?.videoDetails?.thumbnail?.thumbnails;
309
+ var vids=info?.streamingData?.formats;
310
+ var avids=info?.streamingData?.adaptiveFormats;
311
+ var cap=info?.captions?.playerCaptionsTracklistRenderer?.captionTracks;
312
+ var t=info?.videoDetails?.title.replaceAll("|","").replaceAll("\\","").replaceAll("?","").replaceAll("*","").replaceAll("<","").replaceAll("/","").replaceAll(":","").replaceAll('"',"").replaceAll(">","").replaceAll("'","");
313
+ ytproDownDiv.innerHTML=`<style>#downytprodiv a{text-decoration:none;} #downytprodiv li{list-style:none; display:flex;align-items:center;justify-content:center;border-radius:25px;padding:8px;background:${d};margin:5px;margin-top:8px}</style>`;
314
+
315
+
316
+
317
+ ytproDownDiv.innerHTML+="Select Available Formats<ul id='listurl'>";
318
+
319
+ for(var x in vids){
320
+
321
+ var url=vids[x].url;
322
+
323
+ ytproDownDiv.innerHTML+=`<li data-ytprotit="${t}" onclick="YTDownVid(this,'.mp4')" data-ytprourl="${url}">
324
+ ${downBtn}<span style="margin-left:10px;" >${vids[x].qualityLabel} ${formatFileSize(((vids[x].bitrate*(vids[x].approxDurationMs/1000))/8))} </span></li>` ;
325
+ }
326
+
327
+
328
+ ytproDownDiv.innerHTML+=`<li id="showAdaptives" onclick="showHideAdaptives()" style="min-height:20px;border-radius:5px">
329
+ Show Adaptive Formats (No Audio)
330
+ <span style="margin-left:10px;" >
331
+ <svg style="margin-top:5px" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="${c}" viewBox="0 0 18 18">
332
+ <path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708"/>
333
+ </svg>
334
+ </span>
335
+ </li>` ;
336
+
337
+
338
+ for(x in avids){
339
+ if(!(avids[x].mimeType.indexOf("audio") > -1)){
340
+ var url=avids[x].url;
341
+ ytproDownDiv.innerHTML+=`<li data-ytprotit="${t}" class="adpFormats" style="display:none;" onclick="YTDownVid(this,'.mp4')" data-ytprourl="${url}">
342
+ ${downBtn}<span style="margin-left:10px;" >${avids[x].qualityLabel} ${formatFileSize(avids[x].contentLength)}
343
+ </span></li>` ;
344
+ }
345
+ }
346
+
347
+
348
+ for(x in avids){
349
+ if(avids[x].mimeType.indexOf("audio") > -1){
350
+ var url=avids[x].url;
351
+ ytproDownDiv.innerHTML+=`<li data-ytprotit="${t}" onclick="YTDownVid(this,'.mp3')" data-ytprourl="${url}">
352
+ ${downBtn}<span style="margin-left:10px;" >Audio ${avids[x]?.audioTrack?.displayName || ""} | ${avids[x].audioQuality.replace("AUDIO_QUALITY_","")}${formatFileSize(avids[x].contentLength)}
353
+ </span></li>` ;
354
+ }
355
+ }
356
+
357
+
358
+
359
+ ytproDownDiv.innerHTML+="<br>Thumbnails<br><br><style>.thu{height:80px;border-radius:5px;}.thu img{max-height:97%;max-width:70%;border-radius:10px;border:1px solid silver;}</style>";
360
+ for(x in thumb){
361
+ ytproDownDiv.innerHTML+=`<li data-ytprotit="${t+Date.now()}" onclick="YTDownVid(this,'.png')" class="thu" data-ytprourl="${thumb[x].url}">
362
+ <img src="${thumb[x].url}"><br>
363
+ <span style="margin-left:30px;display:flex;align-items:center;justify-content:center;" >${downBtn}<span style="margin-left:10px;" >${thumb[x].height} &#x2715; ${thumb[x].width}
364
+ </span></span></li>` ;
365
+ }
366
+
367
+ if(cap && cap.length){
368
+ ytproDownDiv.innerHTML+=`<br>Captions<br><br><style>cp{width:100%;height:auto;padding-bottom:8px;}c{height:45px;width:50px;padding-top:5px;background:${d};border-radius:10px;margin-left:10px;display:block}</style>`;
369
+ for(var x in cap){
370
+ cap[x].baseUrl = cap[x].baseUrl.replace("&fmt=srv3","");
371
+
372
+
373
+ ytproDownDiv.innerHTML+=`<cp>
374
+ <span style="width:100px;text-align:left">${cap[x]?.name?.runs[0]?.text}</span>
375
+ <br><br>
376
+ <div style="position:absolute;right:10px;display:flex">
377
+ <c onclick="downCap('${cap[x].baseUrl}&fmt=sbv','${t}.txt')">${downBtn} <br>.txt</c>
378
+ <c onclick="downCap('${cap[x].baseUrl}&fmt=srt','${t}.srt')">${downBtn} <br>.srt</c>
379
+ <c onclick="downCap('${cap[x].baseUrl}','${t}.xml')" >${downBtn} <br>.xml</c>
380
+ <c onclick="downCap('${cap[x].baseUrl}&fmt=vtt','${t}.vtt')">${downBtn} <br>.vtt</c>
381
+ <c onclick="downCap('${cap[x].baseUrl}&fmt=srv1','${t}.srv1')">${downBtn} <br>.srv1</c><c onclick="downCap('${cap[x].baseUrl}&fmt=ttml','${t}.ttml')">${downBtn} <br>.ttml</c></div>
382
+ <br>
383
+ </cp>
384
+ <br><br>
385
+ <br><br>
386
+ `;
387
+ }
388
+ }
389
+
390
+
391
+
392
+
393
+ }
package/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "lrkmusic-ytpro",
3
+ "version": "1.0.0",
4
+ "description": "you can find the source code at",
5
+ "main": "script.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "republish": "npm version patch && npm publish"
9
+ },
10
+ "keywords": [],
11
+ "author": "Satya Prakash",
12
+ "license": "ISC",
13
+ "type": "commonjs",
14
+ "publishConfig": {
15
+ "access": "public"
16
+ }
17
+ }