Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webdriver update #3

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
FROM python:3.8-slim-buster

WORKDIR /app
RUN apt-get update && \
apt-get install -y --no-install-recommends \
wkhtmltopdf \
gcc \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*

RUN pip install \
pylint \
Expand Down
44 changes: 40 additions & 4 deletions app/api.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
"""API Module"""

import os
from flask import Flask, json
import tempfile
from flask import Flask, json, render_template, request, jsonify, send_file
from cifraclub import CifraClub
from get_pdf import create_pdf_with_columns_portrait as gen_pdf

app = Flask(__name__)

@app.route('/')
@app.route("/")
def index():
return render_template("index.html")

@app.route('/home')
def home():
"""Home route"""
return app.response_class(
Expand All @@ -15,14 +21,44 @@ def home():
mimetype='application/json'
)


@app.route("/submit", methods=["POST"])
def submit():
data = request.json
items = data["items"]
file_name = data["fileName"]

# Criando um arquivo temporário para armazenar o PDF
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as temp_pdf:
temp_file_path = temp_pdf.name # Caminho do arquivo temporário

# Gerar o PDF no arquivo temporário
gen_pdf(items, temp_file_path)

# Enviar o arquivo para o cliente
try:
return send_file(
temp_file_path, as_attachment=True, download_name=f"{file_name}.pdf"
)
finally:
# Após o envio, deletar o arquivo temporário
if os.path.exists(temp_file_path):
os.remove(temp_file_path)


@app.route('/artists/<artist>/songs/<song>')
def get_cifra(artist, song):
"""Get cifra by artist and song"""
cifrablub = CifraClub()
musica = cifrablub.cifra(artist, song)

saida = f"Artista: {musica['artist']}\nMusica: {musica['name']}\nYoutube: {musica['youtube_url']}\n\n"
for cifra in musica['cifra']:
saida = saida + "\n "+cifra
return app.response_class(
response=json.dumps(cifrablub.cifra(artist, song), ensure_ascii=False),
response=saida,
status=200,
mimetype='application/json'
mimetype="application/json",
)

if __name__ == "__main__":
Expand Down
14 changes: 12 additions & 2 deletions app/cifraclub.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,24 @@
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
# from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.firefox.options import Options

CIFRACLUB_URL = "https://www.cifraclub.com.br/"

class CifraClub():
"""CifraClub Class"""
def __init__(self):
self.driver = webdriver.Remote("http://selenium:4444/wd/hub", DesiredCapabilities.FIREFOX)
options = Options()
options.add_argument('--headless') # Executar o navegador em modo headless (opcional)
options.add_argument('--no-sandbox') # Necessário em alguns ambientes como Docker
options.add_argument('--disable-dev-shm-usage') # Evita problemas de memória compartilhada

self.driver = webdriver.Remote(
command_executor="http://selenium:4444/wd/hub",
options=options,
# desired_capabilities=options.to_capabilities() # Garante compatibilidade
)

def cifra(self, artist: str, song: str) -> dict:
"""Lê a página HTML e extrai a cifra e meta dados da música."""
Expand Down
63 changes: 63 additions & 0 deletions app/get_pdf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from reportlab.lib.pagesizes import letter, A4
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch
import requests


def create_pdf_with_columns_portrait(data_list, output_pdf):
# Configurações básicas para o formato retrato
page_width, page_height = A4
margin = 0.2 * inch
column_gap = 0.1 * inch
column_width = (page_width - 2 * margin - column_gap) / 2

# Iniciar canvas
c = canvas.Canvas(output_pdf, pagesize=A4)

for data in data_list:
text_obj = c.beginText()
text_obj.setFont("Courier", 9)
text_obj.setTextOrigin(margin, page_height - margin)

title = data["title"]
link = data["link"]

# Extrair artista e música do link
artista, musica = link.rstrip("/").split("/")[-2:]
url = f"http://localhost:3000/artists/{artista}/songs/{musica}"
response = requests.get(url)
response.raise_for_status()
text = response.text

# Escrever título (opcional)
text_obj.setFont("Courier-Bold", 10)
text_obj.textLine(f"{title}")
text_obj.setFont("Courier", 9)
text_obj.textLine("") # Linha em branco

