@bghitcode/bghitapp 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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +203 -0
  3. package/dist/cli.js +2995 -0
  4. package/package.json +104 -0
  5. package/src-tauri/Cargo.lock +5966 -0
  6. package/src-tauri/Cargo.toml +59 -0
  7. package/src-tauri/Info.plist +14 -0
  8. package/src-tauri/assets/macos/dmg/background.png +0 -0
  9. package/src-tauri/assets/main.wxs +350 -0
  10. package/src-tauri/bghitapp.json +42 -0
  11. package/src-tauri/build.rs +5 -0
  12. package/src-tauri/capabilities/default.json +29 -0
  13. package/src-tauri/entitlements.plist +7 -0
  14. package/src-tauri/icons/chatgpt.icns +0 -0
  15. package/src-tauri/icons/deepseek.icns +0 -0
  16. package/src-tauri/icons/excalidraw.icns +0 -0
  17. package/src-tauri/icons/flomo.icns +0 -0
  18. package/src-tauri/icons/gemini.icns +0 -0
  19. package/src-tauri/icons/grok.icns +0 -0
  20. package/src-tauri/icons/icon.icns +0 -0
  21. package/src-tauri/icons/icon.png +0 -0
  22. package/src-tauri/icons/lizhi.icns +0 -0
  23. package/src-tauri/icons/programmusic.icns +0 -0
  24. package/src-tauri/icons/qwerty.icns +0 -0
  25. package/src-tauri/icons/twitter.icns +0 -0
  26. package/src-tauri/icons/wechat.icns +0 -0
  27. package/src-tauri/icons/weekly.icns +0 -0
  28. package/src-tauri/icons/weread.icns +0 -0
  29. package/src-tauri/icons/xiaohongshu.icns +0 -0
  30. package/src-tauri/icons/youtube.icns +0 -0
  31. package/src-tauri/icons/youtubemusic.icns +0 -0
  32. package/src-tauri/rust_proxy.toml +10 -0
  33. package/src-tauri/src/app/config.rs +100 -0
  34. package/src-tauri/src/app/invoke.rs +242 -0
  35. package/src-tauri/src/app/menu.rs +324 -0
  36. package/src-tauri/src/app/mod.rs +6 -0
  37. package/src-tauri/src/app/setup.rs +172 -0
  38. package/src-tauri/src/app/window.rs +577 -0
  39. package/src-tauri/src/inject/auth.js +75 -0
  40. package/src-tauri/src/inject/custom.js +0 -0
  41. package/src-tauri/src/inject/event.js +1111 -0
  42. package/src-tauri/src/inject/find.js +708 -0
  43. package/src-tauri/src/inject/fullscreen.js +253 -0
  44. package/src-tauri/src/inject/offline.js +68 -0
  45. package/src-tauri/src/inject/splash-transition.js +13 -0
  46. package/src-tauri/src/inject/style.js +505 -0
  47. package/src-tauri/src/inject/theme_refresh.js +59 -0
  48. package/src-tauri/src/inject/toast.js +22 -0
  49. package/src-tauri/src/lib.rs +227 -0
  50. package/src-tauri/src/main.rs +8 -0
  51. package/src-tauri/src/util.rs +245 -0
  52. package/src-tauri/tauri.conf.json +20 -0
  53. package/src-tauri/tauri.linux.conf.json +12 -0
  54. package/src-tauri/tauri.macos.conf.json +28 -0
  55. package/src-tauri/tauri.windows.conf.json +15 -0
