Skip to content

Releases: openwave-player/openwave

OpenWave 0.1.5

04 Jun 21:47
f0c2452

Choose a tag to compare

Esta versão traz melhorias significativas na estabilidade, fluidez da interface (UI) e desempenho geral do OpenWave. O foco principal foi eliminar travamentos ao carregar grandes bibliotecas musicais e otimizar o consumo de recursos do sistema.

O que há de novo?

Escaneamento de Biblioteca em Background (Não-Bloqueante)

  • Antes: Ao selecionar uma pasta com milhares de músicas, a interface do OpenWave congelava até que o Mutagen terminasse de ler os metadados de todos os arquivos.
  • Agora: O processo de varredura e indexação de arquivos foi movido para uma thread secundária assíncrona (threading.Thread). A interface permanece 100% responsiva, exibindo um estado visual de carregamento inteligente enquanto processa as faixas em segundo plano.

Busca Otimizada com Debounce (Redução de CPU)

  • Implementado um mecanismo de debounce (atraso controlado de 300ms) usando GLib.timeout_add tanto na busca global de faixas quanto no filtro de artistas.
  • A interface agora aguarda o usuário terminar de digitar antes de disparar a filtragem na listagem, evitando renderizações consecutivas desnecessárias e reduzindo drasticamente o uso de CPU.

Desacoplamento do Motor de Áudio (Player)

  • A classe Player foi completamente isolada da lógica da interface gráfica (Gtk.Window).
  • Toda a comunicação interna do barramento do GStreamer (mensagens de TAG, Fim de Faixa/EOS, Erros e Progresso) agora utiliza um padrão baseado em callbacks puros definidos externamente (on_tag_found_cb, on_eos_cb, etc.), facilitando a manutenção e futuros testes automatizados.

Polimento na Interface e Gerenciamento de Estado

  • Sincronização de Seleção: Correção de concorrências visuais (travamentos em loops de eventos) ao alternar entre as visões de Álbum, Artista e Playlists através da sidebar.
  • Proteção contra Falhas: Adicionada maior resiliência com blocos try/except refinados em consultas críticas de tempo/duração no pipeline do GStreamer, prevenindo crashes inesperados no fechamento do app.

Detalhes Técnicos das Alterações

  • openwave/player.py: Remoção de referências diretas à janela principal; encapsulamento estrito do loop de progresso (_tick) e timer.
  • openwave/window.py: Implementação do _scan_worker, adoção de flags de controle como self.is_scanning e timeouts para entradas de texto.
  • openwave/ui_builder.py: Melhorias na consistência visual dos seletores.

Full Changelog: 0.1.4...0.1.5

OpenWave 0.1.4

04 Jun 01:45
299a1ee

Choose a tag to compare

Esta atualização traz um dos recursos mais essenciais para um player de música de desktop: a integração completa com o menu de volume e notificações do sistema!

Focada em oferecer uma experiência fluida no Linux Mint, essa atualização torna o OpenWave um "cidadão de primeira classe" no seu ambiente gráfico, sendo também totalmente compatível com GNOME, KDE Plasma e outros painéis modernos.

Novidades e Melhorias

  • Integração com Applet de Som: O OpenWave agora tem um reprodutor embutido direto no menu de volume/notificações do painel do sistema.
  • Controles Multimídia Nativos: Agora você pode pausar, reproduzir, avançar ou voltar faixas usando os botões do painel do sistema ou as teclas de mídia nativas do seu teclado.
  • Metadados Completos: O sistema agora reconhece e exibe perfeitamente o título da música, o artista e o álbum da faixa em reprodução.
  • Capa do Álbum no Painel: A arte do álbum agora é renderizada e enviada em tempo real para o applet de som, deixando o visual muito mais rico.
  • Sincronia de Progresso: O tempo de reprodução da música agora é sincronizado com o sistema, permitindo que o painel mostre a minutagem correta.

