fist comin

This commit is contained in:
Dark Steveneq
2025-10-18 21:40:02 +02:00
parent 63d9c21e98
commit 6fc0736c2d
12 changed files with 402 additions and 358 deletions

View File

@@ -1,49 +1,42 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake) project(qyouvideo VERSION 0.1 LANGUAGES CXX)
project(qyouradio VERSION 0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt6 REQUIRED COMPONENTS Core Quick Multimedia) find_package(Qt6 REQUIRED COMPONENTS Core Quick Multimedia)
find_package(DiscordSDK)
qt_standard_project_setup(REQUIRES 6.8) qt_standard_project_setup(REQUIRES 6.8)
configure_file(buildFlags.h.in buildFlags.h) qt_add_executable(appqyouvideo
qt_add_executable(appqyouradio
main.cpp main.cpp
buildFlags.h
player.cpp player.h player.cpp player.h
resources/qyouradio.rc resources/qyouvideo.rc
resources/resource.h resources/resource.h
) )
qt_add_resources(appqyouradio "resources" qt_add_resources(appqyouvideo "resources"
PREFIX "/" PREFIX "/"
FILES FILES
resources/logo.png resources/logo.png
) )
set_source_files_properties(Player.qml
PROPERTIES QT_QML_SINGLETON_TYPE TRUE)
qt_add_qml_module(appqyouradio qt_add_qml_module(appqyouvideo
URI qyouradio URI qyouvideo
VERSION 1.0 VERSION 1.0
QML_FILES QML_FILES
Main.qml Main.qml
# Player.qml VideoEntry.qml
ViewPlayer.qml ViewAbout.qml
ViewSettings.qml ViewVideoList.qml
VideoPlayer.qml
) )
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. # Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an # If you are developing for iOS or macOS you should consider setting an
# explicit, fixed bundle identifier manually though. # explicit, fixed bundle identifier manually though.
set_target_properties(appqyouradio PROPERTIES set_target_properties(appqyouvideo PROPERTIES
# MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appqyouradio # MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appqyouradio
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
@@ -51,30 +44,25 @@ set_target_properties(appqyouradio PROPERTIES
WIN32_EXECUTABLE TRUE WIN32_EXECUTABLE TRUE
) )
target_include_directories(appqyouradio PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") target_link_libraries(appqyouvideo
target_link_libraries(appqyouradio
PUBLIC Qt6::Quick Qt6::Multimedia PUBLIC Qt6::Quick Qt6::Multimedia
) )
if (DiscordSDK_FOUND)
target_link_libraries(appqyouradio
PRIVATE DiscordSDK::DiscordSDK
)
endif()
include(GNUInstallDirs) include(GNUInstallDirs)
install(TARGETS appqyouradio install(TARGETS appqyouvideo
BUNDLE DESTINATION . BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
) )
qt_generate_deploy_app_script( qt_generate_deploy_app_script(
TARGET appqyouradio TARGET appqyouvideo
OUTPUT_SCRIPT deploy_script OUTPUT_SCRIPT deploy_script
NO_UNSUPPORTED_PLATFORM_ERROR NO_UNSUPPORTED_PLATFORM_ERROR
) )
install(SCRIPT ${deploy_script}) install(SCRIPT ${deploy_script})
add_subdirectory(QYRComponents) add_subdirectory(QYRComponents)
project(qyouvideo VERSION 0.1 LANGUAGES CXX)

134
Main.qml
View File

@@ -9,11 +9,7 @@ ApplicationWindow {
id: root id: root
width: 1280 width: 1280
height: 800 height: 800
title: qsTr("QYouRadio") title: qsTr("QYouVideo")
Component.onCompleted: function() {
console.log(Player.stations)
}
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
@@ -30,76 +26,8 @@ ApplicationWindow {
Label { Label {
Layout.leftMargin: 5 Layout.leftMargin: 5
text: "QYouRadio" text: "QYouVideo"
heading: "h1" heading: "h1"
// font.bold: true
}
Item {
Layout.leftMargin: 5
width: 320
height: 36
Rectangle {
anchors.fill: parent
id: nowplaying_root
// visible: Player.currentIndex != null
visible: anchors.bottomMargin < 42
color: Colors.primary
radius: 5
clip: true
NumberAnimation {
running: Player.playing && tabbar.currentIndex != Player.currentIndex && nowplaying_root.anchors.bottomMargin >= 42
target: nowplaying_root
property: "anchors.bottomMargin"
from: 42
to: 0
duration: 145
}
NumberAnimation {
running: !Player.playing || (tabbar.currentIndex == Player.currentIndex && nowplaying_root.anchors.bottomMargin < 42)
target: nowplaying_root
property: "anchors.bottomMargin"
from: 0
to: 42
duration: 145
}
Label {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 1
anchors.leftMargin: 4
anchors.rightMargin: 4
text: (Player.loading ? "Loading " : "Playing ") + qsTr(Player.currentStation.name)
heading: "h5"
}
Label {
id: nowplaying_title
anchors.bottom: parent.bottom
anchors.left: parent.left
// anchors.right: parent.right
anchors.bottomMargin: 1
anchors.leftMargin: 4
// anchors.rightMargin: 4
text: qsTr(Player.currentStation.songTitle)
heading: "h3"
SequentialAnimation {
running: nowplaying_title.width > 320
loops: Animation.Infinite
NumberAnimation { target: nowplaying_title; property: "anchors.leftMargin"; from: 4; to: 4; duration: 10000 }
NumberAnimation { target: nowplaying_title; property: "anchors.leftMargin"; from: 4; to: -nowplaying_title.width + 324; duration: nowplaying_title.width * 4 }
NumberAnimation { target: nowplaying_title; property: "anchors.leftMargin"; from: -nowplaying_title.width + 324; to: -nowplaying_title.width + 324; duration: 10000 }
NumberAnimation { target: nowplaying_title; property: "anchors.leftMargin"; from: -nowplaying_title.width + 324; to: 4; duration: nowplaying_title.width * 4 }
}
}
}
} }
Item { Item {
@@ -113,16 +41,17 @@ ApplicationWindow {
background: Item{} background: Item{}
TabButton { TabButton {
text: qsTr("Autoradio") text: qsTr("Videos")
outlined: true
implicitWidth: 80
} }
TabButton { TabButton {
text: qsTr("Live Mix") text: qsTr("About")
outlined: true
implicitWidth: 80
} }
TabButton { TabButton {
text: qsTr("Deep Bass") text: qsTr("Upload")
}
TabButton {
text: qsTr("Settings")
} }
} }
} }
@@ -141,61 +70,28 @@ ApplicationWindow {
active: true active: true
asynchronous: true asynchronous: true
visible: status == Loader.Ready visible: status == Loader.Ready
sourceComponent: ViewPlayer { source: "ViewVideoList.qml"
index: 0
}
} }
Loader { Loader {
// active: tabbar.currentIndex == 1 // active: tabbar.currentIndex == 1
active: true active: true
asynchronous: true asynchronous: true
visible: status == Loader.Ready visible: status == Loader.Ready
sourceComponent: ViewPlayer { source: "ViewAbout.qml"
index: 1
}
} }
Loader { Loader {
// active: tabbar.currentIndex == 2 // active: tabbar.currentIndex == 2
active: true active: true
asynchronous: true asynchronous: true
visible: status == Loader.Ready visible: status == Loader.Ready
sourceComponent: ViewPlayer { sourceComponent: Label {
index: 2 heading: "h1"
text: "No idea if I'll ever implement this so don't worry >w<"
font.bold: true
} }
} }
Component.onCompleted: contentItem.highlightMoveDuration = 160; Component.onCompleted: contentItem.highlightMoveDuration = 160;
} }
RowLayout {
Layout.fillWidth: false
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: 30
Layout.bottomMargin: 30
width: 220
Button {
Layout.rightMargin: 5
text: Player.loading ? "Loading" : (Player.playing ? "Pause" : "Play")
onClicked: function() {
if (Player.playing) {
Player.stopPlaying();
} else {
Player.startPlaying(tabbar.currentIndex);
}
}
}
Slider {
Layout.fillWidth: true
Layout.leftMargin: 5
from: 0.1
to: 1.1
stepSize: 0.05
value: Player.volume + 0.1
onMoved: Player.volume = value - 0.1
}
}
} }
} }

