@oxymoron.13/tizentube-s95b 0.2.0 → 0.2.2

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 (84) hide show
  1. package/README.md +42 -49
  2. package/S95B-CHANGES.txt +3 -9
  3. package/dist/userScript.js +2 -2
  4. package/package.json +5 -11
  5. package/UPSTREAM-README.md +0 -42
  6. package/mods/config.js +0 -117
  7. package/mods/domrect-polyfill.js +0 -104
  8. package/mods/features/adblock.js +0 -584
  9. package/mods/features/autoFrameRate.js +0 -42
  10. package/mods/features/enableFeatures.js +0 -19
  11. package/mods/features/moreSubtitles.js +0 -378
  12. package/mods/features/pictureInPicture.js +0 -198
  13. package/mods/features/preferredVideoQuality.js +0 -101
  14. package/mods/features/s95bCodec.js +0 -45
  15. package/mods/features/s95bI18n.js +0 -34
  16. package/mods/features/s95bMenu.js +0 -223
  17. package/mods/features/sponsorblock.js +0 -437
  18. package/mods/features/standaloneUserscript.js +0 -107
  19. package/mods/features/updater.js +0 -119
  20. package/mods/features/userAgentSpoofing.js +0 -73
  21. package/mods/features/videoQueuing.js +0 -64
  22. package/mods/package-lock.json +0 -2321
  23. package/mods/package.json +0 -33
  24. package/mods/resolveCommand.js +0 -376
  25. package/mods/rollup.config.js +0 -41
  26. package/mods/spatial-navigation-polyfill.js +0 -1756
  27. package/mods/tiny-sha256.js +0 -99
  28. package/mods/translations/i18nResources.js +0 -11
  29. package/mods/translations/index.js +0 -18
  30. package/mods/translations/language-names.js +0 -981
  31. package/mods/translations/resources/ar.json +0 -308
  32. package/mods/translations/resources/az.json +0 -308
  33. package/mods/translations/resources/bs.json +0 -308
  34. package/mods/translations/resources/cs.json +0 -308
  35. package/mods/translations/resources/de.json +0 -308
  36. package/mods/translations/resources/dk.json +0 -308
  37. package/mods/translations/resources/el.json +0 -308
  38. package/mods/translations/resources/en.json +0 -308
  39. package/mods/translations/resources/es-419.json +0 -308
  40. package/mods/translations/resources/es.json +0 -308
  41. package/mods/translations/resources/fi-FI.json +0 -308
  42. package/mods/translations/resources/fr.json +0 -311
  43. package/mods/translations/resources/hr.json +0 -308
  44. package/mods/translations/resources/hu.json +0 -308
  45. package/mods/translations/resources/id.json +0 -308
  46. package/mods/translations/resources/it.json +0 -308
  47. package/mods/translations/resources/ja.json +0 -308
  48. package/mods/translations/resources/lt.json +0 -308
  49. package/mods/translations/resources/lv.json +0 -308
  50. package/mods/translations/resources/pl.json +0 -308
  51. package/mods/translations/resources/pt-BR.json +0 -308
  52. package/mods/translations/resources/pt-PT.json +0 -308
  53. package/mods/translations/resources/ro.json +0 -310
  54. package/mods/translations/resources/ru.json +0 -308
  55. package/mods/translations/resources/sr-Cyrl.json +0 -308
  56. package/mods/translations/resources/sr-Latn.json +0 -308
  57. package/mods/translations/resources/tlh.json +0 -308
  58. package/mods/translations/resources/tr.json +0 -308
  59. package/mods/translations/resources/uk.json +0 -308
  60. package/mods/translations/resources/vi.json +0 -309
  61. package/mods/translations/resources/zh-CN.json +0 -308
  62. package/mods/translations/resources/zh-TW.json +0 -308
  63. package/mods/translations/update-translations.js +0 -55
  64. package/mods/ui/chapters.js +0 -137
  65. package/mods/ui/clock.js +0 -71
  66. package/mods/ui/customCommandExecution.js +0 -49
  67. package/mods/ui/customGuideAction.js +0 -119
  68. package/mods/ui/customUI.js +0 -192
  69. package/mods/ui/customYTSettings.js +0 -29
  70. package/mods/ui/disableWhosWatching.js +0 -48
  71. package/mods/ui/settings.js +0 -1024
  72. package/mods/ui/sidebarModification.js +0 -179
  73. package/mods/ui/speedUI.js +0 -119
  74. package/mods/ui/theme.js +0 -26
  75. package/mods/ui/ui.css +0 -157
  76. package/mods/ui/ui.js +0 -261
  77. package/mods/ui/ytUI.js +0 -510
  78. package/mods/userScript.js +0 -28
  79. package/mods/utils/ASTParser.js +0 -67
  80. package/mods/utils/innerTubeCalls.js +0 -138
  81. package/service/package-lock.json +0 -4193
  82. package/service/package.json +0 -29
  83. package/service/rollup.config.js +0 -47
  84. package/service/service.js +0 -118