O que mudou por baixo do capô (Technical Details)

  • Novo Suporte a MPRIS2: Adicionado o módulo mpris.py, construído diretamente sobre o dbus padrão do Python. Isso garante comunicação perfeita com o sistema sem inflar o aplicativo com dependências externas complexas.
  • Refatoração no Player: O módulo player.py (GStreamer) recebeu o método get_position_us() para reportar a posição exata do áudio em microssegundos para o barramento D-Bus.
  • Gerenciamento de Capas: O window.py agora extrai os bytes da capa do álbum na memória e os salva de forma segura e temporária (current_cover.jpg) no diretório de configuração do usuário para que a interface gráfica do sistema operacional consiga acessá-la via URL (file://).

Full Changelog: 0.1.3...0.1.4

OpenWave 0.1.3

03 Jun 22:23
147e15d

Choose a tag to compare

Nesta versão, o núcleo do projeto foi completamente reestruturado para melhorar a manutenibilidade, testabilidade e separação de conceitos. O antigo arquivo monolítico app.py foi dividido em um pacote estruturado chamado openwave/, composto por 7 novos módulos especializados.

Nova Estrutura de Arquivos e Responsabilidades

Abaixo está a divisão da arquitetura do aplicativo e o papel de cada novo módulo:

Arquivo / Módulo Responsabilidade
app.py Ponto de entrada: Apenas inicializa o GTK e abre a janela principal.
openwave/constants.py Configurações: Centraliza versão, URLs e extensões de áudio suportadas.
openwave/utils.py Funções puras: normalize_text, read_audio_metadata, ensure_dir, parse_version.
openwave/updater.py Atualizações: Verificação de updates e download/restart em background.
openwave/dialogs.py Componentes visuais: Diálogos reutilizáveis como PlaylistDialog e show_about_dialog.
openwave/player.py Core de Áudio: Classe Player que encapsula o pipeline GStreamer com callbacks desacoplados.
openwave/ui_builder.py Design/Estilo: Gerenciamento de CSS e funções puras de UI (build_header, sidebar_section, add_sidebar_row).
openwave/window.py Orquestrador: Classe OpenWave, agora muito menor, focada apenas em coordenar os módulos.

Benefícios Práticos desta Refatoração

  • Testabilidade Isolada: A classe Player agora pode ser testada separadamente e seu backend pode ser substituído (ex: por outro motor de áudio) sem a necessidade de tocar na janela do app.
  • Execução em Background Isolada da UI: O módulo updater.py pode ser importado e testado de forma independente, sem precisar renderizar a interface GTK.
  • Facilidade em Ajustes Visuais: O CSS e os builders da barra lateral (sidebar) ficaram centralizados em ui_builder.py, tornando as modificações estéticas muito mais fáceis de ajustar visualmente.
  • Manutenção Segura: Adicionar um novo diálogo em dialogs.py ficou mais seguro, eliminando o risco de quebrar a lógica principal de reprodução de áudio.

Full Changelog: 0.1.2...0.1.3

OpenWave 0.1.2

02 Jun 22:51
0b1f1d6

Choose a tag to compare

Atualizações automáticas

  • Verificação em segundo plano ao iniciar o app
  • Comparação de versão com a última Release publicada no GitHub
  • Download e substituição automática do app.py com reinício do processo ao aceitar a atualização

Full Changelog: 0.1.1...0.1.2

OpenWave 0.1.1

31 May 21:08
7fb6b52

Choose a tag to compare

Refactoring realizado sobre app.py (versão 0.1).

Bugs corrigidos

1. Gst.init(None) chamado duas vezes

Arquivo: app.py — bloco if __name__ == "__main__"
O GStreamer era inicializado em _init_gstreamer() e novamente no ponto de entrada. A segunda chamada é um no-op silencioso, mas pode causar avisos em certas versões do GStreamer e indica descuido na ordem de inicialização.
Fix: removida a chamada redundante do bloco __main__.


2. stop_playback deixava o pipeline GStreamer em estado inconsistente

Arquivo: app.py — método stop_playback
O método usava Gst.State.PAUSED para "parar" a reprodução. Isso mantinha o pipeline alocado (decodificadores, buffers, handle de arquivo), consumindo recursos desnecessariamente e causando comportamento imprevisível ao retomar outra faixa.
Fix: trocado para Gst.State.NULL, que libera o pipeline completamente. Adicionados reset visual da barra de progresso e do tempo atual.


3. Timer de progresso acumulava instâncias a cada faixa

Arquivo: app.py — método play_track
O timer criado com GLib.timeout_add(1000, update_progress) nunca era cancelado antes de iniciar uma nova faixa. Após tocar N faixas, N timers rodavam em paralelo, todos chamando update_progress a cada segundo — causando contenção, glitches de UI e uso de CPU crescente.
Fix: adicionado helper _cancel_progress_timer() chamado no início de play_track, em stop_playback e em on_error.


4. on_error não limpava o estado de reprodução

Arquivo: app.py — método on_error
Ao receber um erro do GStreamer, o método atualizava o ícone play/pause mas não cancelava o timer de progresso, não resetava current_track_path e não resetava a barra de progresso. A UI ficava mostrando a última posição conhecida e novos cliques em "próxima" podiam tentar retomar a faixa com erro.
Fix: on_error agora chama _cancel_progress_timer(), zera current_track_path, reseta progresso e tempo para 00:00.


5. empty_label sempre visível após inicialização com biblioteca carregada

Arquivo: app.py — método __init__
A sequência era: _apply_track_view() (que define empty_label.set_visible(False) quando há faixas) → show_all() (que força todos os widgets para visíveis) → empty_label.set_visible(True) (hardcoded). O resultado: o label "Abra uma pasta para ver suas músicas" aparecia sobreposto à lista mesmo com a biblioteca carregada.
Fix: a última linha foi substituída por set_visible(not has_tracks), baseado no estado real da biblioteca.


6. on_artists_tree_selection_changed referenciada mas nunca definida

Arquivo: app.py — método _sidebar_tree_section
O método conectava o sinal changed da seleção de um TreeView ao handler self.on_artists_tree_selection_changed, que não existe em lugar nenhum na classe. Qualquer código que chegasse a instanciar esse widget resultaria em AttributeError em runtime.
Fix: _sidebar_tree_section (e _build_artist_tree_model, que a alimentava) eram código completamente morto — nunca chamados. Ambos foram removidos.


Redundâncias eliminadas

Elemento removido Motivo
pretty_album_name() Sempre retornava o argumento album sem transformação real; inlinado em read_audio_metadata
format_time(ns) Wrapper de 2 linhas sobre format_time_from_seconds; callers atualizados para pos / Gst.SECOND
_set_cover_from_tag_bytes() Wrapper de 2 linhas sobre _load_cover_from_bytes, nunca chamada em lugar nenhum
_build_artist_tree_model() 50 linhas de código morto (nunca chamada)
_sidebar_tree_section() 45 linhas de código morto (nunca chamada)
show_all() em main Redundante; OpenWave.init já chama self.show_all()
Chamada dupla a _refresh_album_browser em _apply_track_view Já era feita por _select_sidebar_row_for_view na mesma sequência de chamadas
4× hasattr(self, "album_selector") Widget sempre existe após _build_ui; guards mascaravam bugs em vez de proteger
Linhas em branco duplicadas em vários métodos Estilo