80
VideoEntry.qml Normal file
View File

@@ -0,0 +1,80 @@
import QtQuick 6.8
import QtQuick.Controls 6.8
import QtQuick.Layouts 6.8
import QYRComponents 1.0
Rectangle {
anchors.margins: 10
width: 384
height: 224
color: area.containsMouse ? Colors.surface1 : Colors.surface0
radius: 10
required property string name
required property string id
required property var metadata
ColumnLayout {
anchors.fill: parent
anchors.margins: 5
Image {
Layout.fillWidth: true
Layout.fillHeight: true
asynchronous: true
cache: true
source: "https://youvideo.nonamesoft.xyz/thumbnails/" + parent.parent.id
fillMode: Image.PreserveAspectFit
onStatusChanged: if (status == Image.Error) {
source = "https://youvideo.nonamesoft.xyz/thumbnails/audio.png";
children[0].visible = true
}
// This is a fucking mess
Label {
visible: false
anchors.fill: parent
heading: "h3"
font.bold: true
text: parent.parent.parent.name
wrapMode: Text.Wrap
clip: true
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
Rectangle {
anchors.bottom: parent.bottom
anchors.left: parent.left
color: Colors.background
width: children[0].paintedWidth
height: children[0].paintedHeight
Label {
anchors.fill: parent
heading: "h4"
// text: new Date(parent.parent.parent.parent.metadata.duration * 1000).toISOString().slice(11, 19)
}
}
}
Label {
heading: "h3"
font.bold: true
text: parent.parent.name
Layout.fillWidth: true
clip: true
}
}
MouseArea {
anchors.fill: parent
id: area
hoverEnabled: true
onClicked: Player.loadVideo(parent.id)
}
}

49
VideoPlayer.qml Normal file
View File

@@ -0,0 +1,49 @@
import QtQuick 6.8
import QtMultimedia 6.8
import QtQuick.Controls 6.8
import QtQuick.Layouts 6.8
import QYRComponents 1.0
Rectangle {
visible: Player.hasVideo
color: Colors.surface1
width: childrenRect.width
height: childrenRect.height
ColumnLayout {
anchors.fill: parent
RowLayout {
Button {
text: Player.playing ? "Pause" : "Play"
onClicked: function() {
if (Player.playing) {
Player.pause()
} else {
Player.play();
}
}
}
Button {
text: "Stop"
onClicked: Player.stop()
}
Slider {
Layout.fillWidth: true
from: 0
to: 106
}
Slider {
from: 0
to: 1
value: Player.volume
onMoved: Player.volume = value
}
}
}
}

59
ViewAbout.qml Normal file
View File

@@ -0,0 +1,59 @@
import QtQuick 6.8
import QtQuick.Controls 6.8
import QtQuick.Layouts 6.8
import QYRComponents 1.0
ColumnLayout {
Label {
heading: "h2"
text: "About"
font.bold: true
}
Label {
heading: "h3"
text: "Youpiter"
font.bold: true
}
Label {
heading: "h4"
text: "Creator of YouVideo"
font.bold: true
}
Label {
heading: "h3"
text: "Ghostfox"
}
Label {
heading: "h4"
text: "Creator of QYouRadio"
}
Label {
heading: "h3"
text: "Ghostfox"
}
Label {
heading: "h4"
text: "Creator of QYouVideo"
}
Label {
heading: "h3"
text: "Qt Group"
}
Label {
heading: "h4"
text: "Creator of Qt, QML and QtQuick"
}
Item {
Layout.fillHeight: true
}
}

85
ViewVideoList.qml Normal file
View File

@@ -0,0 +1,85 @@
import QtQuick 6.8
import QtQuick.Controls 6.8
import QtQuick.Layouts 6.8
import QYRComponents 1.0
Item {
anchors.fill: parent
property bool loading: true
property bool failed: false
VideoPlayer {}
GridView {
anchors.horizontalCenter: parent.horizontalCenter
visible: !loading || !failed
anchors.fill: parent
model: ListModel { id: model }
clip: true
cellWidth: 384
cellHeight: 224
delegate: VideoEntry {}
Component.onCompleted: parent.fetchData()
}
BusyIndicator {
anchors.centerIn: parent
visible: loading
running: loading
}
ColumnLayout {
Layout.alignment: Qt.AlignVCenter
anchors.centerIn: parent
visible: failed
Label {
text: "Couldn't get videos!"
heading: "h2"
font.bold: true
}
Label {
text: "This could mean that either your internet or YouVideo is down."
heading: "h4"
}
Label {
Layout.bottomMargin: 25
text: "Check your network connection and try again!"
heading: "h4"
}
Button {
text: "Retry"
onClicked: parent.fetchData()
}
}
function fetchData() {
model.clear();
loading = true;
failed = false;
const xhr = new XMLHttpRequest;
xhr.open("GET", "http://youvideo.nonamesoft.xyz/youvideo/api/videos");
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
loading = false;
if (xhr.status != 200) {
failed = true;
return;
}
const data = JSON.parse(xhr.responseText);
data.forEach(video => {
model.append(video);
});
}
}
xhr.send();
}
}

