import os import yaml from bs4 import BeautifulSoup import json import copy import shutil # Caminho para o arquivo _quarto.yml quarto_config_file = "_quarto.yml" # Caminho para o arquivo _quarto-html.yml quarto_html_config_file = "_quarto-html.yml" with open(quarto_config_file) as f: quarto_config = yaml.safe_load(f) with open(quarto_html_config_file) as f: quarto_html_config = yaml.safe_load(f) # Extrair as informações do arquivo _quarto.yml # funcao para iterar os capítulos def extrair_arquivos_qmd(objeto, capitulos_arquivos_html): if isinstance(objeto, list): for elemento in objeto: extrair_arquivos_qmd(elemento, capitulos_arquivos_html) elif isinstance(objeto, dict): if 'part' in objeto: extrair_arquivos_qmd(objeto['part'], capitulos_arquivos_html) if 'chapters' in objeto: extrair_arquivos_qmd(objeto['chapters'], capitulos_arquivos_html) elif isinstance(objeto, str) and objeto.endswith('.qmd'): capitulos_arquivos_html.append(objeto[:-4]) # pegando o local dos arquivos html pasta_livro_renderizado = quarto_html_config["project"]["output-dir"] # pegando o campo controle-moan para verificar se é um dicionário é_dicionário = quarto_config["controle-moan"]["dicionario"] # pegando os capítulos capitulos = quarto_html_config["book"]["chapters"] capitulos_arquivo_html = [] extrair_arquivos_qmd(capitulos, capitulos_arquivo_html) # Onde ficarao as referencias dos capítulos ref_cap = {} # Letras para 'numerar' os capítulos letras = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'O', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] total_de_letras = len(letras) letras_index_digito_1 = 0 # ver qual é a próxima letra para um capítulo nao numerado def escolher_letra_para_capitulo(letras_index_digito_1): cap = letras[letras_index_digito_1%total_de_letras] # verifica se o cap precisa de um segundo digito if letras_index_digito_1/total_de_letras >= 1: # as duas barras // de divisao pega só a parte inteira da divisao letras_index_digito_2 = (letras_index_digito_1 // total_de_letras) - 1 cap = letras[letras_index_digito_2%total_de_letras] + letras[letras_index_digito_1%total_de_letras] return cap # altera os arquivos html for index, output_file in enumerate(capitulos_arquivo_html): # Caminho completo para o arquivo HTML arquivo_html = os.path.join(pasta_livro_renderizado, output_file + ".html") # conta os elementos que serão uma referencia / Ele começa em 0 na abertura de um novo capítulo ref_num = 0 # Abre o arquivo HTML with open(arquivo_html, "r", encoding="utf-8") as f: content = f.read() # função colocar as referencias nas tags def colocar_referencia(cap, el, ref): # Se a tag tem id, apenas pega o valor e coloca no título da tag e defini unidade_bool false. Se não, cria o id, tb coloca no título da tag e coloca unidade_bool true if el.get("id"): el['title'] = el['id'] unidade_bool = False else: # Define o id da referência el['id'] = f"{cap}P{ref}" # adiciona o title da referência el['title'] = f"{cap}P{ref}" unidade_bool = True # Se unidade_bool for true, adiciona a classe unidade; caso contrário, adiciona a classe unidade_silenciosa. Isso caso a tag já nao possua essas classes if unidade_bool: if not "unidade" in el.get("class", []): el["class"] = el.get("class", []) + ["unidade"] else: if not "unidade_silenciosa" in el.get("class", []) and "unidade" not in el.get("class", []): el["class"] = el.get("class", []) + ["unidade_silenciosa"] # Cria um objeto BeautifulSoup soup = BeautifulSoup(content, "html.parser") # Encontre a tag 'main' no documento main_tag = soup.find("main") # Crie o elemento script com os metadados script_tag = soup.new_tag('script', data="moan-metadados") script_tag.string = f'var metadados = {{livroUrl: "{pasta_livro_renderizado}"}}' # Adicione o script ao cabeçalho (head) do HTML soup.head.append(script_tag) # Se existir o ark, colocar os dados nas tags object do primeiro capítulo do livro if "ark" in quarto_html_config["moan-dados"] and index == 0: ark = quarto_html_config["moan-dados"]["ark"] # Substitua "." por "_p_" e "/" por "_b_" em 'ark' ark = ark.replace(".", "_p_").replace("/", "_b_") # Adicione "ark_dp_" ao início de 'ark' ark = "ark_dp_" + ark # Encontre as tags object com id "metadados_livro_yml" e "metadados_livro_json" obj_metadados_yml = main_tag.find("object", {"id": "metadados_livro_yml"}) obj_metadados_json = main_tag.find("object", {"id": "metadados_livro_json"}) if obj_metadados_yml and obj_metadados_json: # Defina o atributo "data" das tags object obj_metadados_yml["data"] = "https://ark.livro.online/yaml/" + ark + ".yml" obj_metadados_json["data"] = "https://ark.livro.online/json/" + ark + ".json" # Verifique se o arquivo "postos-de-venda.json" existe json_file_path = "postos-de-venda.json" if os.path.exists(json_file_path) and index == 0: # O arquivo JSON existe, abra-o e extraia as chaves e valores with open(json_file_path, "r", encoding="utf-8") as json_file: postos_de_venda = json.load(json_file) # Crie uma nova lista não ordenada para armazenar os links ul = soup.new_tag("ul", id="postos-de-venda") for key, value in postos_de_venda.items(): # Crie uma nova tag de link ("a") com a chave como texto e o valor como src link = soup.new_tag("a", href=value) link.string = key # Define o texto do link como a chave # Adicione o link como um item de lista à lista não ordenada li = soup.new_tag("li") li.append(link) ul.append(li) # Encontre a tag "section" com ID "versão-impressa" section_versao_impressa = main_tag.find("section", id="versão-impressa") if section_versao_impressa: # Adicione a lista não ordenada de links à seção "versão-impressa" section_versao_impressa.append(ul) # Copie o arquivo JSON para a pasta especificada em "pasta_livro_renderizado" dest_file = os.path.join(pasta_livro_renderizado, "postos-de-venda.json") shutil.copy(json_file_path, dest_file) # Definindo o capítulo if index == 0: cap = letras[letras_index_digito_1] # É a letra A, tem que ser a letra A é_um_capitulo_numerado = False ref_cap[cap] = capitulos_arquivo_html[index] else: é_um_capitulo_numerado = False é_um_capitulo_verbete = False # Encontre a primeira tag