@@ -0,0 +1,253 @@
1
+ // Polyfill for HTML5 Fullscreen API in Tauri webview.
2
+ // Bridges the standard requestFullscreen / exitFullscreen DOM API to Tauri's
3
+ // native window fullscreen so video sites (YouTube, Vimeo, Bilibili, etc.) can
4
+ // go true fullscreen on their player buttons.
5
+ //
6
+ // Split out from component.js so a future CLI flag (or custom.js override)
7
+ // can short-circuit the polyfill for apps that don't need video fullscreen.
8
+ (function () {
9
+ if (window.__BGHITAPP_FULLSCREEN_POLYFILL__) return;
10
+ window.__BGHITAPP_FULLSCREEN_POLYFILL__ = true;
11
+
12
+ function initFullscreenPolyfill() {
13
+ if (!window.__TAURI__ || !document.head) {
14
+ setTimeout(initFullscreenPolyfill, 100);
15
+ return;
16
+ }
17
+
18
+ const appWindow = window.__TAURI__.window.getCurrentWindow();
19
+ let fullscreenElement = null;
20
+ let actualFullscreenElement = null;
21
+ let originalStyles = null;
22
+ let originalParent = null;
23
+ let originalNextSibling = null;
24
+ let wasInBody = false;
25
+ let monitorId = null;
26
+
27
+ if (!document.getElementById("bghitapp-fullscreen-style")) {
28
+ const styleEl = document.createElement("style");
29
+ styleEl.id = "bghitapp-fullscreen-style";
30
+ styleEl.textContent = `
31
+ body.bghitapp-fullscreen-active {
32
+ overflow: hidden !important;
33
+ }
34
+ .bghitapp-fullscreen-element {
35
+ position: fixed !important;
36
+ top: 0 !important;
37
+ left: 0 !important;
38
+ width: 100vw !important;
39
+ height: 100vh !important;
40
+ max-width: 100vw !important;
41
+ max-height: 100vh !important;
42
+ margin: 0 !important;
43
+ padding: 0 !important;
44
+ z-index: 2147483647 !important;
45
+ background: #000 !important;
46
+ object-fit: contain !important;
47
+ }
48
+ .bghitapp-fullscreen-element video {
49
+ width: 100% !important;
50
+ height: 100% !important;
51
+ object-fit: contain !important;
52
+ }
53
+ `;
54
+ document.head.appendChild(styleEl);
55
+ }
56
+
57
+ function startFullscreenMonitor() {
58
+ if (monitorId) return;
59
+ monitorId = setInterval(() => {
60
+ appWindow
61
+ .isFullscreen()
62
+ .then((isFullscreen) => {
63
+ if (fullscreenElement && !isFullscreen) {
64
+ exitFullscreen();
65
+ }
66
+ })
67
+ .catch(() => {});
68
+ }, 500);
69
+ }
70
+
71
+ function stopFullscreenMonitor() {
72
+ if (!monitorId) return;
73
+ clearInterval(monitorId);
74
+ monitorId = null;
75
+ }
76
+
77
+ function findMediaElement() {
78
+ const videos = document.querySelectorAll("video");
79
+ if (videos.length > 0) {
80
+ let largestVideo = videos[0];
81
+ let maxArea = 0;
82
+ videos.forEach((video) => {
83
+ const rect = video.getBoundingClientRect();
84
+ const area = rect.width * rect.height;
85
+ if (area > maxArea || !video.paused) {
86
+ maxArea = area;
87
+ largestVideo = video;
88
+ }
89
+ });
90
+ return largestVideo;
91
+ }
92
+ return null;
93
+ }
94
+
95
+ function enterFullscreen(element) {
96
+ fullscreenElement = element;
97
+
98
+ let targetElement = element;
99
+ if (element === document.documentElement || element === document.body) {
100
+ const mediaElement = findMediaElement();
101
+ if (mediaElement) {
102
+ targetElement = mediaElement;
103
+ actualFullscreenElement = mediaElement;
104
+ } else {
105
+ actualFullscreenElement = element;
106
+ }
107
+ } else {
108
+ actualFullscreenElement = element;
109
+ }
110
+
111
+ originalStyles = {
112
+ position: targetElement.style.position,
113
+ top: targetElement.style.top,
114
+ left: targetElement.style.left,
115
+ width: targetElement.style.width,
116
+ height: targetElement.style.height,
117
+ maxWidth: targetElement.style.maxWidth,
118
+ maxHeight: targetElement.style.maxHeight,
119
+ margin: targetElement.style.margin,
120
+ padding: targetElement.style.padding,
121
+ zIndex: targetElement.style.zIndex,
122
+ background: targetElement.style.background,
123
+ objectFit: targetElement.style.objectFit,
124
+ };
125
+
126
+ wasInBody = targetElement.parentNode === document.body;
127
+ if (!wasInBody) {
128
+ originalParent = targetElement.parentNode;
129
+ originalNextSibling = targetElement.nextSibling;
130
+ }
131
+
132
+ targetElement.classList.add("bghitapp-fullscreen-element");
133
+ document.body.classList.add("bghitapp-fullscreen-active");
134
+
135
+ if (!wasInBody) {
136
+ document.body.appendChild(targetElement);
137
+ }
138
+
139
+ appWindow.setFullscreen(true).then(() => {
140
+ startFullscreenMonitor();
141
+ const event = new Event("fullscreenchange", { bubbles: true });
142
+ document.dispatchEvent(event);
143
+ element.dispatchEvent(event);
144
+
145
+ const webkitEvent = new Event("webkitfullscreenchange", {
146
+ bubbles: true,
147
+ });
148
+ document.dispatchEvent(webkitEvent);
149
+ element.dispatchEvent(webkitEvent);
150
+ });
151
+
152
+ return Promise.resolve();
153
+ }
154
+
155
+ function exitFullscreen() {
156
+ if (!fullscreenElement) {
157
+ return Promise.resolve();
158
+ }
159
+
160
+ stopFullscreenMonitor();
161
+
162
+ const exitingElement = fullscreenElement;
163
+ const targetElement = actualFullscreenElement;
164
+
165
+ targetElement.classList.remove("bghitapp-fullscreen-element");
166
+ document.body.classList.remove("bghitapp-fullscreen-active");
167
+
168
+ if (originalStyles) {
169
+ Object.keys(originalStyles).forEach((key) => {
170
+ targetElement.style[key] = originalStyles[key];
171
+ });
172
+ }
173
+
174
+ if (!wasInBody && originalParent) {
175
+ if (
176
+ originalNextSibling &&
177
+ originalNextSibling.parentNode === originalParent
178
+ ) {
179
+ originalParent.insertBefore(targetElement, originalNextSibling);
180
+ } else if (originalParent.isConnected) {
181
+ originalParent.appendChild(targetElement);
182
+ }
183
+ }
184
+
185
+ fullscreenElement = null;
186
+ actualFullscreenElement = null;
187
+ originalStyles = null;
188
+ originalParent = null;
189
+ originalNextSibling = null;
190
+ wasInBody = false;
191
+
192
+ return appWindow.setFullscreen(false).then(() => {
193
+ const event = new Event("fullscreenchange", { bubbles: true });
194
+ document.dispatchEvent(event);
195
+ exitingElement.dispatchEvent(event);
196
+
197
+ const webkitEvent = new Event("webkitfullscreenchange", {
198
+ bubbles: true,
199
+ });
200
+ document.dispatchEvent(webkitEvent);
201
+ exitingElement.dispatchEvent(webkitEvent);
202
+ });
203
+ }
204
+
205
+ Object.defineProperty(document, "fullscreenEnabled", {
206
+ get: () => true,
207
+ configurable: true,
208
+ });
209
+ Object.defineProperty(document, "webkitFullscreenEnabled", {
210
+ get: () => true,
211
+ configurable: true,
212
+ });
213
+
214
+ Object.defineProperty(document, "fullscreenElement", {
215
+ get: () => fullscreenElement,
216
+ configurable: true,
217
+ });
218
+ Object.defineProperty(document, "webkitFullscreenElement", {
219
+ get: () => fullscreenElement,
220
+ configurable: true,
221
+ });
222
+ Object.defineProperty(document, "webkitCurrentFullScreenElement", {
223
+ get: () => fullscreenElement,
224
+ configurable: true,
225
+ });
226
+
227
+ Element.prototype.requestFullscreen = function () {
228
+ return enterFullscreen(this);
229
+ };
230
+ Element.prototype.webkitRequestFullscreen = function () {
231
+ return enterFullscreen(this);
232
+ };
233
+ Element.prototype.webkitRequestFullScreen = function () {
234
+ return enterFullscreen(this);
235
+ };
236
+
237
+ document.exitFullscreen = exitFullscreen;
238
+ document.webkitExitFullscreen = exitFullscreen;
239
+ document.webkitCancelFullScreen = exitFullscreen;
240
+
241
+ document.addEventListener(
242
+ "keydown",
243
+ (e) => {
244
+ if (e.key === "Escape" && fullscreenElement) {
245
+ exitFullscreen();
246
+ }
247
+ },
248
+ true,
249
+ );
250
+ }
251
+
252
+ initFullscreenPolyfill();
253
+ })();
@@ -0,0 +1,68 @@
1
+ (function() {
2
+ var TARGET_URL = window.bghitappConfig?.url || window.location.href;
3
+
4
+ var OFFLINE_HTML = '<!DOCTYPE html>'
5
+ + '<html><head><meta charset="utf-8"><style>'
6
+ + '*{margin:0;padding:0;box-sizing:border-box}'
7
+ + 'body{display:flex;justify-content:center;align-items:center;height:100vh;background:#1a1a1a;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,system-ui,sans-serif}'
8
+ + '.card{text-align:center;max-width:400px;padding:40px}'
9
+ + '.icon{width:64px;height:64px;stroke:#636366;margin-bottom:24px}'
10
+ + '.heading{font-size:24px;font-weight:700;color:#fff;margin-bottom:8px}'
11
+ + '.subtext{font-size:16px;color:#AEAEB2;margin-bottom:32px}'
12
+ + '.retry-btn{display:inline-flex;align-items:center;justify-content:center;min-width:120px;height:44px;padding:0 16px;background:#0A84FF;color:#fff;border:none;border-radius:8px;font-size:16px;font-weight:600;cursor:pointer;transition:background .15s}'
13
+ + '.retry-btn:hover{background:#409CFF}'
14
+ + '.retry-btn:disabled{background:#636366;cursor:not-allowed}'
15
+ + '.spinner{display:none;width:20px;height:20px;border:2px solid #FFF;border-top-color:transparent;border-radius:50%;animation:spin .6s linear infinite}'
16
+ + '.retry-btn.loading .btn-text{display:none}'
17
+ + '.retry-btn.loading .spinner{display:inline-block}'
18
+ + '@keyframes spin{to{transform:rotate(360deg)}}'
19
+ + '</style></head><body>'
20
+ + '<div class="card">'
21
+ + '<svg class="icon" viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">'
22
+ + '<path d="M1 1l22 22"/><path d="M16.72 11.06A10.94 10.94 0 0 1 19 12.55"/>'
23
+ + '<path d="M5 12.55a10.94 10.94 0 0 1 5.17-2.39"/>'
24
+ + '<path d="M10.71 5.05A16 16 0 0 1 22.56 9"/>'
25
+ + '<path d="M1.42 9a15.91 15.91 0 0 1 4.7-2.88"/>'
26
+ + '<path d="M8.53 16.11a6 6 0 0 1 6.95 0"/>'
27
+ + '<line x1="12" y1="20" x2="12.01" y2="20"/>'
28
+ + '</svg>'
29
+ + '<h1 class="heading">No Internet Connection</h1>'
30
+ + '<p class="subtext">Check your network and try again</p>'
31
+ + '<button class="retry-btn" onclick="retry()">'
32
+ + '<span class="btn-text">Retry</span><span class="spinner"></span></button>'
33
+ + '</div>'
34
+ + '<script>var cooldown=false;function retry(){if(cooldown)return;cooldown=true;var b=document.querySelector(".retry-btn");b.classList.add("loading");b.disabled=true;setTimeout(function(){var o=localStorage.getItem("bghitapp_original_url");if(o)window.location.href=o;else window.location.reload()},3000)}</'
35
+ + 'script></body></html>';
36
+
37
+ function isOffline() {
38
+ return !navigator.onLine;
39
+ }
40
+
41
+ function goToOffline() {
42
+ var href = window.location.href;
43
+ if (!href.includes('offline.html') && !href.includes('data:text/html')) {
44
+ localStorage.setItem('bghitapp_original_url', TARGET_URL);
45
+ document.open();
46
+ document.write(OFFLINE_HTML);
47
+ document.close();
48
+ }
49
+ }
50
+
51
+ function goOnline() {
52
+ if (window.location.href.includes('data:text/html') || document.querySelector('.retry-btn')) {
53
+ var original = localStorage.getItem('bghitapp_original_url') || TARGET_URL;
54
+ window.location.replace(original);
55
+ }
56
+ }
57
+
58
+ if (isOffline()) {
59
+ if (document.readyState === 'loading') {
60
+ document.addEventListener('DOMContentLoaded', goToOffline);
61
+ } else {
62
+ goToOffline();
63
+ }
64
+ }
65
+
66
+ window.addEventListener('offline', goToOffline);
67
+ window.addEventListener('online', goOnline);
68
+ })();
@@ -0,0 +1,13 @@
1
+ (function() {
2
+ function onReady() {
3
+ if (window.__TAURI__ && window.bghitappConfig?.splash) {
4
+ window.__TAURI__.core.invoke('close_splashscreen');
5
+ }
6
+ }
7
+
8
+ if (document.readyState === 'complete') {
9
+ onReady();
10
+ } else {
11
+ window.addEventListener('load', onReady);
12
+ }
13
+ })();