View File

@@ -14,7 +14,7 @@
, wrapQtAppsHook , wrapQtAppsHook
}: }:
stdenv.mkDerivation { stdenv.mkDerivation {
pname = "qyouradio"; pname = "qyouvideo";
version = "1.0"; version = "1.0";
src = ./.; src = ./.;

6
flake.lock generated
View File

@@ -20,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1760315168, "lastModified": 1760807995,
"narHash": "sha256-qWDhFoiz6VSd+S+rVzC2m5u8xuAzxRsuDI8OojbPEZ4=", "narHash": "sha256-Xpg9h3/uNVMJXZq2LzBDaDM1u057ox0wnZGvxSogNY0=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "160e3dfce302bb2fcd03761b84248c7534f3b948", "rev": "a2975bcaf36af01a1279b84ab575fbc12d472b6a",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -1,9 +1,6 @@
#include <QIcon> #include <QIcon>
#include <QGuiApplication> #include <QGuiApplication>
#include <QQmlApplicationEngine> #include <QQmlApplicationEngine>
#include <QDebug>
#include "buildFlags.h"
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@@ -13,15 +10,9 @@ int main(int argc, char *argv[])
QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
&app, []() { QCoreApplication::exit(-1); }, &app, []() { QCoreApplication::exit(-1); },
Qt::QueuedConnection); Qt::QueuedConnection);
engine.loadFromModule("qyouradio", "Main"); engine.loadFromModule("qyouvideo", "Main");
app.setWindowIcon(QIcon(":/resources/logo.png")); app.setWindowIcon(QIcon(":/resources/logo.png"));
#if DiscordSDK_FOUND
qInfo("Has Discord Social SDK: true");
#else
qInfo("Has Discord Social SDK: false");
#endif
return app.exec(); return app.exec();
} }