package/mods/package.json DELETED
@@ -1,33 +0,0 @@
1
- {
2
- "name": "@tizentube/mods",
3
- "version": "1.0.0",
4
- "description": "",
5
- "main": "index.js",
6
- "type": "module",
7
- "scripts": {
8
- "build": "rollup -c rollup.config.js"
9
- },
10
- "keywords": [],
11
- "author": "Reis Can, YouTube WebOs contributors",
12
- "license": "GPL-3.0-only",
13
- "dependencies": {
14
- "@babel/preset-env": "^7.22.9",
15
- "@rollup/plugin-babel": "^6.0.3",
16
- "@rollup/plugin-terser": "^0.4.3",
17
- "core-js": "^3.46.0",
18
- "esprima": "^4.0.1",
19
- "estraverse": "^5.3.0",
20
- "i18next": "^25.8.18",
21
- "qrcode-npm": "^0.0.3",
22
- "rollup": "^3.26.2",
23
- "rollup-plugin-string": "^3.0.0",
24
- "tiny-sha256": "^1.0.2",
25
- "whatwg-fetch": "^3.6.2"
26
- },
27
- "devDependencies": {
28
- "@rollup/plugin-commonjs": "^29.0.0",
29
- "@rollup/plugin-json": "^6.1.0",
30
- "@rollup/plugin-node-resolve": "^16.0.3",
31
- "@rollup/plugin-replace": "^6.0.3"
32
- }
33
- }
@@ -1,376 +0,0 @@
1
- import { configWrite, configRead } from './config.js';
2
- import { enablePip } from './features/pictureInPicture.js';
3
- import modernUI, { optionShow } from './ui/settings.js';
4
- import { speedSettings } from './ui/speedUI.js';
5
- import { showToast, buttonItem, showModal, QrCodeRenderer, overlayPanelItemListRenderer, overlayMessageRenderer } from './ui/ytUI.js';
6
- import checkForUpdates from './features/updater.js';
7
- import { t } from 'i18next';
8
- import { requestNextAndNavigateChannel, getFeedbackPanelTokens, sendFeedbackToken } from './utils/innerTubeCalls.js';
9
- import qrcode from 'qrcode-npm';
10
- import showGuideSettings from './ui/sidebarModification.js';
11
-
12
- export default function resolveCommand(cmd, _) {
13
- // resolveCommand function is pretty OP, it can do from opening modals, changing client settings and way more.
14
- // Because the client might change, we should find it first.
15
-
16
- for (const key in window._yttv) {
17
- if (window._yttv[key] && window._yttv[key].instance && window._yttv[key].instance.resolveCommand) {
18
- return window._yttv[key].instance.resolveCommand(cmd, _);
19
- }
20
- }
21
- }
22
-
23
- export function findFunction(funcName) {
24
- for (const key in window._yttv) {
25
- if (window._yttv[key] && window._yttv[key][funcName] && typeof window._yttv[key][funcName] === 'function') {
26
- return window._yttv[key][funcName];
27
- }
28
- }
29
- }
30
-
31
- // Patch resolveCommand to be able to change TizenTube settings
32
-
33
- export function patchResolveCommand() {
34
- for (const key in window._yttv) {
35
- if (window._yttv[key] && window._yttv[key].instance && window._yttv[key].instance.resolveCommand) {
36
-
37
- const ogResolve = window._yttv[key].instance.resolveCommand;
38
- window._yttv[key].instance.resolveCommand = function (cmd, _) {
39
- if (cmd.setClientSettingEndpoint) {
40
- // Command to change client settings. Use TizenTube configuration to change settings.
41
- for (const settings of cmd.setClientSettingEndpoint.settingDatas) {
42
- if (!settings.clientSettingEnum.item.includes('_')) {
43
- for (const setting of cmd.setClientSettingEndpoint.settingDatas) {
44
- const valName = Object.keys(setting).find(key => key.includes('Value'));
45
- const value = valName === 'intValue' ? Number(setting[valName]) : setting[valName];
46
- if (valName === 'arrayValue') {
47
- const arr = configRead(setting.clientSettingEnum.item);
48
- if (arr.includes(value)) {
49
- arr.splice(arr.indexOf(value), 1);
50
- } else {
51
- arr.push(value);
52
- }
53
- configWrite(setting.clientSettingEnum.item, arr);
54
- } else configWrite(setting.clientSettingEnum.item, value);
55
- }
56
- } else if (settings.clientSettingEnum.item === 'I18N_LANGUAGE') {
57
- const lang = settings.stringValue;
58
- const date = new Date();
59
- date.setFullYear(date.getFullYear() + 10);
60
- document.cookie = `PREF=hl=${lang}; expires=${date.toUTCString()};`;
61
- resolveCommand({
62
- signalAction: {
63
- signal: 'RELOAD_PAGE'
64
- }
65
- });
66
- return true;
67
- }
68
- }
69
- } else if (cmd.customAction) {
70
- customAction(cmd.customAction.action, cmd.customAction.parameters);
71
- return true;
72
- } else if (cmd?.signalAction?.customAction) {
73
- customAction(cmd.signalAction.customAction.action, cmd.signalAction.customAction.parameters);
74
- return true;
75
- } else if (cmd?.showEngagementPanelEndpoint?.customAction) {
76
- customAction(cmd.showEngagementPanelEndpoint.customAction.action, cmd.showEngagementPanelEndpoint.customAction.parameters);
77
- return true;
78
- } else if (cmd?.playlistEditEndpoint?.customAction) {
79
- customAction(cmd.playlistEditEndpoint.customAction.action, cmd.playlistEditEndpoint.customAction.parameters);
80
- return true;
81
- } else if (cmd?.openPopupAction?.uniqueId === 'playback-settings') {
82
- // Patch the playback settings popup to use TizenTube speed settings
83
- const items = cmd.openPopupAction.popup.overlaySectionRenderer.overlay.overlayTwoPanelRenderer.actionPanel.overlayPanelRenderer.content.overlayPanelItemListRenderer.items;
84
- for (const item of items) {
85
- if (item?.compactLinkRenderer?.icon?.iconType === 'SLOW_MOTION_VIDEO') {
86
- item.compactLinkRenderer.subtitle && (item.compactLinkRenderer.subtitle.simpleText = t('player.withTizenTube'));
87
- item.compactLinkRenderer.serviceEndpoint = {
88
- clickTrackingParams: "null",
89
- signalAction: {
90
- customAction: {
91
- action: 'TT_SPEED_SETTINGS_SHOW',
92
- parameters: []
93
- }
94
- }
95
- };
96
- }
97
- }
98
-
99
- cmd.openPopupAction.popup.overlaySectionRenderer.overlay.overlayTwoPanelRenderer.actionPanel.overlayPanelRenderer.content.overlayPanelItemListRenderer.items.splice(2, 0,
100
- buttonItem(
101
- { title: t('player.miniPlayer') },
102
- { icon: 'CLEAR_COOKIES' }, [
103
- {
104
- customAction: {
105
- action: 'ENTER_MP'
106
- }
107
- }
108
- ])
109
- );
110
-
111
- cmd.openPopupAction.popup.overlaySectionRenderer.overlay.overlayTwoPanelRenderer.actionPanel.overlayPanelRenderer.content.overlayPanelItemListRenderer.items.splice(3, 0,
112
- buttonItem(
113
- { title: t('player.share.button') },
114
- { icon: 'OPEN_IN_NEW' }, [
115
- {
116
- customAction: {
117
- action: 'SHARE'
118
- }
119
- }
120
- ])
121
- );
122
-
123
- cmd.openPopupAction.popup.overlaySectionRenderer.overlay.overlayTwoPanelRenderer.actionPanel.overlayPanelRenderer.content.overlayPanelItemListRenderer.items.splice(3, 0,
124
- buttonItem(
125
- { title: t('player.screenOff') },
126
- { icon: 'EYE_OFF' }, [
127
- {
128
- customAction: {
129
- action: 'SCREEN_OFF'
130
- }
131
- }
132
- ])
133
- );
134
-
135
- if (window.h5vcc && window.h5vcc.tizentube && window.h5vcc.tizentube.HasSystemFeature &&
136
- window.h5vcc.tizentube.HasSystemFeature('android.software.picture_in_picture')) {
137
- cmd.openPopupAction.popup.overlaySectionRenderer.overlay.overlayTwoPanelRenderer.actionPanel.overlayPanelRenderer.content.overlayPanelItemListRenderer.items.splice(3, 0,
138
- buttonItem(
139
- { title: t('player.pictureInPicture') },
140
- { icon: 'TV' }, [
141
- {
142
- customAction: {
143
- action: 'ENTER_PIP'
144
- }
145
- },
146
- {
147
- signalAction: {
148
- signal: 'POPUP_BACK'
149
- }
150
- }
151
- ])
152
- );
153
- }
154
- } else if (cmd?.watchEndpoint?.videoId) {
155
- window.isPipPlaying = false;
156
- const ytlrPlayerContainer = document.querySelector('ytlr-player-container');
157
- ytlrPlayerContainer.style.removeProperty('z-index');
158
- }
159
-
160
- if (cmd.customAction) return window._yttv[key].instance.resolveCommand(cmd, _);
161
-
162
- if (cmd.commandExecutorCommand && cmd.commandExecutorCommand.commands) {
163
- for (const command of cmd.commandExecutorCommand.commands) {
164
- if (command.customAction) {
165
- customAction(command.customAction.action, command.customAction.parameters);
166
- } else if (command.signalAction?.customAction) {
167
- customAction(command.signalAction.customAction.action, command.signalAction.customAction.parameters);
168
- } else if (command.showEngagementPanelEndpoint?.customAction) {
169
- customAction(command.showEngagementPanelEndpoint.customAction.action, command.showEngagementPanelEndpoint.customAction.parameters);
170
- } else if (command.playlistEditEndpoint?.customAction) {
171
- customAction(command.playlistEditEndpoint.customAction.action, command.playlistEditEndpoint.customAction.parameters);
172
- } else {
173
- window._yttv[key].instance.resolveCommand(command, _);
174
- }
175
- }
176
- return true;
177
- }
178
-
179
- if (cmd?.requestAccountSelectorCommand
180
- && cmd.requestAccountSelectorCommand?.identityActionContext?.eventTrigger === 'ACCOUNT_EVENT_TRIGGER_ON_EXIT') {
181
- if (!configRead('enableWhosWatchingMenuOnAppExit')) {
182
- ogResolve.call(this, {
183
- signalAction: {
184
- signal: 'EXIT_APP'
185
- }
186
- });
187
- return false;
188
- }
189
- }
190
-
191
- return ogResolve.call(this, cmd, _);
192
- }
193
- }
194
- }
195
- }
196
-
197
- function customAction(action, parameters) {
198
- switch (action) {
199
- case 'SETTINGS_UPDATE':
200
- modernUI(true, parameters);
201
- break;
202
- case 'OPTIONS_SHOW':
203
- optionShow(parameters, parameters.update);
204
- break;
205
- case 'SKIP':
206
- const kE = document.createEvent('Event');
207
- kE.initEvent('keydown', true, true);
208
- kE.keyCode = 27;
209
- kE.which = 27;
210
- document.dispatchEvent(kE);
211
-
212
- document.querySelector('video').currentTime = parameters.time;
213
- break;
214
- case 'TT_SETTINGS_SHOW':
215
- modernUI();
216
- break;
217
- case 'TT_SPEED_SETTINGS_SHOW':
218
- speedSettings();
219
- break;
220
- case 'UPDATE_REMIND_LATER':
221
- configWrite('dontCheckUpdateUntil', parameters);
222
- break;
223
- case 'UPDATE_DOWNLOAD':
224
- window.h5vcc.tizentube.InstallAppFromURL(parameters);
225
- showToast(t('settings.options.updater.downloading.title'), t('settings.options.updater.downloading.subtitle'));
226
- break;
227
- case 'SET_PLAYER_SPEED':
228
- const speed = Number(parameters);
229
- document.querySelector('video').playbackRate = speed;
230
- break;
231
- case 'ENTER_MP':
232
- enablePip();
233
- break;
234
- case 'ENTER_PIP':
235
- window.h5vcc.tizentube.EnterPIP();
236
- break;
237
- case 'SHOW_TOAST':
238
- showToast('TizenTube', parameters);
239
- break;
240
- case 'ADD_TO_QUEUE':
241
- window.queuedVideos.videos.push(parameters);
242
- showToast('TizenTube', t('toasts.videoAddedToQueue'));
243
- break;
244
- case 'CLEAR_QUEUE':
245
- window.queuedVideos.videos = [];
246
- showToast('TizenTube', t('toasts.videoQueueCleared'));
247
- break;
248
- case 'CHECK_FOR_UPDATES':
249
- checkForUpdates(true);
250
- break;
251
- case 'GO_TO_CHANNEL':
252
- requestNextAndNavigateChannel(parameters);
253
- break;
254
- case 'NOT_INTERESTED':
255
- markFeedback(parameters, 0, true);
256
- break;
257
- case 'DONT_RECOMMEND_CHANNEL':
258
- markFeedback(parameters, 1, false);
259
- break;
260
- case 'FEEDBACK_REASON':
261
- sendFeedbackToken(parameters.token)
262
- .then(() => {
263
- resolveCommand({
264
- signalAction: {
265
- signal: 'POPUP_BACK'
266
- }
267
- });
268
- showToast('TizenTube', t('toasts.feedbackSent'));
269
- })
270
- .catch(err => console.error('TizenTube: failed to send feedback:', err));
271
- break;
272
- case 'SHARE':
273
- const videoPlayer = document.querySelector('.html5-video-player');
274
- const videoData = videoPlayer.getVideoData();
275
- const videoId = videoData.video_id;
276
- const shareUrl = `https://www.youtube.com/watch?v=${videoId}`;
277
-
278
- const qr = qrcode.qrcode(6, 'H');
279
- qr.addData(shareUrl);
280
- qr.make();
281
-
282
- const qrDataImgTag = qr.createImgTag(8, 8);
283
- const qrDataUrl = qrDataImgTag.match(/src="([^"]+)"/)[1];
284
-
285
- showModal({
286
- title: t('player.share.title'),
287
- }, overlayPanelItemListRenderer([
288
- overlayMessageRenderer(t('player.share.qrCodeScanMessage')),
289
- QrCodeRenderer(qrDataUrl)
290
- ]), 'tt-share-modal');
291
- break;
292
- case 'SHOW_GUIDE_BUTTONS':
293
- showGuideSettings('SHOW_GUIDE_BUTTONS', parameters);
294
- break;
295
- case 'RELOAD_GUIDE_OPTIONS':
296
- showGuideSettings(parameters.settingType, true);
297
- break;
298
- case 'MOVE_GUIDE_BUTTON':
299
- showGuideSettings('MOVE_GUIDE_BUTTON', parameters);
300
- break;
301
- case 'SHOW_GUIDE_SETTINGS':
302
- showGuideSettings(parameters);
303
- break;
304
- case 'ADD_OR_REMOVE_CHANNEL_TO_SIDEBAR':
305
- const sortedSidebarContents = configRead('sidebarContentsOrder');
306
-
307
- if (sortedSidebarContents.find(item => item.browseId === parameters.browseId)) {
308
- sortedSidebarContents.splice(sortedSidebarContents.findIndex(item => item.browseId === parameters.browseId), 1);
309
- } else {
310
- sortedSidebarContents.push({
311
- browseId: parameters.browseId,
312
- title: parameters.title,
313
- });
314
- }
315
- configWrite('sidebarContentsOrder', sortedSidebarContents);
316
- showToast(t('toasts.sidebarContentsUpdated.title'), t('toasts.sidebarContentsUpdated.subtitle'));
317
- break;
318
- case 'SCREEN_OFF':
319
- for (const child of document.body.children) {
320
- if (child.tagName.toLowerCase() === 'script' || child.tagName.toLowerCase() === 'svg') continue;
321
- child.style.setProperty('display', 'none', 'important');
322
- }
323
- window.screenTurnedOffAt = Date.now();
324
- break;
325
- }
326
- }
327
-
328
- // YouTube moved the "Not interested" / "Don't recommend channel" feedback tokens
329
- // out of the long press menu into an engagement panel (see getFeedbackPanel in
330
- // adblock.js). Fetch the panel first, then send the feedback with the token it
331
- // returns (token 0 = "Not interested", token 1 = "Don't recommend channel").
332
- // If YouTube asks for a dismissal reason, present the reasons in a modal and send
333
- // the selected one (see FEEDBACK_REASON).
334
- async function markFeedback(parameters, tokenIndex, showReasons) {
335
- try {
336
- const tokens = await getFeedbackPanelTokens(parameters.panelId, parameters.params);
337
- const token = tokens[tokenIndex];
338
- if (!token) return;
339
-
340
- const response = await sendFeedbackToken(token);
341
- if (!showReasons) return;
342
-
343
- const dismissal = response?.feedbackResponses?.[0]?.followUpDialog?.dismissalFollowUpRenderer;
344
- const reasons = dismissal?.reasons;
345
- if (!Array.isArray(reasons) || !reasons.length) return;
346
-
347
- const buttons = reasons.map((reason) => buttonItem(
348
- { title: extractText(reason.title) },
349
- null,
350
- [
351
- {
352
- signalAction: {
353
- signal: 'POPUP_BACK'
354
- }
355
- },
356
- {
357
- customAction: {
358
- action: 'FEEDBACK_REASON',
359
- parameters: { token: reason.token }
360
- }
361
- }
362
- ]
363
- ));
364
- showModal(extractText(dismissal.dismissalReasonsPrompt), overlayPanelItemListRenderer(buttons), 'tt-feedback-reasons');
365
- } catch (err) {
366
- console.error('TizenTube: failed to mark feedback:', err);
367
- }
368
- }
369
-
370
- function extractText(text) {
371
- if (!text) return '';
372
- if (text.simpleText) return text.simpleText;
373
- if (text.content) return text.content;
374
- if (Array.isArray(text.runs)) return text.runs.map((run) => run?.text ?? '').join('');
375
- return String(text);
376
- }
@@ -1,41 +0,0 @@
1
- import { string } from 'rollup-plugin-string';
2
- import terser from '@rollup/plugin-terser';
3
- import getBabelOutputPlugin from '@rollup/plugin-babel';
4
- import { nodeResolve } from '@rollup/plugin-node-resolve';
5
- import commonjs from '@rollup/plugin-commonjs';
6
- import replace from '@rollup/plugin-replace';
7
- import json from '@rollup/plugin-json';
8
-
9
- export default {
10
- input: "userScript.js",
11
- output: { file: "../dist/userScript.js", format: "iife" },
12
- plugins: [
13
- json(),
14
- string({
15
- include: "**/*.css",
16
- }),
17
- nodeResolve({
18
- browser: true,
19
- preferBuiltins: false,
20
- }),
21
- commonjs({
22
- include: [/node_modules/, /mods/],
23
- transformMixedEsModules: true,
24
- }),
25
- getBabelOutputPlugin({
26
- babelHelpers: 'bundled',
27
- presets: [
28
- ['@babel/preset-env', {
29
- targets: 'Chrome 47',
30
- }],
31
- ],
32
- }),
33
- terser({
34
- ecma: '5',
35
- mangle: true,
36
- }),
37
- replace({
38
- '\uFFFF': '\u0000',
39
- })
40
- ]
41
- };