column = 0
for line in text.splitlines():
if text_obj.getY() < margin:
# Alternar coluna ou adicionar nova página
if column == 0:
column = 1
text_obj.setTextOrigin(
margin + column_width + column_gap, page_height - margin
)
else:
c.drawText(text_obj)
c.showPage()
text_obj = c.beginText()
text_obj.setFont("Courier", 9)
text_obj.setTextOrigin(margin, page_height - margin)
column = 0

# Adicionar linha ao texto
text_obj.textLine(line.rstrip())

# Renderizar o conteúdo do link na página atual
c.drawText(text_obj)
c.showPage() # Garantir nova página para o próximo link

# Renderizar a última página
c.save()
9 changes: 6 additions & 3 deletions app/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Flask==2.2.2
beautifulsoup4==4.11.1
selenium==4.6.0
flask
bs4
selenium
pdfkit
reportlab
requests
5 changes: 5 additions & 0 deletions app/src/format.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
body {
column-count: 2;
column-gap: 1.5em;
/* Ajuste o espaçamento entre as colunas */
}
125 changes: 125 additions & 0 deletions app/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<!DOCTYPE html>
<html lang="pt-br">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Formulário</title>

<!-- Incluir Bootstrap para o layout -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">

<script>
let items = [];

// Função para adicionar título e link à lista
function addToComboBox() {
const titleInput = document.getElementById("title");
const linkInput = document.getElementById("link");
const comboBox = document.getElementById("comboBox");

const title = titleInput.value.trim();
const link = linkInput.value.trim();

if (title && link) {
const item = { title, link };
items.push(item);

const option = document.createElement("option");
option.value = `${title} - ${link}`;
option.textContent = `${title} - ${link}`;
comboBox.appendChild(option);

titleInput.value = '';
linkInput.value = '';
} else {
alert("Preencha ambos os campos!");
}
}

// Função para enviar o formulário
function submitForm() {
const fileNameInput = document.getElementById("fileName");
const fileName = fileNameInput.value.trim();

if (!fileName) {
alert("Por favor, insira um nome para o arquivo!");
return;
}

const requestData = {
items: items,
fileName: fileName
};

// Exibir "Carregando..." e desabilitar o botão
document.getElementById("loadingMessage").style.display = "block";
document.getElementById("submitButton").disabled = true;

fetch('/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestData),
})
.then(response => response.blob()) // Receber o arquivo como blob
.then(blob => {
// Criar link para download do arquivo PDF
const downloadLink = document.createElement("a");
const url = URL.createObjectURL(blob);
downloadLink.href = url;
downloadLink.download = `${fileName}.pdf`;
downloadLink.click(); // Iniciar download

alert("PDF gerado com sucesso!");
})
.catch(error => {
console.error("Erro ao enviar dados:", error);
alert("Ocorreu um erro ao processar a requisição!");
})
.finally(() => {
// Esconder "Carregando..." e habilitar o botão novamente
document.getElementById("loadingMessage").style.display = "none";
document.getElementById("submitButton").disabled = false;
});
}
</script>
</head>

<body>
<div class="container mt-4">
<h1>Criando SetList</h1>
<form onsubmit="event.preventDefault(); addToComboBox();">
<div class="mb-3">
<label for="title" class="form-label">Momento:</label>
<input type="text" id="title" name="title" class="form-control" required>
</div>
<div class="mb-3">
<label for="link" class="form-label">Link:</label>
<input type="url" id="link" name="link" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary">Adicionar</button>
</form>

<h2 class="mt-4">Lista de músicas</h2>
<select id="comboBox" size="10" class="form-select mb-3" style="width: 100%;"></select>

<div class="mb-3">
<label for="fileName" class="form-label">Nome do Arquivo:</label>
<input type="text" id="fileName" name="fileName" class="form-control" required>
</div>

<button id="submitButton" class="btn btn-success" onclick="submitForm()">Enviar</button>

<!-- Mensagem de Carregando -->
<div id="loadingMessage" class="mt-3" style="display: none;">
<div class="alert alert-info" role="alert">Carregando... Por favor, aguarde.</div>
</div>
</div>

<!-- Incluir o JS do Bootstrap -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>

</html>