View File

@@ -2,32 +2,21 @@
// Public // Public
Player::Player(QObject *parent) : QObject(parent), Player::Player(QObject *parent) : QObject(parent),
player(this), output(this), timer(this), m_currentIndex(0), m_stations({ player(this), output(this), manager(this)
Station{"Autoradio", "autoradio", "", 0},
Station{"Live Mix", "live", "", 0},
Station{"Bass Boosted", "bassboosted", "", 0}
})
{ {
QObject::connect(&this->player, &QMediaPlayer::mediaStatusChanged, this, [this] () {
emit this->hasVideoChanged();
emit this->loadingChanged();
});
QObject::connect(&this->player, &QMediaPlayer::playbackStateChanged, this, [this] () { QObject::connect(&this->player, &QMediaPlayer::playbackStateChanged, this, [this] () {
qDebug("Player::Player()->Lambda: Playing got changed!");
emit this->playingChanged(); emit this->playingChanged();
}); });
QObject::connect(&this->output, &QAudioOutput::volumeChanged, this, [this] () { QObject::connect(&this->output, &QAudioOutput::volumeChanged, this, [this] () {
qDebug("Player::Player()->Lambda: Volume got changed!");
emit this->volumeChanged(); emit this->volumeChanged();
}); });
this->timer.start(metadataFetchTimeout);
QObject::connect(&this->timer, &QTimer::timeout, this, [this] () {
qDebug("Player::Player()->Lambda: Timer triggered!");
if (this->m_currentIndex > -1)
{
emit this->currentStationChanged();
}
emit this->stationsChanged();
});
this->output.setVolume(0.2); this->output.setVolume(0.2);
this->player.setAudioOutput(&this->output); this->player.setAudioOutput(&this->output);
@@ -39,12 +28,26 @@ Player::~Player()
qDebug("Player::~Player(): Destructed"); qDebug("Player::~Player(): Destructed");
} }
bool Player::hasVideo() const
{
return this->player.isAvailable();
}
bool Player::loading() const
{
return this->player.mediaStatus() == QMediaPlayer::LoadingMedia || this->player.mediaStatus() == QMediaPlayer::BufferingMedia;
}
bool Player::failed() const
{
return this->m_failed;
}
bool Player::playing() const bool Player::playing() const
{ {
return this->player.playbackState() == QMediaPlayer::PlayingState; return this->player.playbackState() == QMediaPlayer::PlayingState;
} }
float Player::volume() const float Player::volume() const
{ {
return this->output.volume(); return this->output.volume();
@@ -55,59 +58,67 @@ void Player::setVolume(float newVolume)
this->output.setVolume(newVolume); this->output.setVolume(newVolume);
} }
const QList<Station> Player::stations() const
{
return this->m_stations;
}
const int Player::currentIndex() const
{
return this->m_currentIndex;
}
const Station* Player::currentStation() const
{
if (this->m_currentIndex < 0 || this->m_currentIndex >= this->m_stations.length())
{
qWarning("Player::currentStation(): Tried accessing out of bounds.");
return nullptr;
}
return &this->m_stations[this->m_currentIndex];
}
// Public slots // Public slots
void Player::startPlaying(u_int8_t index) void Player::loadVideo(QString id)
{ {
if (index < 0 || index >= this->m_stations.length()) if (this->hasVideo())
{ {
qWarning("Player::startPlaying(): Tried accessing out of bounds."); this->unloadVideo();
}
const QNetworkReply* reply = this->manager.get(QNetworkRequest(QUrl("https://youvideo.nonamesoft.xyz/youvideo/video/" + id)));
if (reply->error() != QNetworkReply::NoError)
{
qDebug() << "Player::loadVideo(): Video " << id << " doesn't exist!\n";
delete reply;
return; return;
} }
if (this->playing()) {
this->stopPlaying();
}
this->m_currentIndex = index;
emit this->currentIndexChanged();
emit this->currentStationChanged();
this->player.setSource(QUrl("https://youradio.nonamesoft.xyz/youradio/api/" + this->m_stations[index].m_slug)); qDebug() << "Player::fetchMetadata(): Yippie! Got video " << id << "\n";
this->player.play();
qDebug("Player::startPlaying(): Starting playing"); this->player.setSource(QUrl("https://youvideo.nonamesoft.xyz/youvideo/api/" + id));
// Signals will be sent by shit sent from player
this->m_failed = false;
emit this->failedChanged();
delete reply;
} }
void Player::stopPlaying() void Player::unloadVideo() {
this->player.setSource(QUrl(""));
this->player.stop();
this->m_failed = false;
emit this->hasVideoChanged();
emit this->failedChanged();
emit this->loadingChanged();
emit this->playingChanged();
}
void Player::play()
{ {
if (!this->playing()) if (!this->hasVideo() || !this->loading())
{
return;
}
this->player.play();
}
void Player::pause()
{
if (!this->hasVideo() || !this->loading())
{
return;
}
this->player.pause();
}
void Player::stop()
{
if (!this->hasVideo() || !this->loading())
{ {
qWarning("Player::stopPlaying(): Prevented redundant stopPlaying() call.");
return; return;
} }
this->player.stop(); this->player.stop();
this->player.setSource(QUrl("")); this->unloadVideo();
this->m_currentIndex = -1;
emit this->currentIndexChanged();
emit this->currentStationChanged();
qDebug("Player::stopPlaying(): Stopping playback...");
} }

