pake-cli 2.1.12 → 2.2.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.
@@ -18,8 +18,7 @@ tauri-build = { version = "1.4.0", features = [] }
18
18
  serde_json = "1.0.96"
19
19
  serde = { version = "1.0.163", features = ["derive"] }
20
20
  tauri = { version = "1.4.1", features = ["api-all", "system-tray"] }
21
- download_rs = { version = "0.2.0", features = ["sync_download"] }
22
- tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "dev" }
21
+ tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
23
22
 
24
23
  [dev-dependencies]
25
24
  cargo-bloat = "0.11.1"
Binary file
@@ -1,6 +1,8 @@
1
- use crate::util::{check_file_or_append, get_download_message, show_toast};
2
- use download_rs::sync_download::Download;
1
+ use crate::util::{check_file_or_append, get_download_message, MessageType, show_toast};
3
2
  use tauri::{api, command, AppHandle, Manager, Window};
3
+ use tauri::api::http::{ClientBuilder, HttpRequestBuilder, ResponseType};
4
+ use std::fs::File;
5
+ use std::io::Write;
4
6
 
5
7
  #[derive(serde::Deserialize)]
6
8
  pub struct DownloadFileParams {
@@ -11,16 +13,29 @@ pub struct DownloadFileParams {
11
13
  #[command]
12
14
  pub async fn download_file(app: AppHandle, params: DownloadFileParams) -> Result<(), String> {
13
15
  let window: Window = app.get_window("pake").unwrap();
16
+ show_toast(&window, &get_download_message(MessageType::Start));
17
+
14
18
  let output_path = api::path::download_dir().unwrap().join(params.filename);
15
19
  let file_path = check_file_or_append(output_path.to_str().unwrap());
16
- let download = Download::new(&params.url, Some(&file_path), None);
17
- match download.download() {
18
- Ok(_) => {
19
- show_toast(&window, &get_download_message());
20
+ let client = ClientBuilder::new().build().unwrap();
21
+
22
+ let response = client.send(
23
+ HttpRequestBuilder::new("GET", &params.url)
24
+ .unwrap()
25
+ .response_type(ResponseType::Binary)
26
+ ).await;
27
+
28
+ match response {
29
+ Ok(res) => {
30
+ let bytes = res.bytes().await.unwrap().data;
31
+
32
+ let mut file = File::create(file_path).unwrap();
33
+ file.write_all(&bytes).unwrap();
34
+ show_toast(&window, &get_download_message(MessageType::Success));
20
35
  Ok(())
21
36
  }
22
37
  Err(e) => {
23
- show_toast(&window, &e.to_string());
38
+ show_toast(&window, &get_download_message(MessageType::Failure));
24
39
  Err(e.to_string())
25
40
  }
26
41
  }
@@ -38,7 +38,6 @@ pub fn get_menu() -> Menu {
38
38
  pub fn menu_event_handle(event: WindowMenuEvent) {
39
39
  if event.menu_item_id() == "close" {
40
40
  event.window().minimize().expect("can't minimize window");
41
- // event.window().eval("toggleVideoPlayback(true);").unwrap();
42
41
  }
43
42
 
44
43
  if event.menu_item_id() == "goto_url" {
@@ -96,18 +96,18 @@ document.addEventListener('DOMContentLoaded', () => {
96
96
  const urlSubmit = document.getElementById('pakeUrlSubmit');
97
97
  const urlClose = document.getElementById('pakeUrlClose');
98
98
 
99
- urlSubmit.onclick = function () {
99
+ urlSubmit.onclick = function() {
100
100
  const url = urlInput.value;
101
101
  if (url) {
102
102
  window.location.href = url;
103
103
  }
104
104
  };
105
105
 
106
- urlClose.onclick = function () {
106
+ urlClose.onclick = function() {
107
107
  urlModal.style.display = 'none';
108
108
  };
109
109
 
110
- urlInput.addEventListener('keydown', function (event) {
110
+ urlInput.addEventListener('keydown', function(event) {
111
111
  if (event.key === 'Enter') {
112
112
  const url = urlInput.value;
113
113
  if (url) {
@@ -116,13 +116,13 @@ document.addEventListener('DOMContentLoaded', () => {
116
116
  }
117
117
  });
118
118
 
119
- document.addEventListener('keydown', function (event) {
119
+ document.addEventListener('keydown', function(event) {
120
120
  if (event.key === 'Escape' && urlModal.style.display === 'block') {
121
121
  urlModal.style.display = 'none';
122
122
  }
123
123
  });
124
124
 
125
- window.showUrlModal = function () {
125
+ window.showUrlModal = function() {
126
126
  urlModal.style.display = 'block';
127
127
  urlInput.focus();
128
128
  };
@@ -134,11 +134,11 @@ document.addEventListener('DOMContentLoaded', () => {
134
134
  m.style.cssText =
135
135
  'max-width:60%;min-width: 80px;padding:0 12px;height: 32px;color: rgb(255, 255, 255);line-height: 32px;text-align: center;border-radius: 8px;position: fixed; bottom:24px;right: 28px;z-index: 999999;background: rgba(0, 0, 0,.8);font-size: 13px;';
136
136
  document.body.appendChild(m);
137
- setTimeout(function () {
137
+ setTimeout(function() {
138
138
  const d = 0.5;
139
139
  m.style.transition = 'transform ' + d + 's ease-in, opacity ' + d + 's ease-in';
140
140
  m.style.opacity = '0';
141
- setTimeout(function () {
141
+ setTimeout(function() {
142
142
  document.body.removeChild(m);
143
143
  }, d * 1000);
144
144
  }, 3000);
@@ -146,35 +146,4 @@ document.addEventListener('DOMContentLoaded', () => {
146
146
 
147
147
  window.pakeToast = pakeToast;
148
148
 
149
- // chatgpt supports unlimited times of GPT4-Mobile
150
- if (window.location.hostname === 'chat.openai.com') {
151
- const originFetch = fetch;
152
- window.fetch = (url, options) => {
153
- return originFetch(url, options).then(async response => {
154
- if (url.indexOf('/backend-api/models') === -1) {
155
- return response;
156
- }
157
- const responseClone = response.clone();
158
- let res = await responseClone.json();
159
- res.models = res.models.map(m => {
160
- m.tags = m.tags.filter(t => {
161
- return t !== 'mobile';
162
- });
163
- if (m.slug === 'gpt-4-mobile') {
164
- res.categories.push({
165
- browsing_model: null,
166
- category: 'gpt_4',
167
- code_interpreter_model: null,
168
- default_model: 'gpt-4-mobile',
169
- human_category_name: 'GPT-4-Mobile',
170
- plugins_model: null,
171
- subscription_level: 'plus',
172
- });
173
- }
174
- return m;
175
- });
176
- return new Response(JSON.stringify(res), response);
177
- });
178
- };
179
- }
180
149
  });
@@ -1,17 +1,13 @@
1
1
  const shortcuts = {
2
- ArrowUp: () => scrollTo(0, 0),
3
- ArrowDown: () => scrollTo(0, document.body.scrollHeight),
4
- // Don't use command + ArrowLeft or command + ArrowRight
5
- // When editing text in page, it causes unintended page navigation.
6
- // ArrowLeft: () => window.history.back(),
7
- // ArrowRight: () => window.history.forward(),
2
+ 'ArrowUp': () => scrollTo(0, 0),
3
+ 'ArrowDown': () => scrollTo(0, document.body.scrollHeight),
8
4
  '[': () => window.history.back(),
9
5
  ']': () => window.history.forward(),
10
- r: () => window.location.reload(),
6
+ 'r': () => window.location.reload(),
11
7
  '-': () => zoomOut(),
12
8
  '=': () => zoomIn(),
13
9
  '+': () => zoomIn(),
14
- 0: () => setZoom('100%'),
10
+ '0': () => setZoom('100%'),
15
11
  };
16
12
 
17
13
  function setZoom(zoom) {
@@ -40,46 +36,6 @@ function handleShortcut(event) {
40
36
  }
41
37
  }
42
38
 
43
- //这里参考 ChatGPT 的代码
44
- const uid = () => window.crypto.getRandomValues(new Uint32Array(1))[0];
45
-
46
- function transformCallback(callback = () => {}, once = false) {
47
- const identifier = uid();
48
- const prop = `_${identifier}`;
49
- Object.defineProperty(window, prop, {
50
- value: (result) => {
51
- if (once) {
52
- Reflect.deleteProperty(window, prop);
53
- }
54
- return callback(result);
55
- },
56
- writable: false,
57
- configurable: true,
58
- });
59
- return identifier;
60
- }
61
-
62
- async function invoke(cmd, args) {
63
- return new Promise((resolve, reject) => {
64
- if (!window.__TAURI_POST_MESSAGE__)
65
- reject('__TAURI_POST_MESSAGE__ does not exist~');
66
- const callback = transformCallback((e) => {
67
- resolve(e);
68
- Reflect.deleteProperty(window, `_${error}`);
69
- }, true);
70
- const error = transformCallback((e) => {
71
- reject(e);
72
- Reflect.deleteProperty(window, `_${callback}`);
73
- }, true);
74
- window.__TAURI_POST_MESSAGE__({
75
- cmd,
76
- callback,
77
- error,
78
- ...args,
79
- });
80
- });
81
- }
82
-
83
39
  // Judgment of file download.
84
40
  function isDownloadLink(url) {
85
41
  const fileExtensions = [
@@ -105,6 +61,7 @@ function externalTargetLink() {
105
61
  document.addEventListener('DOMContentLoaded', () => {
106
62
  const tauri = window.__TAURI__;
107
63
  const appWindow = tauri.window.appWindow;
64
+ const invoke = tauri.tauri.invoke;
108
65
 
109
66
  const topDom = document.createElement('div');
110
67
  topDom.id = 'pack-top-dom';
@@ -137,42 +94,36 @@ document.addEventListener('DOMContentLoaded', () => {
137
94
  }
138
95
  });
139
96
 
97
+ const isExternalLink = (url, host) => window.location.host !== host;
98
+ const isDownloadRequired = (url, anchorElement, e) =>
99
+ anchorElement.download || e.metaKey || e.ctrlKey || isDownloadLink(url);
100
+
101
+ const handleExternalLink = (e, url) => {
102
+ e.preventDefault();
103
+ tauri.shell.open(url);
104
+ };
105
+
106
+ const handleDownloadLink = (e, url, filename) => {
107
+ e.preventDefault();
108
+ invoke('download_file', { params: { url, filename } });
109
+ };
110
+
140
111
  const detectAnchorElementClick = (e) => {
141
112
  const anchorElement = e.target.closest('a');
142
113
  if (anchorElement && anchorElement.href) {
143
- const target = anchorElement.target;
144
- anchorElement.target = '_self';
145
114
  const hrefUrl = new URL(anchorElement.href);
146
115
  const absoluteUrl = hrefUrl.href;
116
+ let filename = anchorElement.download || getFilenameFromUrl(absoluteUrl);
147
117
 
148
118
  // Handling external link redirection.
149
- if (
150
- window.location.host !== hrefUrl.host &&
151
- (target === '_blank' || target === '_new' || externalTargetLink())
152
- ) {
153
- e.preventDefault && e.preventDefault();
154
- tauri.shell.open(absoluteUrl);
119
+ if (isExternalLink(absoluteUrl, hrefUrl.host) && (['_blank', '_new'].includes(anchorElement.target) || externalTargetLink())) {
120
+ handleExternalLink(e, absoluteUrl);
155
121
  return;
156
122
  }
157
123
 
158
- let filename = anchorElement.download || getFilenameFromUrl(absoluteUrl);
159
-
160
124
  // Process download links for Rust to handle.
161
- // If the download attribute is set, the download attribute is used as the file name.
162
- if (
163
- (anchorElement.download ||
164
- e.metaKey ||
165
- e.ctrlKey ||
166
- isDownloadLink(absoluteUrl)) &&
167
- !externalDownLoadLink()
168
- ) {
169
- e.preventDefault();
170
- invoke('download_file', {
171
- params: {
172
- url: absoluteUrl,
173
- filename,
174
- },
175
- });
125
+ if (isDownloadRequired(absoluteUrl, anchorElement, e) && !externalDownLoadLink()) {
126
+ handleDownloadLink(e, absoluteUrl, filename);
176
127
  }
177
128
  }
178
129
  };
@@ -206,6 +157,12 @@ document.addEventListener('DOMContentLoaded', () => {
206
157
  } catch (e) {
207
158
  console.log(e);
208
159
  }
160
+
161
+ // Fix Chinese input method "Enter" on Safari
162
+ document.addEventListener('keydown', (e) => {
163
+ if (e.keyCode === 229) e.stopPropagation();
164
+ }, true);
165
+
209
166
  });
210
167
 
211
168
  function setDefaultZoom() {
@@ -217,26 +174,7 @@ function setDefaultZoom() {
217
174
 
218
175
  function getFilenameFromUrl(url) {
219
176
  const urlPath = new URL(url).pathname;
220
- const filename = urlPath.substring(urlPath.lastIndexOf('/') + 1);
221
- return filename;
222
- }
223
-
224
- function removeUrlParameters(url) {
225
- const parsedUrl = new URL(url);
226
- parsedUrl.search = '';
227
- return parsedUrl.toString();
228
- }
229
-
230
- // Toggle video playback when the window is hidden.
231
- function toggleVideoPlayback(pause) {
232
- const videos = document.getElementsByTagName('video');
233
- for (const video of videos) {
234
- if (pause) {
235
- video.pause();
236
- } else {
237
- video.play();
238
- }
239
- }
177
+ return urlPath.substring(urlPath.lastIndexOf('/') + 1);
240
178
  }
241
179
 
242
180
  // Collect blob urls to blob by overriding window.URL.createObjectURL
@@ -262,33 +200,49 @@ function convertBlobUrlToBinary(blobUrl) {
262
200
  });
263
201
  }
264
202
 
265
- function downloadFromBlobUrl(blobUrl, filename) {
266
- const tauri = window.__TAURI__;
267
- convertBlobUrlToBinary(blobUrl).then((binary) => {
268
- console.log('binary', binary);
269
- tauri.fs.writeBinaryFile(filename, binary, {
203
+ async function downloadFromBlobUrl(blobUrl, filename) {
204
+ try {
205
+ const tauri = window.__TAURI__;
206
+ const binary = await convertBlobUrlToBinary(blobUrl);
207
+
208
+ await tauri.fs.writeBinaryFile(filename, binary, {
270
209
  dir: tauri.fs.BaseDirectory.Download,
271
- }).then(() => {
272
- window.pakeToast('Download successful, saved to download directory~');
273
210
  });
274
- });
211
+
212
+ const lang = getSystemLanguage();
213
+ window.pakeToast(lang === 'en' ? 'Download successful, saved to download directory~' : '下载成功,已保存到下载目录~');
214
+ } catch (error) {
215
+ console.error('Error downloading from Blob URL:', error);
216
+ }
275
217
  }
276
218
 
219
+
277
220
  // detect blob download by createElement("a")
278
221
  function detectDownloadByCreateAnchor() {
279
- const createEle = document.createElement;
280
- document.createElement = (el) => {
281
- if (el !== 'a') return createEle.call(document, el);
282
- const anchorEle = createEle.call(document, el);
283
-
284
- // use addEventListener to avoid overriding the original click event.
285
- anchorEle.addEventListener('click', () => {
286
- const url = anchorEle.href;
287
- if (window.blobToUrlCaches.has(url)) {
288
- downloadFromBlobUrl(url, anchorEle.download || getFilenameFromUrl(url));
289
- }
290
- });
222
+ const originalCreateElement = document.createElement;
223
+
224
+ document.createElement = function(el, ...args) {
225
+ const element = originalCreateElement.call(this, el, ...args);
226
+
227
+ if (el === 'a') {
228
+ element.addEventListener('click', (event) => {
229
+ const url = element.href;
230
+ if (window.blobToUrlCaches.has(url)) {
231
+ // Prevent default 'click' event if a blob URL is detected
232
+ event.preventDefault();
233
+ const filename = element.download || getFilenameFromUrl(url);
234
+ downloadFromBlobUrl(url, filename);
235
+ }
236
+ });
237
+ }
291
238
 
292
- return anchorEle;
239
+ return element;
293
240
  };
294
241
  }
242
+
243
+
244
+ // Determine the language of the current system.
245
+ function getSystemLanguage() {
246
+ const lang = navigator.language.substr(0, 2);
247
+ return lang === 'ch' ? 'ch' : 'en';
248
+ }
@@ -171,6 +171,7 @@ window.addEventListener('DOMContentLoaded', _event => {
171
171
  #react-root [data-testid="AppTabBar_Explore_Link"],
172
172
  #react-root a[href*="/lists"][role="link"][aria-label],
173
173
  #react-root a[href*="/i/communitynotes"][role="link"][aria-label],
174
+ #react-root a[role="link"][aria-label="Communities"],
174
175
  #react-root a[href*="/i/verified-orgs-signup"][role="link"][aria-label] {
175
176
  display: none !important;
176
177
  }
@@ -53,7 +53,6 @@ pub fn run_app() {
53
53
  #[cfg(target_os = "macos")]
54
54
  {
55
55
  event.window().minimize().unwrap();
56
- // event.window().eval("toggleVideoPlayback(true);").unwrap();
57
56
  }
58
57
 
59
58
  #[cfg(not(target_os = "macos"))]
@@ -33,19 +33,43 @@ pub fn show_toast(window: &Window, message: &str) {
33
33
  window.eval(&script).unwrap();
34
34
  }
35
35
 
36
- pub fn get_download_message() -> String {
37
- let default_message = "Download successful, saved to download directory~";
38
- let chinese_message = "下载成功,已保存到下载目录~";
36
+ pub enum MessageType {
37
+ Start,
38
+ Success,
39
+ Failure,
40
+ }
41
+
42
+ pub fn get_download_message(message_type: MessageType) -> String {
43
+ let default_start_message = "Start downloading~";
44
+ let chinese_start_message = "开始下载中~";
45
+
46
+ let default_success_message = "Download successful, saved to download directory~";
47
+ let chinese_success_message = "下载成功,已保存到下载目录~";
48
+
49
+ let default_failure_message = "Download failed, please check your network connection~";
50
+ let chinese_failure_message = "下载失败,请检查你的网络连接~";
39
51
 
40
52
  env::var("LANG")
41
53
  .map(|lang| {
42
54
  if lang.starts_with("zh") {
43
- chinese_message
55
+ match message_type {
56
+ MessageType::Start => chinese_start_message,
57
+ MessageType::Success => chinese_success_message,
58
+ MessageType::Failure => chinese_failure_message,
59
+ }
44
60
  } else {
45
- default_message
61
+ match message_type {
62
+ MessageType::Start => default_start_message,
63
+ MessageType::Success => default_success_message,
64
+ MessageType::Failure => default_failure_message,
65
+ }
46
66
  }
47
67
  })
48
- .unwrap_or(default_message)
68
+ .unwrap_or_else(|_| match message_type {
69
+ MessageType::Start => default_start_message,
70
+ MessageType::Success => default_success_message,
71
+ MessageType::Failure => default_failure_message,
72
+ })
49
73
  .to_string()
50
74
  }
51
75