Compare commits
6 Commits
c6771e6747
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 7164a5a299 | |||
| a60f430334 | |||
| 0a4c1fbe88 | |||
| 6b691a282b | |||
|
|
11f79a9b98 | ||
| fbcda7a401 |
8
.github/workflows/windows.yml
vendored
8
.github/workflows/windows.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- qt_ver: '6.9.3'
|
||||
- qt_ver: '6.10.1'
|
||||
vs: '2022'
|
||||
aqt_arch: 'win64_msvc2022_64'
|
||||
msvc_arch: 'x64'
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
with:
|
||||
arch: ${{ matrix.aqt_arch }}
|
||||
version: ${{ matrix.qt_ver }}
|
||||
modules: 'qtmultimedia qt5compat'
|
||||
modules: 'qtmultimedia'
|
||||
- name: Build
|
||||
shell: cmd
|
||||
run: |
|
||||
@@ -59,11 +59,11 @@ jobs:
|
||||
cmake --build build_dependencies/taglib --config Release --target=install -j || goto :error
|
||||
echo ::endgroup::
|
||||
:: ------ app ------
|
||||
cmake -Bbuild . -DUSE_QTEXTCODEC=ON -DCMAKE_INSTALL_PREFIX='%PWD%\build\' || goto :error
|
||||
cmake -Bbuild . -DUSE_QTEXTCODEC=OFF -DCMAKE_INSTALL_PREFIX='%PWD%\build\' || goto :error
|
||||
cmake --build build --config Release -j || goto :error
|
||||
cmake --build build --config Release --target=install || goto :error
|
||||
:: ------ pkg ------
|
||||
windeployqt --verbose=2 --no-quick-import --no-translations --no-opengl-sw --no-system-d3d-compiler --no-system-dxc-compiler --multimedia --core5compat --skip-plugin-types tls,networkinformation build\bin\pmusic.exe
|
||||
windeployqt --verbose=2 --no-quick-import --no-translations --no-opengl-sw --no-system-d3d-compiler --no-system-dxc-compiler --multimedia --skip-plugin-types tls,networkinformation build\bin\pmusic.exe
|
||||
robocopy ./dependencies_bin/bin build/bin *.dll
|
||||
if ErrorLevel 8 (exit /B 1)
|
||||
copy LICENSE build/bin/
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -6,6 +6,9 @@ build-*/
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
# Clangd cache
|
||||
.cache/
|
||||
|
||||
# User config file
|
||||
CMakeLists.txt.user*
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ set (PMUSIC_CPP_FILES
|
||||
lyricsmanager.cpp
|
||||
fftspectrum.cpp
|
||||
playbackprogressindicator.cpp
|
||||
lyricswidget.cpp
|
||||
)
|
||||
|
||||
set (PMUSIC_HEADER_FILES
|
||||
@@ -59,6 +60,7 @@ set (PMUSIC_HEADER_FILES
|
||||
fftspectrum.h
|
||||
playbackprogressindicator.h
|
||||
taskbarmanager.h
|
||||
lyricswidget.h
|
||||
)
|
||||
|
||||
set (PMUSIC_UI_FILES
|
||||
@@ -113,6 +115,10 @@ if (USE_QTEXTCODEC)
|
||||
target_link_libraries(${EXE_NAME} PRIVATE Qt6::Core5Compat)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${EXE_NAME} PRIVATE
|
||||
PMUSIC_VERSION_STRING="${CMAKE_PROJECT_VERSION}"
|
||||
)
|
||||
|
||||
# Install settings
|
||||
if (WIN32)
|
||||
set_target_properties(${EXE_NAME} PROPERTIES
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<message>
|
||||
<location filename="../lrcbar.cpp" line="88"/>
|
||||
<source>(Interlude...)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>(Zwischenspiel …)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -14,92 +14,92 @@
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="125"/>
|
||||
<source>Mono</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Mono</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="127"/>
|
||||
<source>Stereo</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Stereo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="129"/>
|
||||
<source>%1 Channels</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1 Kanäle</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="298"/>
|
||||
<source>Select songs to play</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Songs zum Spielen auswählen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="300"/>
|
||||
<source>Audio Files</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Audiodateien</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="685"/>
|
||||
<source>Select image as background skin</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Bild als Hintergrundskin auswählen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="687"/>
|
||||
<source>Image files (*.jpg *.jpeg *.png *.gif)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Bilddateien (*.jpg *.jpeg *.png *.gif)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="764"/>
|
||||
<source>Based on the following free software libraries:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Basiert auf den folgenden freien Programmbibliotheken:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="23"/>
|
||||
<location filename="../mainwindow.cpp" line="762"/>
|
||||
<location filename="../lrcbar.cpp" line="89"/>
|
||||
<source>Pineapple Music</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Pineapple Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="327"/>
|
||||
<source>No song loaded...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Kein Song geladen …</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="339"/>
|
||||
<source>Drag and drop file to load</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Datei zum Laden ziehen und ablegen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="352"/>
|
||||
<source>Lrc</source>
|
||||
<comment>Lyrics</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Lrc</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="711"/>
|
||||
<location filename="../mainwindow.ui" line="714"/>
|
||||
<location filename="../mainwindow.cpp" line="759"/>
|
||||
<source>About</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Über</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="728"/>
|
||||
<source>Open</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Öffnen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="135"/>
|
||||
<source>Sample Rate: %1 Hz</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Abtastrate: %1 Hz</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="140"/>
|
||||
<source>Bitrate: %1 Kbps</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Bitrate: %1 kbps</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="145"/>
|
||||
<source>Channel Count: %1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Kanalanzahl: %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -107,12 +107,12 @@
|
||||
<message>
|
||||
<location filename="../playbackprogressindicator.cpp" line="85"/>
|
||||
<source>Time</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Zeit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../playbackprogressindicator.cpp" line="85"/>
|
||||
<source>Chapter Name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Kapitelname</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -120,7 +120,7 @@
|
||||
<message>
|
||||
<location filename="../main.cpp" line="27"/>
|
||||
<source>File list.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Dateiliste.</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
||||
20
lrcbar.cpp
20
lrcbar.cpp
@@ -10,9 +10,9 @@
|
||||
#include <QPainter>
|
||||
#include <QWindow>
|
||||
|
||||
LrcBar::LrcBar(QWidget *parent)
|
||||
LrcBar::LrcBar(QWidget *parent, LyricsManager *mgr)
|
||||
: QWidget(parent, Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Tool)
|
||||
, m_lrcMgr(new LyricsManager(this))
|
||||
, m_lrcMgr(mgr)
|
||||
{
|
||||
m_font.setPointSize(30);
|
||||
m_font.setStyleStrategy(QFont::PreferAntialias);
|
||||
@@ -32,9 +32,14 @@ LrcBar::LrcBar(QWidget *parent)
|
||||
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
setMouseTracking(true);
|
||||
setGeometry(QRect(QPoint((qApp->primaryScreen()->geometry().width() - windowSize.width()) / 2,
|
||||
qApp->primaryScreen()->geometry().height() - windowSize.height() - 50),
|
||||
setGeometry(QRect(QPoint((qApp->primaryScreen()->availableGeometry().width() - windowSize.width()) / 2,
|
||||
qApp->primaryScreen()->availableGeometry().bottom() - windowSize.height() - 5),
|
||||
windowSize));
|
||||
|
||||
connect(m_lrcMgr, &LyricsManager::lyricsLoaded, this, [this](bool){
|
||||
m_currentTimeMs = 0;
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
LrcBar::~LrcBar()
|
||||
@@ -42,18 +47,11 @@ LrcBar::~LrcBar()
|
||||
|
||||
}
|
||||
|
||||
bool LrcBar::loadLyrics(QString filepath)
|
||||
{
|
||||
m_currentTimeMs = 0;
|
||||
return m_lrcMgr->loadLyrics(filepath);
|
||||
}
|
||||
|
||||
void LrcBar::playbackPositionChanged(int timestampMs, int totalTimeMs)
|
||||
{
|
||||
if (!isVisible()) return;
|
||||
|
||||
m_currentTimeMs = timestampMs;
|
||||
m_lrcMgr->updateCurrentTimeMs(timestampMs, totalTimeMs);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
3
lrcbar.h
3
lrcbar.h
@@ -13,10 +13,9 @@ class LrcBar : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LrcBar(QWidget *parent);
|
||||
explicit LrcBar(QWidget *parent, LyricsManager *mgr);
|
||||
~LrcBar();
|
||||
|
||||
bool loadLyrics(QString filepath);
|
||||
void playbackPositionChanged(int timestampMs, int totalTimeMs);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -43,10 +43,14 @@ bool LyricsManager::loadLyrics(QString filepath)
|
||||
if (!filepath.endsWith(".lrc", Qt::CaseInsensitive)) {
|
||||
fileInfo.setFile(fileInfo.dir().filePath(fileInfo.completeBaseName() + ".lrc"));
|
||||
}
|
||||
if (!fileInfo.exists()) return false;
|
||||
if (!fileInfo.exists()) {
|
||||
emit lyricsLoaded(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile file(fileInfo.absoluteFilePath());
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
emit lyricsLoaded(false);
|
||||
return false;
|
||||
}
|
||||
QByteArray fileContent(file.readAll());
|
||||
@@ -126,9 +130,11 @@ bool LyricsManager::loadLyrics(QString filepath)
|
||||
if (!m_lyricsMap.isEmpty()) {
|
||||
m_timestampList = m_lyricsMap.keys();
|
||||
std::sort(m_timestampList.begin(), m_timestampList.end());
|
||||
emit lyricsLoaded(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
emit lyricsLoaded(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -151,6 +157,22 @@ void LyricsManager::updateCurrentTimeMs(int curTimeMs, int totalTimeMs)
|
||||
iter--;
|
||||
}
|
||||
m_currentLyricsTime = *iter;
|
||||
m_currentLineIndex = std::distance(m_timestampList.begin(), iter);
|
||||
}
|
||||
|
||||
const QList<int>& LyricsManager::timestamps() const
|
||||
{
|
||||
return m_timestampList;
|
||||
}
|
||||
|
||||
const QHash<int, QString>& LyricsManager::lyricsMap() const
|
||||
{
|
||||
return m_lyricsMap;
|
||||
}
|
||||
|
||||
int LyricsManager::currentLineIndex() const
|
||||
{
|
||||
return m_currentLineIndex;
|
||||
}
|
||||
|
||||
QString LyricsManager::lyrics(int lineOffset) const
|
||||
@@ -197,6 +219,7 @@ void LyricsManager::reset()
|
||||
{
|
||||
m_currentLyricsTime = 0;
|
||||
m_nextLyricsTime = 0;
|
||||
m_currentLineIndex = -1;
|
||||
m_timeOffset = 0;
|
||||
m_lyricsMap.clear();
|
||||
m_timestampList.clear();
|
||||
|
||||
@@ -25,8 +25,16 @@ public:
|
||||
QString lyrics(int lineOffset = 0) const;
|
||||
double maskPercent(int curTimeMs);
|
||||
|
||||
const QList<int>& timestamps() const;
|
||||
const QHash<int, QString>& lyricsMap() const;
|
||||
int currentLineIndex() const;
|
||||
|
||||
static int parseTimeToMilliseconds(const QString& timeString);
|
||||
|
||||
signals:
|
||||
void lyricsLoaded(bool success);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
@@ -39,5 +47,6 @@ private:
|
||||
QList<int> m_timestampList;
|
||||
int m_currentLyricsTime = 0;
|
||||
int m_nextLyricsTime = 0;
|
||||
int m_currentLineIndex = -1;
|
||||
int m_timeOffset = 0;
|
||||
};
|
||||
|
||||
131
lyricswidget.cpp
Normal file
131
lyricswidget.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
// SPDX-FileCopyrightText: 2026 Gary Wang <opensource@blumia.net>
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "lyricswidget.h"
|
||||
#include "lyricsmanager.h"
|
||||
|
||||
#include <QListWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QListWidgetItem>
|
||||
#include <QListWidgetItem>
|
||||
#include <QFont>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QScrollBar>
|
||||
#include <QEasingCurve>
|
||||
|
||||
LyricsWidget::LyricsWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_listWidget(new QListWidget(this))
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(m_listWidget);
|
||||
|
||||
m_listWidget->setFrameShape(QFrame::NoFrame);
|
||||
m_listWidget->setStyleSheet("background: transparent;");
|
||||
m_listWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
m_listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_listWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Hide scrollbar for cleaner look? Or Keep it? User didn't specify. Hiding it looks more like "Lyrics Mode"
|
||||
// Enable word wrap
|
||||
m_listWidget->setWordWrap(true);
|
||||
m_listWidget->setTextElideMode(Qt::ElideNone);
|
||||
m_listWidget->setSelectionMode(QAbstractItemView::NoSelection);
|
||||
m_listWidget->setFocusPolicy(Qt::NoFocus);
|
||||
}
|
||||
|
||||
void LyricsWidget::setLyricsManager(LyricsManager *mgr)
|
||||
{
|
||||
if (m_lyricsManager) {
|
||||
disconnect(m_lyricsManager, nullptr, this, nullptr);
|
||||
}
|
||||
m_lyricsManager = mgr;
|
||||
if (m_lyricsManager) {
|
||||
connect(m_lyricsManager, &LyricsManager::lyricsLoaded, this, &LyricsWidget::onLyricsLoaded);
|
||||
// Load initial state if any
|
||||
onLyricsLoaded(m_lyricsManager->hasLyrics());
|
||||
}
|
||||
}
|
||||
|
||||
void LyricsWidget::updatePosition(qint64 position)
|
||||
{
|
||||
if (!m_lyricsManager || !m_lyricsManager->hasLyrics() || !isVisible()) return;
|
||||
|
||||
// Note: rely on LyricsManager::updateCurrentTimeMs()
|
||||
int index = m_lyricsManager->currentLineIndex();
|
||||
|
||||
if (index != m_lastHighlightIndex) {
|
||||
highlightCurrentLine(index);
|
||||
}
|
||||
}
|
||||
|
||||
void LyricsWidget::onLyricsLoaded(bool success)
|
||||
{
|
||||
m_listWidget->clear();
|
||||
m_lastHighlightIndex = -1;
|
||||
|
||||
if (!success || !m_lyricsManager) return;
|
||||
|
||||
const QList<int>& timestamps = m_lyricsManager->timestamps();
|
||||
const QHash<int, QString>& lyricsMap = m_lyricsManager->lyricsMap();
|
||||
|
||||
for (int timestamp : timestamps) {
|
||||
QListWidgetItem *item = new QListWidgetItem(lyricsMap.value(timestamp));
|
||||
item->setTextAlignment(Qt::AlignCenter);
|
||||
|
||||
// Default style
|
||||
QFont font = item->font();
|
||||
font.setPointSize(10);
|
||||
item->setFont(font);
|
||||
item->setForeground(QColor(255, 255, 255, 150)); // Dimmed
|
||||
|
||||
m_listWidget->addItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
void LyricsWidget::highlightCurrentLine(int index)
|
||||
{
|
||||
if (index < 0 || index >= m_listWidget->count()) return;
|
||||
|
||||
// Reset old highlight
|
||||
if (m_lastHighlightIndex >= 0 && m_lastHighlightIndex < m_listWidget->count()) {
|
||||
QListWidgetItem *oldItem = m_listWidget->item(m_lastHighlightIndex);
|
||||
QFont font = oldItem->font();
|
||||
font.setPointSize(10);
|
||||
font.setBold(false);
|
||||
oldItem->setFont(font);
|
||||
oldItem->setForeground(QColor(255, 255, 255, 150));
|
||||
}
|
||||
|
||||
// Set new highlight
|
||||
QListWidgetItem *newItem = m_listWidget->item(index);
|
||||
QFont font = newItem->font();
|
||||
font.setPointSize(14);
|
||||
font.setBold(true);
|
||||
newItem->setFont(font);
|
||||
newItem->setForeground(QColor(255, 255, 255, 255));
|
||||
|
||||
// Smooth scroll
|
||||
QScrollBar *vBar = m_listWidget->verticalScrollBar();
|
||||
int startScroll = vBar->value();
|
||||
|
||||
m_listWidget->scrollToItem(newItem, QAbstractItemView::PositionAtCenter);
|
||||
int endScroll = vBar->value();
|
||||
|
||||
// Restore and animate
|
||||
if (startScroll != endScroll) {
|
||||
vBar->setValue(startScroll);
|
||||
|
||||
if (!m_scrollAnimation) {
|
||||
m_scrollAnimation = new QPropertyAnimation(vBar, "value", this);
|
||||
m_scrollAnimation->setDuration(400);
|
||||
m_scrollAnimation->setEasingCurve(QEasingCurve::OutCubic);
|
||||
}
|
||||
m_scrollAnimation->stop();
|
||||
m_scrollAnimation->setStartValue(startScroll);
|
||||
m_scrollAnimation->setEndValue(endScroll);
|
||||
m_scrollAnimation->start();
|
||||
}
|
||||
|
||||
m_lastHighlightIndex = index;
|
||||
}
|
||||
37
lyricswidget.h
Normal file
37
lyricswidget.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// SPDX-FileCopyrightText: 2026 Gary Wang <opensource@blumia.net>
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QListWidget;
|
||||
class QListWidgetItem;
|
||||
class QPropertyAnimation;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class LyricsManager;
|
||||
class LyricsWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LyricsWidget(QWidget *parent = nullptr);
|
||||
|
||||
void setLyricsManager(LyricsManager *mgr);
|
||||
void updatePosition(qint64 position);
|
||||
|
||||
private slots:
|
||||
void onLyricsLoaded(bool success);
|
||||
|
||||
private:
|
||||
QListWidget *m_listWidget;
|
||||
LyricsManager *m_lyricsManager = nullptr;
|
||||
int m_lastHighlightIndex = -1;
|
||||
QPropertyAnimation *m_scrollAnimation = nullptr;
|
||||
|
||||
void updateLyrics();
|
||||
void highlightCurrentLine(int index);
|
||||
};
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "fftspectrum.h"
|
||||
#include "lrcbar.h"
|
||||
#include "taskbarmanager.h"
|
||||
#include "lyricsmanager.h"
|
||||
#include "lyricswidget.h"
|
||||
|
||||
// taglib
|
||||
#ifndef NO_TAGLIB
|
||||
@@ -48,11 +50,16 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
, m_mediaPlayer(new QMediaPlayer(this))
|
||||
, m_audioOutput(new QAudioOutput(this))
|
||||
, m_fftSpectrum(new FFTSpectrum(this))
|
||||
, m_lrcbar(new LrcBar(nullptr))
|
||||
, m_lyricsManager(new LyricsManager(this))
|
||||
, m_lrcbar(new LrcBar(nullptr, m_lyricsManager))
|
||||
, m_lyricsWidget(new LyricsWidget(this))
|
||||
, m_playlistManager(new PlaylistManager(this))
|
||||
, m_taskbarManager(new TaskBarManager(this))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
m_lyricsWidget->setLyricsManager(m_lyricsManager);
|
||||
ui->pluginStackedWidget->addWidget(m_lyricsWidget);
|
||||
|
||||
m_playlistManager->setAutoLoadFilterSuffixes({
|
||||
"*.mp3", "*.wav", "*.aiff", "*.ape", "*.flac", "*.ogg", "*.oga", "*.mpga", "*.aac", "*.tta"
|
||||
});
|
||||
@@ -255,7 +262,7 @@ void MainWindow::dropEvent(QDropEvent *e)
|
||||
}
|
||||
|
||||
if (fileName.endsWith(".lrc")) {
|
||||
m_lrcbar->loadLyrics(fileName);
|
||||
m_lyricsManager->loadLyrics(fileName);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -313,7 +320,7 @@ void MainWindow::loadFile(const QUrl &url)
|
||||
{
|
||||
const QString filePath = url.toLocalFile();
|
||||
m_mediaPlayer->setSource(url);
|
||||
m_lrcbar->loadLyrics(filePath);
|
||||
m_lyricsManager->loadLyrics(filePath);
|
||||
QList<std::pair<qint64, QString>> chapters(PlaybackProgressIndicator::tryLoadChapters(filePath));
|
||||
ui->playbackProgressIndicator->setChapters(chapters);
|
||||
}
|
||||
@@ -519,7 +526,12 @@ void MainWindow::initConnections()
|
||||
ui->playbackProgressIndicator->setPosition(pos);
|
||||
m_taskbarManager->setProgressValue(pos);
|
||||
}
|
||||
|
||||
if (m_lrcbar->isVisible() || m_lyricsWidget->isVisible()) {
|
||||
m_lyricsManager->updateCurrentTimeMs(pos, m_mediaPlayer->duration());
|
||||
m_lrcbar->playbackPositionChanged(pos, m_mediaPlayer->duration());
|
||||
m_lyricsWidget->updatePosition(pos);
|
||||
}
|
||||
|
||||
static QString lastChapterName;
|
||||
if (ui->playbackProgressIndicator->chapterModel()->rowCount() > 0) {
|
||||
@@ -718,6 +730,15 @@ void MainWindow::on_playlistView_activated(const QModelIndex &index)
|
||||
|
||||
void MainWindow::on_lrcBtn_clicked()
|
||||
{
|
||||
if (size().height() < 200) {
|
||||
setFixedSize(fullSize);
|
||||
}
|
||||
|
||||
if (ui->pluginStackedWidget->currentWidget() != m_lyricsWidget) {
|
||||
ui->pluginStackedWidget->setCurrentWidget(m_lyricsWidget);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_lrcbar->isVisible()) {
|
||||
m_lrcbar->hide();
|
||||
} else {
|
||||
@@ -764,7 +785,7 @@ void MainWindow::on_actionHelp_triggered()
|
||||
infoBox.setWindowTitle(tr("About"));
|
||||
infoBox.setStandardButtons(QMessageBox::Ok);
|
||||
infoBox.setText(
|
||||
tr("Pineapple Music") %
|
||||
QString("%1 %2").arg(tr("Pineapple Music")).arg(PMUSIC_VERSION_STRING) %
|
||||
"\n\n" %
|
||||
tr("Based on the following free software libraries:") %
|
||||
"\n\n" %
|
||||
@@ -785,7 +806,7 @@ void MainWindow::on_actionHelp_triggered()
|
||||
"\n"
|
||||
"[Source Code](https://github.com/BLumia/pineapple-music)\n"
|
||||
"\n"
|
||||
"Copyright © 2025 [BLumia](https://github.com/BLumia/)"
|
||||
"Copyright © 2026 [BLumia](https://github.com/BLumia/)"
|
||||
);
|
||||
infoBox.setTextFormat(Qt::MarkdownText);
|
||||
infoBox.exec();
|
||||
|
||||
@@ -21,6 +21,8 @@ QT_END_NAMESPACE
|
||||
|
||||
class FFTSpectrum;
|
||||
class LrcBar;
|
||||
class LyricsManager;
|
||||
class LyricsWidget;
|
||||
class PlaylistManager;
|
||||
class TaskBarManager;
|
||||
class MainWindow : public QMainWindow
|
||||
@@ -104,7 +106,9 @@ private:
|
||||
QMediaPlayer *m_mediaPlayer;
|
||||
QAudioOutput *m_audioOutput;
|
||||
FFTSpectrum* m_fftSpectrum;
|
||||
LyricsManager *m_lyricsManager;
|
||||
LrcBar *m_lrcbar;
|
||||
LyricsWidget *m_lyricsWidget;
|
||||
QPropertyAnimation *m_fadeOutAnimation;
|
||||
PlaylistManager *m_playlistManager;
|
||||
TaskBarManager *m_taskbarManager;
|
||||
|
||||
Reference in New Issue
Block a user