1use std::path::{Component, Path};
2
3use serde::Deserialize;
4
5use crate::{cache::download, error::Result, types::Chatsound, Chatsounds, Error};
6
7#[derive(Deserialize)]
8pub struct GitHubApiFileEntry {
9 pub path: String,
10 pub r#type: String,
11 pub size: Option<usize>,
12}
13
14#[derive(Deserialize)]
15pub struct GitHubApiTrees {
16 pub tree: Vec<GitHubApiFileEntry>,
17}
18
19pub type GitHubMsgpackEntries = Vec<Vec<String>>;
20
21impl Chatsounds {
22 pub async fn fetch_github_api(&self, repo: &str, _repo_path: &str) -> Result<GitHubApiTrees> {
23 let api_url = format!("https://api.github.com/repos/{repo}/git/trees/HEAD?recursive=1");
24
25 #[cfg(feature = "fs")]
26 let cache = &self.cache_path;
27 #[cfg(feature = "memory")]
28 let cache = self.fs_memory.clone();
29
30 let bytes = download(&api_url, cache, false).await?;
31
32 let trees: GitHubApiTrees =
33 serde_json::from_slice(&bytes).map_err(|err| Error::Json { err, url: api_url })?;
34
35 Ok(trees)
36 }
37
38 pub fn load_github_api(
39 &mut self,
40 repo: &str,
41 repo_path: &str,
42 mut trees: GitHubApiTrees,
43 ) -> Result<()> {
44 for entry in &mut trees.tree {
45 if entry.r#type != "blob" || !entry.path.starts_with(repo_path) {
46 continue;
47 }
48
49 let sound_path = entry.path.split_off(repo_path.len() + 1);
51
52 let path = Path::new(&sound_path);
53 if let Some(Component::Normal(s)) = path.components().nth(1) {
54 if let Some(sentence) = Path::new(&s).file_stem() {
55 let sentence = sentence.to_string_lossy().to_string();
56 let vec = self.map_store.entry(sentence).or_default();
57 let chatsound = Chatsound {
58 repo: repo.to_string(),
59 repo_path: repo_path.to_string(),
60 sound_path,
61 };
62
63 let url = chatsound.get_url();
64 match vec.binary_search_by(|c| c.get_url().cmp(&url)) {
65 Ok(_pos) => {
66 }
68 Err(pos) => {
69 vec.insert(pos, chatsound);
70 }
71 }
72 }
73 }
74 }
75
76 Ok(())
77 }
78
79 pub async fn fetch_github_msgpack(
80 &self,
81 repo: &str,
82 repo_path: &str,
83 ) -> Result<GitHubMsgpackEntries> {
84 let msgpack_url =
85 format!("https://raw.githubusercontent.com/{repo}/HEAD/{repo_path}/list.msgpack");
86
87 #[cfg(feature = "fs")]
88 let cache = &self.cache_path;
89 #[cfg(feature = "memory")]
90 let cache = self.fs_memory.clone();
91
92 let bytes = download(&msgpack_url, cache, false).await?;
93 let entries: GitHubMsgpackEntries =
94 rmp_serde::decode::from_slice(&bytes).map_err(|err| Error::Msgpack {
95 err,
96 url: msgpack_url,
97 })?;
98
99 Ok(entries)
100 }
101
102 pub fn load_github_msgpack(
103 &mut self,
104 repo: &str,
105 repo_path: &str,
106 entries: GitHubMsgpackEntries,
107 ) -> Result<()> {
108 for entry in entries {
109 let sentence = entry[1].clone();
111 let sound_path = entry[2].clone();
112 let vec = self.map_store.entry(sentence.to_string()).or_default();
113
114 let chatsound = Chatsound {
115 repo: repo.to_string(),
116 repo_path: repo_path.to_string(),
117 sound_path,
118 };
119
120 let url = chatsound.get_url();
121 match vec.binary_search_by(|c| c.get_url().cmp(&url)) {
122 Ok(_pos) => {
123 }
125 Err(pos) => {
126 vec.insert(pos, chatsound);
127 }
128 }
129 }
130
131 Ok(())
132 }
133}