mirror of
https://github.com/flibusta-apps/book_bot.git
synced 2025-12-06 15:35:35 +01:00
Add normalize on formating
This commit is contained in:
@@ -168,7 +168,7 @@ where
|
|||||||
let total_pages = items_page.total_pages;
|
let total_pages = items_page.total_pages;
|
||||||
let footer = format!("\n\nСтраница 1/{total_pages}");
|
let footer = format!("\n\nСтраница 1/{total_pages}");
|
||||||
|
|
||||||
let formated_items = items_page.format_items((4096 - footer.len()).try_into().unwrap());
|
let formated_items = items_page.format_items(4096 - footer.len());
|
||||||
|
|
||||||
let message_text = format!("{formated_items}{footer}");
|
let message_text = format!("{formated_items}{footer}");
|
||||||
|
|
||||||
@@ -260,7 +260,7 @@ where
|
|||||||
let total_pages = items_page.total_pages;
|
let total_pages = items_page.total_pages;
|
||||||
let footer = format!("\n\nСтраница {page}/{total_pages}");
|
let footer = format!("\n\nСтраница {page}/{total_pages}");
|
||||||
|
|
||||||
let formated_items = items_page.format_items((4096 - footer.len()).try_into().unwrap());
|
let formated_items = items_page.format_items(4096 - footer.len());
|
||||||
|
|
||||||
let message_text = format!("{formated_items}{footer}");
|
let message_text = format!("{formated_items}{footer}");
|
||||||
|
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ where
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let item_message = item.format(4096);
|
let item_message = item.format(4096).result;
|
||||||
|
|
||||||
bot.send_message(cq.from.id, item_message)
|
bot.send_message(cq.from.id, item_message)
|
||||||
.reply_markup(InlineKeyboardMarkup {
|
.reply_markup(InlineKeyboardMarkup {
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ where
|
|||||||
let total_pages = items_page.total_pages;
|
let total_pages = items_page.total_pages;
|
||||||
let footer = format!("\n\nСтраница {page}/{total_pages}");
|
let footer = format!("\n\nСтраница {page}/{total_pages}");
|
||||||
|
|
||||||
let formated_items = items_page.format_items((4096 - footer.len()).try_into().unwrap());
|
let formated_items = items_page.format_items(4096 - footer.len());
|
||||||
|
|
||||||
let message_text = format!("{formated_items}{footer}");
|
let message_text = format!("{formated_items}{footer}");
|
||||||
|
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ async fn update_log_pagination_handler(
|
|||||||
let total_pages = items_page.total_pages;
|
let total_pages = items_page.total_pages;
|
||||||
let footer = format!("\n\nСтраница {page}/{total_pages}");
|
let footer = format!("\n\nСтраница {page}/{total_pages}");
|
||||||
|
|
||||||
let formated_items = items_page.format_items((4096 - footer.len()).try_into().unwrap());
|
let formated_items = items_page.format_items(4096 - footer.len());
|
||||||
|
|
||||||
let message_text = format!("{header}{formated_items}{footer}");
|
let message_text = format!("{header}{formated_items}{footer}");
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,18 @@ use super::types::{
|
|||||||
TranslatorBook,
|
TranslatorBook,
|
||||||
};
|
};
|
||||||
|
|
||||||
const NO_LIMIT: u32 = 4096;
|
const NO_LIMIT: usize = 4096;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct FormatResult {
|
||||||
|
pub result: String,
|
||||||
|
|
||||||
|
pub current_size: usize,
|
||||||
|
pub max_size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Format {
|
pub trait Format {
|
||||||
fn format(&self, max_size: u32) -> String;
|
fn format(&self, max_size: usize) -> FormatResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FormatInline {
|
pub trait FormatInline {
|
||||||
@@ -51,8 +59,8 @@ fn format_authors(authors: Vec<BookAuthor>, count: usize) -> String {
|
|||||||
|
|
||||||
match !authors.is_empty() {
|
match !authors.is_empty() {
|
||||||
true => {
|
true => {
|
||||||
let formated_authors = authors.clone()[..min(count, authors.len())]
|
let formated_authors = authors[..min(count, authors.len())]
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|author| author.format_inline())
|
.map(|author| author.format_inline())
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join("\n");
|
.join("\n");
|
||||||
@@ -71,8 +79,8 @@ fn format_translators(translators: Vec<Translator>, count: usize) -> String {
|
|||||||
|
|
||||||
match !translators.is_empty() {
|
match !translators.is_empty() {
|
||||||
true => {
|
true => {
|
||||||
let formated_translators = translators.clone()[..min(count, translators.len())]
|
let formated_translators = translators[..min(count, translators.len())]
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|translator| translator.format_inline())
|
.map(|translator| translator.format_inline())
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join("\n");
|
.join("\n");
|
||||||
@@ -91,9 +99,9 @@ fn format_sequences(sequences: Vec<Sequence>, count: usize) -> String {
|
|||||||
|
|
||||||
match !sequences.is_empty() {
|
match !sequences.is_empty() {
|
||||||
true => {
|
true => {
|
||||||
let formated_sequences: String = sequences.clone()[..min(count, sequences.len())]
|
let formated_sequences: String = sequences[..min(count, sequences.len())]
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|sequence| sequence.format(NO_LIMIT))
|
.map(|sequence| sequence.format(NO_LIMIT).result)
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join("\n");
|
.join("\n");
|
||||||
|
|
||||||
@@ -111,8 +119,8 @@ fn format_genres(genres: Vec<BookGenre>, count: usize) -> String {
|
|||||||
|
|
||||||
match !genres.is_empty() {
|
match !genres.is_empty() {
|
||||||
true => {
|
true => {
|
||||||
let formated_genres: String = genres.clone()[..min(count, genres.len())]
|
let formated_genres: String = genres[..min(count, genres.len())]
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|genre| genre.format())
|
.map(|genre| genre.format())
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join("\n");
|
.join("\n");
|
||||||
@@ -125,7 +133,7 @@ fn format_genres(genres: Vec<BookGenre>, count: usize) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Format for Author {
|
impl Format for Author {
|
||||||
fn format(&self, _max_size: u32) -> String {
|
fn format(&self, _max_size: usize) -> FormatResult {
|
||||||
let Author {
|
let Author {
|
||||||
id,
|
id,
|
||||||
last_name,
|
last_name,
|
||||||
@@ -141,23 +149,37 @@ impl Format for Author {
|
|||||||
false => "".to_string(),
|
false => "".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
format!("{title}{link}{annotation}")
|
let result = format!("{title}{link}{annotation}");
|
||||||
|
let result_len = result.len();
|
||||||
|
|
||||||
|
FormatResult {
|
||||||
|
result,
|
||||||
|
current_size: result_len,
|
||||||
|
max_size: result_len
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for Sequence {
|
impl Format for Sequence {
|
||||||
fn format(&self, _max_size: u32) -> String {
|
fn format(&self, _max_size: usize) -> FormatResult {
|
||||||
let Sequence { id, name, .. } = self;
|
let Sequence { id, name, .. } = self;
|
||||||
|
|
||||||
let title = format!("📚 {name}");
|
let title = format!("📚 {name}");
|
||||||
let link = format!("/s_{id}");
|
let link = format!("/s_{id}");
|
||||||
|
|
||||||
format!("{title} {link}")
|
let result = format!("{title} {link}");
|
||||||
|
let result_len = result.len();
|
||||||
|
|
||||||
|
FormatResult {
|
||||||
|
result,
|
||||||
|
current_size: result_len,
|
||||||
|
max_size: result_len
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for Translator {
|
impl Format for Translator {
|
||||||
fn format(&self, _max_size: u32) -> String {
|
fn format(&self, _max_size: usize) -> FormatResult {
|
||||||
let Translator {
|
let Translator {
|
||||||
id,
|
id,
|
||||||
last_name,
|
last_name,
|
||||||
@@ -173,7 +195,14 @@ impl Format for Translator {
|
|||||||
false => "".to_string(),
|
false => "".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
format!("{title}{link}{annotation}")
|
let result = format!("{title}{link}{annotation}");
|
||||||
|
let result_len = result.len();
|
||||||
|
|
||||||
|
FormatResult {
|
||||||
|
result,
|
||||||
|
current_size: result_len,
|
||||||
|
max_size: result_len
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,18 +283,30 @@ struct FormatVectorsResult {
|
|||||||
translators: String,
|
translators: String,
|
||||||
sequences: String,
|
sequences: String,
|
||||||
genres: String,
|
genres: String,
|
||||||
|
|
||||||
|
max_result_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FormatVectorsResult {
|
impl FormatVectorsResult {
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
self.authors.len() + self.translators.len() + self.sequences.len() + self.genres.len()
|
self.authors.len() + self.translators.len() + self.sequences.len() + self.genres.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn with_max_result_size(self, max_result_size: usize) -> Self {
|
||||||
|
let Self { authors, translators, sequences, genres, .. } = self;
|
||||||
|
|
||||||
|
Self {
|
||||||
|
authors,
|
||||||
|
translators,
|
||||||
|
sequences,
|
||||||
|
genres,
|
||||||
|
max_result_size
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Book {
|
impl Book {
|
||||||
fn format_vectors(&self, max_size: u32) -> FormatVectorsResult {
|
fn format_vectors(&self, max_size: usize) -> FormatVectorsResult {
|
||||||
let max_size_u: usize = max_size.try_into().unwrap();
|
|
||||||
|
|
||||||
let mut counts = FormatVectorsCounts {
|
let mut counts = FormatVectorsCounts {
|
||||||
authors: self.authors.len(),
|
authors: self.authors.len(),
|
||||||
translators: self.translators.len(),
|
translators: self.translators.len(),
|
||||||
@@ -278,9 +319,12 @@ impl Book {
|
|||||||
translators: format_translators(self.translators.clone(), counts.translators),
|
translators: format_translators(self.translators.clone(), counts.translators),
|
||||||
sequences: format_sequences(self.sequences.clone(), counts.sequences),
|
sequences: format_sequences(self.sequences.clone(), counts.sequences),
|
||||||
genres: format_genres(self.genres.clone(), counts.genres),
|
genres: format_genres(self.genres.clone(), counts.genres),
|
||||||
|
max_result_size: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
while result.len() > max_size_u && counts.can_sub() {
|
let max_result_size = result.len();
|
||||||
|
|
||||||
|
while result.len() > max_size && counts.can_sub() {
|
||||||
counts = counts.sub();
|
counts = counts.sub();
|
||||||
|
|
||||||
result = FormatVectorsResult {
|
result = FormatVectorsResult {
|
||||||
@@ -288,15 +332,16 @@ impl Book {
|
|||||||
translators: format_translators(self.translators.clone(), counts.translators),
|
translators: format_translators(self.translators.clone(), counts.translators),
|
||||||
sequences: format_sequences(self.sequences.clone(), counts.sequences),
|
sequences: format_sequences(self.sequences.clone(), counts.sequences),
|
||||||
genres: format_genres(self.genres.clone(), counts.genres),
|
genres: format_genres(self.genres.clone(), counts.genres),
|
||||||
|
max_result_size: 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result.with_max_result_size(max_result_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for Book {
|
impl Format for Book {
|
||||||
fn format(&self, max_size: u32) -> String {
|
fn format(&self, max_size: usize) -> FormatResult {
|
||||||
let book_title = {
|
let book_title = {
|
||||||
let Book { title, lang, .. } = self;
|
let Book { title, lang, .. } = self;
|
||||||
|
|
||||||
@@ -319,29 +364,36 @@ impl Format for Book {
|
|||||||
let download_command = (StartDownloadData { id: self.id }).to_string();
|
let download_command = (StartDownloadData { id: self.id }).to_string();
|
||||||
let download_links = format!("Скачать:\n📥{download_command}");
|
let download_links = format!("Скачать:\n📥{download_command}");
|
||||||
|
|
||||||
let required_data_len: u32 = format!("{book_title}{annotations}{download_links}").len().try_into().unwrap();
|
let required_data_len: usize = format!("{book_title}{annotations}{download_links}").len();
|
||||||
let FormatVectorsResult { authors, translators, sequences, genres } = self.format_vectors(
|
let FormatVectorsResult { authors, translators, sequences, genres, max_result_size } = self.format_vectors(
|
||||||
max_size - required_data_len
|
max_size - required_data_len
|
||||||
);
|
);
|
||||||
|
|
||||||
format!("{book_title}{annotations}{authors}{translators}{sequences}{genres}{download_links}")
|
let result = format!("{book_title}{annotations}{authors}{translators}{sequences}{genres}{download_links}");
|
||||||
|
let result_len = result.len();
|
||||||
|
|
||||||
|
FormatResult {
|
||||||
|
result,
|
||||||
|
current_size: result_len,
|
||||||
|
max_size: max_result_size + required_data_len
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for SearchBook {
|
impl Format for SearchBook {
|
||||||
fn format(&self, max_size: u32) -> String {
|
fn format(&self, max_size: usize) -> FormatResult {
|
||||||
self.clone().as_book().format(max_size)
|
self.clone().as_book().format(max_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for AuthorBook {
|
impl Format for AuthorBook {
|
||||||
fn format(&self, max_size: u32) -> String {
|
fn format(&self, max_size: usize) -> FormatResult {
|
||||||
self.clone().as_book().format(max_size)
|
self.clone().as_book().format(max_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for TranslatorBook {
|
impl Format for TranslatorBook {
|
||||||
fn format(&self, max_size: u32) -> String {
|
fn format(&self, max_size: usize) -> FormatResult {
|
||||||
self.clone().as_book().format(max_size)
|
self.clone().as_book().format(max_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use super::formaters::Format;
|
use super::formaters::{Format, FormatResult};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
@@ -76,16 +76,63 @@ impl<T> Page<T>
|
|||||||
where
|
where
|
||||||
T: Format + Clone,
|
T: Format + Clone,
|
||||||
{
|
{
|
||||||
pub fn format_items(&self, max_size: u32) -> String {
|
pub fn format_items(&self, max_size: usize) -> String {
|
||||||
let items_count: u32 = self.items.len().try_into().unwrap();
|
let separator = "\n\n\n";
|
||||||
let item_size: u32 = (max_size - 3 * items_count) / items_count;
|
let separator_len: usize = separator.len();
|
||||||
|
|
||||||
|
let items_count: usize = self.items.len();
|
||||||
|
let item_size: usize = (max_size - separator_len * items_count) / items_count;
|
||||||
|
|
||||||
|
let format_result: Vec<FormatResult> = self.items
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.map(|item| item.format(item_size))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let has_any_spliced = {
|
||||||
|
format_result
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.any(|item| item.current_size != item.max_size)
|
||||||
|
};
|
||||||
|
|
||||||
|
if !has_any_spliced {
|
||||||
|
return format_result
|
||||||
|
.into_iter()
|
||||||
|
.map(|item| item.result)
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut free_symbols: usize = format_result
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|item| item.current_size == item.max_size)
|
||||||
|
.map(|item| item_size - item.current_size)
|
||||||
|
.collect::<Vec<usize>>()
|
||||||
|
.into_iter()
|
||||||
|
.sum();
|
||||||
|
|
||||||
self.items
|
self.items
|
||||||
.clone()
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|item| item.format(item_size))
|
.enumerate()
|
||||||
|
.map(|(index, item)| {
|
||||||
|
let already_formated_result = &format_result[index];
|
||||||
|
|
||||||
|
if already_formated_result.current_size == already_formated_result.max_size {
|
||||||
|
already_formated_result.result.clone()
|
||||||
|
} else {
|
||||||
|
let new_item_size = item_size + free_symbols;
|
||||||
|
let new_formated_result = item.format(new_item_size);
|
||||||
|
|
||||||
|
free_symbols = new_item_size - new_formated_result.current_size;
|
||||||
|
|
||||||
|
new_formated_result.result
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join("\n\n\n")
|
.join(separator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +153,7 @@ pub struct AuthorAnnotation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait AsBook<T> {
|
pub trait AsBook<T> {
|
||||||
fn as_book(self) -> T;
|
fn as_book(&self) -> T;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
@@ -129,8 +176,8 @@ pub struct Book {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AsBook<Book> for Book {
|
impl AsBook<Book> for Book {
|
||||||
fn as_book(self) -> Book {
|
fn as_book(&self) -> Self {
|
||||||
self
|
self.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,16 +196,16 @@ pub struct SearchBook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AsBook<Book> for SearchBook {
|
impl AsBook<Book> for SearchBook {
|
||||||
fn as_book(self) -> Book {
|
fn as_book(&self) -> Book {
|
||||||
Book {
|
Book {
|
||||||
id: self.id,
|
id: self.id,
|
||||||
title: self.title,
|
title: self.title.clone(),
|
||||||
lang: self.lang,
|
lang: self.lang.clone(),
|
||||||
available_types: self.available_types,
|
available_types: self.available_types.clone(),
|
||||||
annotation_exists: self.annotation_exists,
|
annotation_exists: self.annotation_exists,
|
||||||
authors: self.authors,
|
authors: self.authors.clone(),
|
||||||
translators: self.translators,
|
translators: self.translators.clone(),
|
||||||
sequences: self.sequences,
|
sequences: self.sequences.clone(),
|
||||||
genres: vec![],
|
genres: vec![],
|
||||||
pages: None
|
pages: None
|
||||||
}
|
}
|
||||||
@@ -179,16 +226,16 @@ pub struct AuthorBook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AsBook<Book> for AuthorBook {
|
impl AsBook<Book> for AuthorBook {
|
||||||
fn as_book(self) -> Book {
|
fn as_book(&self) -> Book {
|
||||||
Book {
|
Book {
|
||||||
id: self.id,
|
id: self.id,
|
||||||
title: self.title,
|
title: self.title.clone(),
|
||||||
lang: self.lang,
|
lang: self.lang.clone(),
|
||||||
available_types: self.available_types,
|
available_types: self.available_types.clone(),
|
||||||
annotation_exists: self.annotation_exists,
|
annotation_exists: self.annotation_exists,
|
||||||
authors: vec![],
|
authors: vec![],
|
||||||
translators: self.translators,
|
translators: self.translators.clone(),
|
||||||
sequences: self.sequences,
|
sequences: self.sequences.clone(),
|
||||||
genres: vec![],
|
genres: vec![],
|
||||||
pages: None
|
pages: None
|
||||||
}
|
}
|
||||||
@@ -209,16 +256,16 @@ pub struct TranslatorBook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AsBook<Book> for TranslatorBook {
|
impl AsBook<Book> for TranslatorBook {
|
||||||
fn as_book(self) -> Book {
|
fn as_book(&self) -> Book {
|
||||||
Book {
|
Book {
|
||||||
id: self.id,
|
id: self.id,
|
||||||
title: self.title,
|
title: self.title.clone(),
|
||||||
lang: self.lang,
|
lang: self.lang.clone(),
|
||||||
available_types: self.available_types,
|
available_types: self.available_types.clone(),
|
||||||
annotation_exists: self.annotation_exists,
|
annotation_exists: self.annotation_exists,
|
||||||
authors: self.authors,
|
authors: self.authors.clone(),
|
||||||
translators: vec![],
|
translators: vec![],
|
||||||
sequences: self.sequences,
|
sequences: self.sequences.clone(),
|
||||||
genres: vec![],
|
genres: vec![],
|
||||||
pages: None
|
pages: None
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user