View File

@@ -1,73 +1,54 @@
#pragma once #pragma once
#include <QtMultimedia> #include <QtMultimedia>
#include <QtConcurrent/QtConcurrent>
#include <QDebug> #include <QDebug>
#include <QObject> #include <QObject>
#include <QList> #include <QNetworkAccessManager>
#include <QTimer>
#include <QtQmlIntegration/qqmlintegration.h> #include <QtQmlIntegration/qqmlintegration.h>
constexpr int metadataFetchTimeout = 10000;
constexpr std::string_view metadataEndpoint = "https://youradio.nonamesoft.xyz/youradio/api/status-json.xsl";
struct Station
{
Q_GADGET
Q_PROPERTY(QString name MEMBER m_name);
Q_PROPERTY(QString slug MEMBER m_slug);
Q_PROPERTY(QString songTitle MEMBER m_songTitle);
Q_PROPERTY(int listeners MEMBER m_listeners);
public:
QString m_name;
QString m_slug;
QString m_songTitle;
int m_listeners;
};
class Player : public QObject class Player : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_SINGLETON QML_SINGLETON
QML_ELEMENT QML_ELEMENT
Q_PROPERTY(bool playing READ playing NOTIFY playingChanged FINAL) Q_PROPERTY(bool hasVideo READ hasVideo NOTIFY hasVideoChanged FINAL)
Q_PROPERTY(float volume READ volume WRITE setVolume NOTIFY volumeChanged FINAL) Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged FINAL)
Q_PROPERTY(const QList<Station> stations READ stations NOTIFY stationsChanged FINAL) Q_PROPERTY(bool failed READ failed NOTIFY failedChanged FINAL)
Q_PROPERTY(int currentIndex READ currentIndex NOTIFY currentIndexChanged FINAL) Q_PROPERTY(bool playing READ playing NOTIFY playingChanged FINAL)
Q_PROPERTY(const Station* currentStation READ currentStation NOTIFY currentStationChanged FINAL) Q_PROPERTY(float volume READ volume WRITE setVolume NOTIFY volumeChanged FINAL)
public: public:
Player(QObject *parent = nullptr); Player(QObject *parent = nullptr);
~Player(); ~Player();
bool playing() const; bool hasVideo() const;
bool loading() const;
bool failed() const;
bool playing() const;
float volume() const;
float volume() const;
void setVolume(float newVolume); void setVolume(float newVolume);
const QList<Station> stations() const;
const int currentIndex() const;
const Station* currentStation() const;
public slots: public slots:
void startPlaying(u_int8_t index); void loadVideo(QString id);
void stopPlaying(); void unloadVideo();
void play();
void pause();
void stop();
signals: signals:
void hasVideoChanged();
void loadingChanged();
void failedChanged();
void playingChanged(); void playingChanged();
void volumeChanged(); void volumeChanged();
void stationsChanged();
void currentIndexChanged();
void currentStationChanged();
private: private:
QMediaPlayer player; QMediaPlayer player;
QAudioOutput output; QAudioOutput output;
QTimer timer; QNetworkAccessManager manager;
int m_currentIndex; bool m_failed = false;
QList<Station> m_stations;
}; };

View File

@@ -1,96 +0,0 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
//LANGUAGE 0x09, 0x01
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
1 VERSIONINFO
FILEVERSION 1, 0, 0, 1
PRODUCTVERSION 1, 0, 0, 1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x29L
#else
FILEFLAGS 0x28L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "LAMINAX CO."
VALUE "FileDescription", "QYouRadio"
VALUE "FileVersion", "1.0.0.1"
VALUE "InternalName", "qyouradio"
VALUE "LegalCopyright", "Copyright (C) Ghostfox 2025"
//VALUE "OriginalFilename", "appqyouradio.exe"
VALUE "ProductName", "QYouRadio"
VALUE "ProductVersion", "1.0.0.1"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x09, 1200
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON "logo.ico"
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED