164 |
Game can't play audio unless a button has been clicked.
165 |
166 |
167 |
185 |
186 |
187 | END
188 | )
189 |
190 | # Build
191 | cargo build --target wasm32-unknown-unknown --release --bin prpr-player
192 |
193 | # Generate bindgen outputs
194 | mkdir -p dist
195 | wasm-bindgen target/wasm32-unknown-unknown/release/$PROJECT_NAME-player.wasm --out-dir dist --out-name prpr --target web --no-typescript
196 |
197 | # Shim to tie the thing together
198 | sed -i "s/import \* as __wbg_star0 from 'env';//" dist/$PROJECT_NAME.js
199 | sed -i "s/let wasm;/let wasm; export const set_wasm = (w) => wasm = w;/" dist/$PROJECT_NAME.js
200 | sed -i "s/imports\['env'\] = __wbg_star0;/return imports.wbg\;/" dist/$PROJECT_NAME.js
201 | sed -i "s/const imports = getImports();/return getImports();/" dist/$PROJECT_NAME.js
202 |
203 | # Create index from the HTML variable
204 | echo "$HTML" > dist/index.html
--------------------------------------------------------------------------------
/project.yml:
--------------------------------------------------------------------------------
1 | name: prpr
2 | options:
3 | bundleIdPrefix: com.mivik
4 | configs:
5 | Debug: debug
6 | Release: release
7 | targets:
8 | cargo_ios:
9 | type: ""
10 | platform: iOS
11 | legacy:
12 | toolPath: "/Users/sjfhsjfh/.cargo/bin/cargo"
13 | arguments: "build --release --target aarch64-apple-ios --bin prpr-client-main"
14 | workingDirectory: "."
15 | prpr:
16 | sources:
17 | - path: target/aarch64-apple-ios/release/prpr-client-main
18 | buildPhase:
19 | copyFiles:
20 | destination: executables
21 | - path: prpr.app/LaunchScreen.storyboardc
22 | buildPhase: resources
23 | - path: assets
24 | type: folder
25 | buildPhase: resources
26 | type: application
27 | platform: iOS
28 | deploymentTarget: "15.6.1"
29 | scheme:
30 | environmentVariables:
31 | - variable: RUST_BACKTRACE
32 | value: 1
33 | isEnabled: true
34 | - variable: RUST_LOG
35 | value: info
36 | isEnabled: true
37 | - variable: METAL_DEVICE_WRAPPER_TYPE
38 | value: 1
39 | isEnabled: true
40 | dependencies:
41 | - target: cargo_ios
42 | embed: false
43 | info:
44 | path: prpr.app/Info.plist
45 | properties:
46 | UILaunchStoryboardName: LaunchScreen
47 |
--------------------------------------------------------------------------------
/prpr-client-main/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "prpr-client-main"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | [dependencies]
7 | prpr-client = { path = "../prpr-client" }
8 |
--------------------------------------------------------------------------------
/prpr-client-main/src/main.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | prpr_client::quad_main();
3 | }
4 |
--------------------------------------------------------------------------------
/prpr-client/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "prpr-client"
3 | version = "0.3.2"
4 | edition = "2021"
5 |
6 | [lib]
7 | crate-type = ["lib", "cdylib"]
8 |
9 | [features]
10 | closed = ["prpr/closed"]
11 |
12 | [dependencies]
13 | anyhow = "1.0"
14 | base64 = "0.20"
15 | chrono = { version = "0.4.23", features = ["serde"] }
16 | futures-util = "0.3.25"
17 | hex = "0.4.3"
18 | image = "*"
19 | lyon = "*"
20 | macroquad = { git = "https://github.com/Mivik/prpr-macroquad", default-features = false }
21 | md5 = "0.7"
22 | once_cell = "*"
23 | openssl = { version = "*", features = ["vendored"] }
24 | pollster = "0.2.5"
25 | prpr = { path = "../prpr" }
26 | regex = "1.7.0"
27 | reqwest = { version = "0.11", features = ["stream"] }
28 | serde = { version = "*", features = ["derive"] }
29 | serde_json = "*"
30 | sha2 = "*"
31 | tokio = { version = "*", features = ["rt-multi-thread", "sync"] }
32 | uuid7 = "0.3.4"
33 |
34 | [target.'cfg(target_os = "android")'.dependencies]
35 | ndk-sys = "0.2"
36 | ndk-context = "0.1"
37 | sasa = { git = "https://github.com/Mivik/sasa", default-features = false, features = ["oboe"] }
38 |
39 | [target.'cfg(not(target_os = "android"))'.dependencies]
40 | sasa = { git = "https://github.com/Mivik/sasa" }
41 |
42 | [target.'cfg(target_os = "ios")'.dependencies]
43 | objc = "*"
44 | objc-foundation = "*"
45 |
--------------------------------------------------------------------------------
/prpr-client/locales/en-US/about.ftl:
--------------------------------------------------------------------------------
1 | label = About
2 |
3 | about =
4 | prpr-client v{ $version }
5 | prpr is a Phigros simulator designed to provide a unified platform for homemade play. Please consciously abide by the relevant requirements of the community, do not use PRPR maliciously, and do not arbitrarily produce or disseminate low-quality works.
6 |
7 | The default Material Skins used in this software (including note materials and percussion effects) are derived from @MisaLiu's phi-chart-render (https://github.com/MisaLiu/phi-chart-render), signed under the CC BY-NC 4.0 license (https://creativecommons.org/licenses/by-nc/4.0/). During the development of this software, these materials were resized and compressed for use.
8 |
9 | Great thanks to @sjfhsjfh, @helloyanis, @inokana, @kagari939 for their help and contributions!
10 |
11 | prpr is open source software under the GNU General Public License v3.0.
12 | Test Group:660488396
13 | GitHub: https://github.com/Mivik/prpr
14 | Support prpr: https://afdian.net/a/mivik
15 |
--------------------------------------------------------------------------------
/prpr-client/locales/en-US/account.ftl:
--------------------------------------------------------------------------------
1 | label = Account
2 |
3 | email = Email
4 | username = Username
5 | password = Password
6 |
7 | back = Back
8 | register = Register
9 | registering = Registering
10 | login = Login
11 | logging-in = Logging in
12 | logout = Logout
13 | edit-name = Modify name
14 |
15 | not-logged-in = [Not logged in]
16 |
17 | logged-out = Logged out
18 |
19 | pictrue-read-failed = Unable to read the picture
20 | pictrue-load-failed = Unable to load image
21 | avatar-import-failed = Failed to import avatar
22 | avatar-upload-failed = Failed to upload avatar
23 | avatar-delete-old-failed = Failed to delete the original avatar
24 | avatar-update-failed = Failed to update avatar
25 |
26 | name-length-req = Username length should be between 4 and 20
27 | name-has-illegal-char = Username contains illegal characters
28 | pwd-length-req = Password length should be between 6 and 26
29 | illegal-email = Illegal email
30 |
31 | email-sent = An verification email has been sent, please verify and log in
32 |
33 | action-success = { $action ->
34 | [login] Logged in successfully
35 | [register] Registered successfully
36 | [edit-name] Name modified
37 | [set-avatar] Avatar updated
38 | [update] Info updated
39 | *[other] _
40 | }
41 | action-failed = { $action ->
42 | [login] Failed to log in
43 | [register] Failed to register
44 | [edit-name] Failed to modify username
45 | [set-avatar] Failed to upload avatar
46 | [update] Failed to update info
47 | *[other] _
48 | }
49 |
--------------------------------------------------------------------------------
/prpr-client/locales/en-US/chart_order.ftl:
--------------------------------------------------------------------------------
1 | time = Time
2 | rev-time = Time (rev)
3 | name = Name
4 | rev-name = Name (rev)
5 |
--------------------------------------------------------------------------------
/prpr-client/locales/en-US/local.ftl:
--------------------------------------------------------------------------------
1 | label = Local
2 |
3 | import-failed = Failed to import
4 | import-success = Imported successfully
5 |
6 | not-loaded = Not yet finished loading
7 |
--------------------------------------------------------------------------------
/prpr-client/locales/en-US/main_scene.ftl:
--------------------------------------------------------------------------------
1 | welcome = Welcome back
2 |
3 | cannot-find-chart = Beatmap not found
4 |
5 | delete-success = Deleted successfully
6 | delete-failed = Failed to delete
7 |
--------------------------------------------------------------------------------
/prpr-client/locales/en-US/message.ftl:
--------------------------------------------------------------------------------
1 | label = Messages
2 |
3 | load-failed = Failed to load message
4 |
5 | updated = Updated on { $time }
6 |
--------------------------------------------------------------------------------
/prpr-client/locales/en-US/online.ftl:
--------------------------------------------------------------------------------
1 | label = Online
2 |
3 | loading = Loading
4 | loaded = Charts loaded
5 | load-failed = Loading failed
6 |
7 | page-indicator = Page { $now }/{ $total }
8 | prev-page = Prev page
9 | next-page = Next page
10 |
--------------------------------------------------------------------------------
/prpr-client/locales/en-US/settings.ftl:
--------------------------------------------------------------------------------
1 | label = Settings
2 |
3 | switch-language = 中文
4 | theme-prompt = Theme: { $name }
5 |
6 | respack-loaded = Resource pack loaded
7 | respack-load-failed = Failed to load resource pack
8 | respack-save-failed = Failed to save resource pack
9 |
10 | autoplay = Autoplay
11 | double-tips = Double tips
12 | fixed-aspect-ratio = Fixed aspect ratio
13 | time-adjustment = Automatic time adjustment
14 | particles = Particles
15 | aggressive-opt = Aggressive optimization
16 | low-perf-mode = Low performance mode
17 | player-rks = Player RKS
18 | offset = Offset (s)
19 | speed = Speed
20 | note-size = Note size
21 | music-vol = Music volume
22 | sfx-vol = Sound effects volume
23 | chal-color = Challenge mode color
24 | chal-colors = White,Green,Blue,Red,Gold,Rainbow
25 | chal-level = Challenge mode level
26 | double-click-pause = Double click to pause
27 |
28 | respack = Respack
29 | reset = Reset
30 | audio-buffer = Audio buffer
31 |
32 | default = [Default]
33 | invalid-input = Invalid input
34 | reset-all = Restore default settings
35 | confirm-reset = Sure?
36 | reset-all-done = Settings are restored
37 | save-failed = Failed to save config
38 |
--------------------------------------------------------------------------------
/prpr-client/locales/en-US/song.ftl:
--------------------------------------------------------------------------------
1 |
2 | load-chart-info-failed = Failed to load beatmap information
3 |
4 | text-part =
5 | { $intro }
6 | { $tags }
7 |
8 | Difficulty:{ $level } ({ $difficulty })
9 | Composer:{ $composer }
10 | Illustrator:{ $illustrator }
11 |
12 | guest = Guest
13 |
14 | load-illu-failed = Failed to load illustration
15 | load-chart-failed = Failed to load the beatmap
16 |
17 | ldb = Leaderboard
18 | ldb-loading = Loading…
19 | ldb-rank = #{ $rank }
20 | ldb-upload-error = Error(Code { $code }):{ $error }
21 | ldb-server-no-resp = Server did not respond
22 | ldb-load-failed = Failed to load leaderboard
23 |
24 | tools = Tools
25 | adjust-offset = Adjust offset
26 | exercise-mode = Exercise mode
27 |
28 | save-success = Saved successfully
29 | save-failed = Save failed
30 |
31 | already-downloaded = Already downloaded
32 | downloading = Downloading
33 | request-failed = Request failed
34 | download-cancelled = Download cancelled
35 | download-success = Downloaded
36 | download-failed = Failed to download
37 |
38 | edit-cancel = Cancel
39 | edit-upload = Upload
40 | edit-save = Save
41 | edit-saving = Saving…
42 | edit-builtin = You cannot change built-in beatmaps
43 | edit-fix-chart = Fix beatmap
44 | edit-load-file-failed = Failed to load file
45 | edit-save-config-failed = Failed to save configuration
46 | edit-save-failed = Failed to save file
47 |
48 | fix-chart-success = Repair successful
49 | fix-chart-failed = Repair failed
50 |
51 | upload-login-first = Please login first!
52 | upload-builtin = Built-in beatmaps cannot be uploaded
53 | upload-downloaded = Downloaded beatmaps cannot be uploaded
54 | upload-rules = Upload rules
55 | upload-rules-content =
56 | Before uploading, you need to confirm that:
57 | 1. The beatmap was created by me, or the act of uploading it has been approved by the scorer. If it is the second case, it needs to be indicated in the beatmap introduction that it is uploaded on behalf of a person;
58 | 2. If the beatmap is created by yourself, it is recommended to use a highly recognizable avatar and ID; If the avatar ID you use in prpr is quite different from the self-made score video publishing platform (specifically, BiliBili), additional annotations are required;
59 | 3. ! It is forbidden to violate the rules and upload the beatmap without the consent of the scorer, otherwise you may face the penalty of permanent ban on uploading;
60 | 4. The content of the beatmap (including music, illustrations, text, etc.) must comply with other laws and regulations of the People's Republic of China, and must not violate the law or contain bad information.
61 | upload-cancel = Cancel
62 | upload-confirm = Confirm
63 | uploading = Uploading
64 | upload-read-file-failed = Failed to read file
65 | upload-chart-too-large = The beatmap file is too large
66 | upload-illu-too-large = The illustration file is too large
67 | upload-read-chart-failed = Failed to read beatmap
68 | upload-read-illu-failed = Failed to read illustration
69 | uploading-chart = Beatmap…
70 | upload-chart-failed = Failed to upload beatmap
71 | uploading-illu = Illustration…
72 | upload-illu-failed = Failed to upload illustration
73 | upload-saving = Saving…
74 | upload-save-failed = Failed to upload
75 | upload-success = Uploaded successfully, please wait for review!
76 | upload-failed = Upload failed
77 |
78 | review-del = Review: Delete
79 | review-deny = Review: Deny
80 | review-approve = Review: Approve
81 | review-exec = Executing
82 | review-suc = Executed successfully
83 | review-wait = Please wait until the last task is done
84 | review-del-confirm = Are you sure?
85 |
--------------------------------------------------------------------------------
/prpr-client/locales/zh-CN/about.ftl:
--------------------------------------------------------------------------------
1 | label = 关于
2 |
3 | about =
4 | prpr-client v{ $version }
5 | prpr 是一款 Phigros 模拟器,旨在为自制谱游玩提供一个统一化的平台。请自觉遵守社群相关要求,不恶意使用 prpr,不随意制作或传播低质量作品。
6 |
7 | 本软件使用的默认材质皮肤(包括音符材质和打击特效)来自于 @MisaLiu 的 phi-chart-render(https://github.com/MisaLiu/phi-chart-render),在 CC BY-NC 4.0 协议(https://creativecommons.org/licenses/by-nc/4.0/)下署名。在本软件的开发过程中,这些材质被调整尺寸并压缩以便使用。
8 |
9 | 感谢 @sjfhsjfh, @helloyanis, @inokana, @kagari939 等为本项目做出的贡献!
10 |
11 | prpr 是开源软件,遵循 GNU General Public License v3.0 协议。
12 | 测试群:660488396
13 | GitHub:https://github.com/Mivik/prpr
14 | 欢迎在爱发电上支持 prpr 的开发:https://afdian.net/a/mivik
15 |
--------------------------------------------------------------------------------
/prpr-client/locales/zh-CN/account.ftl:
--------------------------------------------------------------------------------
1 | label = 账户
2 |
3 | email = 邮箱
4 | username = 用户名
5 | password = 密码
6 |
7 | back = 返回
8 | register = 注册
9 | registering = 注册中
10 | login = 登录
11 | logging-in = 登录中
12 | logout = 退出登录
13 | edit-name = 修改名称
14 |
15 | not-logged-in = [尚未登录]
16 |
17 | logged-out = 退出登录成功
18 |
19 | pictrue-read-failed = 无法读取图片
20 | pictrue-load-failed = 无法加载图片
21 | avatar-import-failed = 导入头像失败
22 | avatar-upload-failed = 上传头像失败
23 | avatar-delete-old-failed = 删除原头像失败
24 | avatar-update-failed = 更新头像失败
25 |
26 | name-length-req = 用户名长度应介于 4-20 之间
27 | name-has-illegal-char = 用户名包含非法字符
28 | pwd-length-req = 密码长度应介于 6-26 之间
29 | illegal-email = 邮箱不合法
30 |
31 | email-sent = 验证信息已发送到邮箱,请验证后登录
32 |
33 | action-success = { $action ->
34 | [login] 登录成功
35 | [register] 注册成功
36 | [edit-name] 更新名称成功
37 | [set-avatar] 更新头像成功
38 | [update] 更新数据成功
39 | *[other] _
40 | }
41 | action-failed = { $action ->
42 | [login] 登录失败
43 | [register] 注册失败
44 | [edit-name] 更新名称失败
45 | [set-avatar] 更新头像失败
46 | [update] 更新数据失败
47 | *[other] _
48 | }
49 |
--------------------------------------------------------------------------------
/prpr-client/locales/zh-CN/chart_order.ftl:
--------------------------------------------------------------------------------
1 | time = 从新到旧
2 | rev-time = 从旧到新
3 | name = 名字正序
4 | rev-name = 名字倒序
5 |
--------------------------------------------------------------------------------
/prpr-client/locales/zh-CN/local.ftl:
--------------------------------------------------------------------------------
1 | label = 本地
2 |
3 | import-failed = 导入失败
4 | import-success = 导入成功
5 |
6 | not-loaded = 尚未加载完成
7 |
--------------------------------------------------------------------------------
/prpr-client/locales/zh-CN/main_scene.ftl:
--------------------------------------------------------------------------------
1 | welcome = 欢迎回来
2 |
3 | cannot-find-chart = 找不到谱面
4 |
5 | delete-success = 已删除
6 | delete-failed = 删除失败
7 |
--------------------------------------------------------------------------------
/prpr-client/locales/zh-CN/message.ftl:
--------------------------------------------------------------------------------
1 | label = 消息
2 |
3 | load-failed = 加载消息失败
4 |
5 | updated = 更新于 { $time }
6 |
--------------------------------------------------------------------------------
/prpr-client/locales/zh-CN/online.ftl:
--------------------------------------------------------------------------------
1 | label = 在线
2 |
3 | loading = 正在加载
4 | loaded = 加载完成
5 | load-failed = 加载失败
6 |
7 | page-indicator = 第 { $now }/{ $total } 页
8 | prev-page = 上一页
9 | next-page = 下一页
10 |
--------------------------------------------------------------------------------
/prpr-client/locales/zh-CN/settings.ftl:
--------------------------------------------------------------------------------
1 | label = 设置
2 |
3 | switch-language = English
4 | theme-prompt = 主题:{ $name }
5 |
6 | respack-loaded = 资源包加载成功
7 | respack-load-failed = 加载资源包失败
8 | respack-save-failed = 保存资源包失败
9 |
10 | autoplay = 自动游玩
11 | double-tips = 双押提示
12 | fixed-aspect-ratio = 固定宽高比
13 | time-adjustment = 自动对齐时间
14 | particles = 粒子效果
15 | aggressive-opt = 激进优化
16 | low-perf-mode = 低性能模式
17 | player-rks = 玩家 RKS
18 | offset = 偏移(s)
19 | speed = 速度
20 | note-size = 音符大小
21 | music-vol = 音乐音量
22 | sfx-vol = 音效音量
23 | chal-color = 挑战模式颜色
24 | chal-colors = 白,绿,蓝,红,金,彩
25 | chal-level = 挑战模式等级
26 | double-click-pause = 双击暂停
27 |
28 | respack = 资源包
29 | reset = 重置
30 | audio-buffer = 音频缓冲区
31 |
32 | default = [默认]
33 | invalid-input = 输入非法
34 | reset-all = 恢复默认设定
35 | confirm-reset = 确定?
36 | reset-all-done = 设定恢复成功
37 | save-failed = 保存设定失败
38 |
--------------------------------------------------------------------------------
/prpr-client/locales/zh-CN/song.ftl:
--------------------------------------------------------------------------------
1 |
2 | load-chart-info-failed = 加载谱面信息失败
3 |
4 | text-part =
5 | { $intro }
6 | { $tags }
7 |
8 | 难度:{ $level } ({ $difficulty })
9 | 曲师:{ $composer }
10 | 插图:{ $illustrator }
11 |
12 | guest = 游客
13 |
14 | load-illu-failed = 加载插图失败
15 | load-chart-failed = 加载谱面失败
16 |
17 | ldb = 排行榜
18 | ldb-loading = 加载中…
19 | ldb-rank = #{ $rank }
20 | ldb-upload-error = 错误(代码 { $code }):{ $error }
21 | ldb-server-no-resp = 服务器无响应
22 | ldb-load-failed = 加载排行榜失败
23 |
24 | tools = 功能
25 | adjust-offset = 调整延迟
26 | exercise-mode = 分段练习
27 |
28 | save-success = 保存成功
29 | save-failed = 保存失败
30 |
31 | already-downloaded = 已经下载过
32 | downloading = 正在下载
33 | request-failed = 请求失败
34 | download-cancelled = 已取消
35 | download-success = 下载完成
36 | download-failed = 下载失败
37 |
38 | edit-cancel = 取消
39 | edit-upload = 上传
40 | edit-save = 保存
41 | edit-saving = 保存中…
42 | edit-builtin = 不能更改内置谱面
43 | edit-fix-chart = 自动修复谱面
44 | edit-load-file-failed = 加载文件失败
45 | edit-save-config-failed = 写入配置文件失败
46 | edit-save-failed = 保存文件失败
47 |
48 | fix-chart-success = 修复成功
49 | fix-chart-failed = 修复失败
50 |
51 | upload-login-first = 请先登录!
52 | upload-builtin = 不能上传内置谱面
53 | upload-downloaded = 不能上传下载的谱面
54 | upload-rules = 上传须知
55 | upload-rules-content =
56 | 在上传前,你需要确认:
57 | 1. 谱面为本人创作,或上传行为已经通过谱师本人同意。如果是第二种情况,需要在谱面简介中注明是代人上传;
58 | 2. 如果是谱面是本人创作,建议使用辨识度高的头像和 ID;如果你在 prpr 使用的头像 ID 与自制谱视频发布平台(具体而言,BiliBili)有较大出入,需要额外标注;
59 | 3. !禁止违反规则未经谱师同意随意上传谱面,否则可能面临永久禁止上传的惩罚;
60 | 4. 谱面内容(包括音乐、插图、文字等)须符合中华人民共和国其他法律法规,不得违法或包含不良信息。
61 | upload-cancel = 再想想
62 | upload-confirm = 确认上传
63 | uploading = 上传中…
64 | upload-read-file-failed = 读取文件失败
65 | upload-chart-too-large = 谱面文件过大
66 | upload-illu-too-large = 插图文件过大
67 | upload-read-chart-failed = 读取谱面失败
68 | upload-read-illu-failed = 读取谱面失败
69 | uploading-chart = 上传谱面中…
70 | upload-chart-failed = 上传谱面失败
71 | uploading-illu = 上传插图中…
72 | upload-illu-failed = 上传插图失败
73 | upload-saving = 保存中…
74 | upload-save-failed = 上传失败
75 | upload-success = 上传成功,请等待审核!
76 | upload-failed = 上传失败
77 |
78 | review-del = 审核:删除
79 | review-deny = 审核:拒绝
80 | review-approve = 审核:通过
81 | review-exec = 执行中
82 | review-suc = 执行成功
83 | review-wait = 请等待上一次操作完成
84 | review-del-confirm = 你确定吗?
85 |
--------------------------------------------------------------------------------
/prpr-client/src/cloud/file.rs:
--------------------------------------------------------------------------------
1 | use super::UploadToken;
2 | use anyhow::{bail, Context, Result};
3 | use reqwest::header;
4 | use serde::Serialize;
5 | use serde_json::{json, Value};
6 |
7 | const SIZE: usize = 4 * 1024 * 1024;
8 |
9 | pub(super) async fn upload_qiniu(token: UploadToken, data: &[u8]) -> Result<()> {
10 | #[derive(Serialize)]
11 | #[serde(rename_all = "camelCase")]
12 | struct QiniuPart {
13 | part_number: usize,
14 | etag: String,
15 | }
16 | let encoded_name = base64::encode(token.key.as_bytes());
17 | let auth = format!("UpToken {}", token.token);
18 | let client = reqwest::Client::new();
19 | let prefix = format!("{}/buckets/{}/objects/{encoded_name}/uploads", token.upload_url, token.bucket);
20 | let upload_id = {
21 | let resp = client
22 | .post(&prefix)
23 | .header(header::AUTHORIZATION, &auth)
24 | .send()
25 | .await
26 | .context("Failed to request upload id")?;
27 | let status = resp.status();
28 | let text = resp.text().await.context("Failed to receive text")?;
29 | if !status.is_success() {
30 | bail!("Failed to request upload id: {text}");
31 | }
32 | let value: Value = serde_json::from_str(&text)?;
33 | value["uploadId"].as_str().unwrap().to_owned()
34 | };
35 | let prefix = format!("{prefix}/{upload_id}");
36 | let mut parts = Vec::new();
37 | for (id, chunk) in data.chunks(SIZE).enumerate() {
38 | let id = id + 1;
39 | let resp = client
40 | .put(format!("{prefix}/{}", id))
41 | .header(header::AUTHORIZATION, &auth)
42 | .header(header::CONTENT_TYPE, "application/octet-stream")
43 | .header("Content-MD5", base64::encode(md5::compute(chunk).0))
44 | .body(chunk.to_owned())
45 | .send()
46 | .await?;
47 | let status = resp.status();
48 | let text = resp.text().await.context("Failed to receive text")?;
49 | if !status.is_success() {
50 | bail!("Failed to upload file: {text}");
51 | }
52 | let value: Value = serde_json::from_str(&text)?;
53 | parts.push(QiniuPart {
54 | part_number: id,
55 | etag: value["etag"].as_str().unwrap().to_owned(),
56 | });
57 | }
58 | let resp = client
59 | .post(prefix)
60 | .header(header::AUTHORIZATION, &auth)
61 | .header(header::CONTENT_TYPE, "application/json")
62 | .body(serde_json::to_string(&json!({ "parts": parts }))?)
63 | .send()
64 | .await?;
65 | if !resp.status().is_success() {
66 | bail!("Failed to upload file: {}", resp.text().await?);
67 | }
68 | Ok(())
69 | }
70 |
--------------------------------------------------------------------------------
/prpr-client/src/cloud/images.rs:
--------------------------------------------------------------------------------
1 | use super::LCFile;
2 | use crate::dir;
3 | use anyhow::{Context, Result};
4 | use image::imageops::thumbnail;
5 | use image::DynamicImage;
6 | use prpr::ext::SafeTexture;
7 | use std::future::Future;
8 | use std::path::Path;
9 |
10 | pub const THUMBNAIL_WIDTH: u32 = 347;
11 | pub const THUMBNAIL_HEIGHT: u32 = 200;
12 |
13 | pub struct Images;
14 | impl Images {
15 | pub fn into_texture(tex: (DynamicImage, Option