h1_tag = soup.find('h1') # Todos os capítulos devem ter uma tag

if h1_tag: # Encontre o primeiro com a classe 'chapter-number' dentro da tag

span_tag = h1_tag.find('span', class_='chapter-number') # Verifique se o com a classe 'chapter-number' foi encontrado dentro do

if span_tag: cap = span_tag.text é_um_capitulo_numerado = True ref_cap[cap] = capitulos_arquivo_html[index] # Verifique se há pelo menos uma tag
com a classe "um_capitulo", ou seja nae é capitulo de verbete caso seja um dicionario encontrou_um_capitulo = bool(main_tag.find('div', class_='um_capitulo')) # Se é um capítulo normal em um dicionário e nao é um capítulo numerado, seleciona a letra para marcar o capítulo # Nao esquecer que deve haver uma div com as classes hidden e um_capitulo em todos os capítulos que nao forem de verbetes em um de um dicionario if not encontrou_um_capitulo and é_dicionário: é_um_capitulo_verbete = True # Coloca os marcadores nos verbetes como o nome do próprio verbete dt_tags = main_tag.find_all('dt') for dt_tag in dt_tags: # Para contar o numero de definicoes dd Num_dd = 0 texto_titulo_dt = dt_tag.text texto_a_ser_sanitizado = dt_tag.text dt_tag['class'] = dt_tag.get("class", []) + ["unidade", "verbete"] dt_tag['title'] = texto_titulo_dt id_dt_tag = (texto_a_ser_sanitizado .replace(' ', '_') .replace('&', '_e_') .replace('$', '_s_') .replace('+', '_mais_') .replace(',', '_vir_') .replace('/', '_barra_') .replace(':', '_dois_pontos_') .replace(';', '_ponto_vir_') .replace('?', '_interrog_') .replace('=', '_igual_') .replace('@', '_at_') .replace('#', '_jv_') .replace('>', '_maiq_') .replace('<', '_menq_') .replace('[', '_abre_colch_') .replace(']', '_fecha_col_') .replace('{', '_abre_ch_') .replace('}', '_fecha_ch_') .replace('.', '_ponto_') .replace('|', '_barra_ver_') .replace('\\', '_barra_inv_') .replace('%', '_p_100_') .replace('^', '_acen_chapeu_') ) dt_tag['id'] = id_dt_tag # Encontre o primeiro elemento irmão
da tag
dd_tag = dt_tag.find_next_sibling('dd') # Itere sobre todas as tags
irmãs até encontrar uma tag não
while dd_tag and dd_tag.name == 'dd': Num_dd += 1 dd_tag['title'] = texto_titulo_dt + " def. " + str(Num_dd) dd_tag['id'] = id_dt_tag + "_def_" + str(Num_dd) # Encontre o próximo elemento irmão
da tag
dd_tag = dd_tag.find_next_sibling('dd') #verifica de há outras tags além de dt, dd, e títulos (usado para o caso de um capítulo de verbete contiver mais conteúdos) tags_procuradas = ['p', 'li', 'tr', 'blockquote', 'code', 'pre'] mais_conteudo_alem_verbetes = False if é_um_capitulo_verbete and é_dicionário: for tag in tags_procuradas: # Verifique se a tag está presente em 'main_tag' if main_tag.find(tag): # Verifique se a tag não tem 'nav' como pai if not main_tag.find(tag).find_parent("nav"): mais_conteudo_alem_verbetes = True break # Se ambas as condições forem atendidas, definimos como True e saímos do loop # Verifica se nao é um capítulo sem numero e se nao for um capítulo de verbete ou se é um capitulo de verbete e se existe outro conteudo alem das definicoes dos verbetes if (not é_um_capitulo_numerado and not é_um_capitulo_verbete) or (é_dicionário and not é_um_capitulo_numerado and é_um_capitulo_verbete and mais_conteudo_alem_verbetes): letras_index_digito_1 += 1 cap = escolher_letra_para_capitulo(letras_index_digito_1) ref_cap[cap] = capitulos_arquivo_html[index] # Iterar sobre todas as tags dentro da tag 'main' for tag in main_tag.find_all(True): # Verifique se a classe 'unidade' está presente nos atributos da tag if "unidade" in tag.get("class", []): # Incrementa o número da referência ref_num += 1 # Coloca a referência na tag colocar_referencia(cap, tag, ref_num) # Pula para a próxima tag continue parent_tag = tag.parent # Não é filho direto de 'td' ou 'li' if parent_tag.name not in ["td", "li", "p"]: # Verifique se a tag é filha de uma tag chamada 'header' usando find_parents(). Em caso positivo, pula is_descendant_of_header = tag.find_parents("header") if is_descendant_of_header: continue # Se é um parágrafo if tag.name == "p" or tag.name == "tr" or tag.name == "li" or tag.name == "code" or tag.name == "blockquote" or (tag.name == "dt" and not é_um_capitulo_verbete) or (tag.name == "dd" and not é_um_capitulo_verbete) or ("quarto-video" in tag.get("class", []) and tag.name == "div") or ("callout" in tag.get("class", []) and tag.name == "div") or ("csl-entry" in tag.get("class", []) and tag.name == "div"): # Incrementa o número da referência ref_num += 1 # Coloca a referência na tag colocar_referencia(cap, tag, ref_num) # Pula para a próxima tag continue # Se for criado pelo usuário um id para euqacoes, aqui coloco a classe unidade_silenciosa para poder ser referenciado quando o usuário solicitar pegar referencia, mas esse tipo de referencia nao deve aparecer na paginacao do capítulo, lá no rodapé if "math" in tag.get("class", []) and tag.name == "span": if tag.parent and tag.parent.name == "span": if tag.parent.get("id"): tag.parent["class"] = tag.parent.get("class", []) + ["unidade_silenciosa"] tag.parent["title"] = tag.parent["id"] continue # Se tiver as classes de teoremas de matemática, colocar unidade_silenciosa if any(classe in tag.get("class", []) for classe in {"theorema", "lemma", "corollary", "proposition", "conjecture", "definition", "example", "exercise"}) and tag.name == "div": if tag.get("id"): tag["class"] = tag.parent.get("class", []) + ["unidade_silenciosa"] tag["title"] = tag.parent["id"] continue # Coloca o conteudo dentro de uma div com id chamado de papel, substituindo o conteudo original da tag main pela div papel # Crie uma div com id "papel" div_papel = soup.new_tag('div', id='papel') # Copie a tag main main_content_copy = copy.copy(main_tag.contents) # Limpe o conteúdo da tag
main_tag.clear() # Adicione a cópia do conteúdo à div "papel" for item_copy in main_content_copy: div_papel.append(item_copy) # Acrescentar a div_papel na tag main main_tag.append(div_papel) # Salva o arquivo HTML modificado with open(arquivo_html, "w", encoding="utf-8") as f: f.write(str(soup)) # Gravar os marcadores de referencia do livro em um arquivo JSON. ele esta na variavel ref_cap e essa informacao será útil para o leitor do livro poder entrar na busca digitar a referenci e obter o conteudo. nome_arquivo = "ref_capitulos.json" caminho_arquivo = os.path.join(pasta_livro_renderizado, nome_arquivo) with open(caminho_arquivo, "w", encoding="utf-8") as arquivo_json: json.dump(ref_cap, arquivo_json, ensure_ascii=False, indent=4)