heugh jazz

This commit is contained in:
Dark Steveneq
2025-10-19 02:58:12 +02:00
parent 5c9b0ec49a
commit 902693bd40
9 changed files with 358 additions and 55 deletions

1
.gitignore vendored
View File

@@ -32,6 +32,7 @@ qrc_*.cpp
Thumbs.db Thumbs.db
*.res *.res
*.rc *.rc
!resources/qyouvideo.rc
/.qmake.cache /.qmake.cache
/.qmake.stash /.qmake.stash

View File

@@ -0,0 +1,32 @@
import QtQuick 6.8
import QtQuick.Controls 6.8
import QtQuick.Controls.Basic 6.8
BusyIndicator {
contentItem: Rectangle {
implicitWidth: 44
implicitHeight: 44
color: "transparent"
radius: 44
border.width: 4
border.color: Colors.primaryAlt
Rectangle {
width: 12
height: 12
anchors.top: parent.top
anchors.topMargin: 8
color: Colors.primary
radius: 12
}
// RotationAnimator {
// target: parent
// running: parent.parent.visible && parent.parent.running
// from: 0
// to: 360
// loops: Animation.Infinite
// duration: 1250
// }
}
}

View File

@@ -25,6 +25,7 @@ qt_add_qml_module(QYRComponents
Label.qml Label.qml
TabButton.qml TabButton.qml
YouAds.qml YouAds.qml
QML_FILES BusyIndicator.qml
# SOURCES qyrcomponents.cpp qyrcomponents.h # SOURCES qyrcomponents.cpp qyrcomponents.h
) )

View File

@@ -5,6 +5,8 @@ import QtQuick.Controls.Basic 6.8
Slider { Slider {
snapMode: Slider.SnapAlways snapMode: Slider.SnapAlways
property real buffered
implicitWidth: 130 implicitWidth: 130
implicitHeight: 20 implicitHeight: 20
@@ -26,6 +28,17 @@ Slider {
background: Rectangle { background: Rectangle {
color: "#555" color: "#555"
radius: 5 radius: 5
Rectangle {
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
visible: parent.parent.buffered != 0
width: parent.width * parent.parent.buffered
color: "#888"
radius: 5
}
} }
handle: Rectangle { handle: Rectangle {

View File

@@ -6,18 +6,41 @@ import QtQuick.Layouts 6.8
import QYRComponents 1.0 import QYRComponents 1.0
Rectangle { Rectangle {
visible: Player.hasVideo visible: Player.active
color: Colors.surface1 color: Colors.surface1
radius: 10
property bool unrolled: true
// width: childrenRect.width // width: childrenRect.width
height: 64 height: unrolled ? 560 : 96
MouseArea {
anchors.fill: parent
height: 20
hoverEnabled: true
propagateComposedEvents: true
onClicked: unrolled = true;
onContainsMouseChanged: function() {
if (!containsMouse) {
unrolled = false;
}
}
}
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
Item {
visible: unrolled
Layout.fillHeight: true
}
RowLayout { RowLayout {
Button { Button {
text: Player.playing ? "Pause" : "Play" text: Player.loading ? "Loading" : (Player.playing ? "Pause" : "Play")
enabled: !Player.loading
onClicked: function() { onClicked: function() {
if (Player.playing) { if (Player.playing) {
Player.pause() Player.pause()
@@ -32,10 +55,28 @@ Rectangle {
onClicked: Player.stop() onClicked: Player.stop()
} }
Label {
heading: "h4"
text: new Date(Player.position).toISOString().slice(14, 19)
}
Slider { Slider {
Layout.fillWidth: true Layout.fillWidth: true
from: 0 from: 0
to: 106 to: Player.duration
value: Player.position
buffered: Player.buffered
onMoved: Player.position = value
}
Label {
heading: "h4"
text: new Date(Player.duration).toISOString().slice(14, 19)
}
Label {
text: Player.buffered
} }
Slider { Slider {
@@ -45,5 +86,24 @@ Rectangle {
onMoved: Player.volume = value onMoved: Player.volume = value
} }
} }
Label {
Layout.fillWidth: true
wrapMode: Text.WordWrap
clip: true
text: Player.title
heading: "h2"
font.bold: true
}
Label {
visible: unrolled
Layout.fillWidth: true
wrapMode: Text.WordWrap
clip: true
text: Player.description
heading: "h4"
font.bold: true
}
} }
} }

View File

@@ -4,23 +4,19 @@ import QtQuick.Layouts 6.8
import QYRComponents 1.0 import QYRComponents 1.0
ColumnLayout { Item {
anchors.fill: parent anchors.fill: parent
property bool loading: true property bool loading: true
property bool failed: false property bool failed: false
VideoPlayer {
Layout.fillWidth: true
Layout.fillHeight: false
}
GridView { GridView {
Layout.fillWidth: true anchors.horizontalCenter: parent.horizontalCenter
Layout.fillHeight: true anchors.top: parent.top
// anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: Player.active ? 96 : 0
visible: !loading || !failed visible: !loading || !failed
// anchors.fill: parent anchors.fill: parent
model: ListModel { id: model } model: ListModel { id: model }
clip: true clip: true
@@ -28,8 +24,6 @@ ColumnLayout {
cellHeight: 224 cellHeight: 224
delegate: VideoEntry {} delegate: VideoEntry {}
Component.onCompleted: parent.fetchData()
} }
BusyIndicator { BusyIndicator {
@@ -66,6 +60,12 @@ ColumnLayout {
} }
} }
Timer {
interval: 1000
running: true
onTriggered: parent.fetchData()
}
function fetchData() { function fetchData() {
model.clear(); model.clear();
loading = true; loading = true;
@@ -76,15 +76,29 @@ ColumnLayout {
if (xhr.readyState == XMLHttpRequest.DONE) { if (xhr.readyState == XMLHttpRequest.DONE) {
loading = false; loading = false;
if (xhr.status != 200) { if (xhr.status != 200) {
console.log("Invalid response");
failed = true; failed = true;
return; return;
} }
const data = JSON.parse(xhr.responseText); const data = JSON.parse(xhr.responseText);
console.log("Received data, found " + data.length + " videos");
data.forEach(video => { data.forEach(video => {
model.append(video); model.append(video);
}); });
} }
} }
xhr.ontimeout = function() {
loading = false;
failed = true;
console.log("Request timed out");
}
xhr.send(); xhr.send();
} }
VideoPlayer {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
Layout.fillWidth: true
}
} }

View File

@@ -1,15 +1,59 @@
#include "player.h" #include "player.h"
// Public // HOLY GRAIL
// https://doc.qt.io/qt-6/qaudiobufferoutput.htmli t
Player::Player(QObject *parent) : QObject(parent), Player::Player(QObject *parent) : QObject(parent),
player(this), output(this), manager(this) player(this), output(this), manager(this)
{ {
QObject::connect(&this->player, &QMediaPlayer::mediaStatusChanged, this, [this] () { QObject::connect(&this->player, &QMediaPlayer::mediaStatusChanged, this, [this] () {
emit this->hasVideoChanged(); const QMediaPlayer::MediaStatus status = this->player.mediaStatus();
emit this->loadingChanged(); if (status == QMediaPlayer::NoMedia)
{
qDebug("Player::Player(): NoMedia");
this->stop();
}
else if (status == QMediaPlayer::BufferingMedia || status == QMediaPlayer::LoadingMedia)
{
qDebug("Player::Player() loadingChanged");
this->m_loading = true;
emit this->loadingChanged();
}
else if (status == QMediaPlayer::EndOfMedia)
{
qDebug("Player::Player() playingChanged");
emit this->playingChanged();
}
else
{
this->m_loading = false;
emit this->loadingChanged();
if (!this->m_initialLoadFinished)
{
this->m_initialLoadFinished = true;
this->play();
}
}
});
QObject::connect(&this->player, &QMediaPlayer::positionChanged, this, [this] () {
this->m_position = this->player.position();
emit this->positionChanged();
});
QObject::connect(&this->player, &QMediaPlayer::bufferProgressChanged, this, [this] () {
this->m_buffered = this->player.bufferedTimeRange().latestTime() / this->m_duration;
emit this->bufferedChanged();
});
QObject::connect(&this->player, &QMediaPlayer::errorOccurred, this, [this] () {
this->m_failed = true;
qDebug("Player::Player() failedChanged");
emit this->failedChanged();
}); });
QObject::connect(&this->player, &QMediaPlayer::playbackStateChanged, this, [this] () { QObject::connect(&this->player, &QMediaPlayer::playbackStateChanged, this, [this] () {
qDebug("Player::Player() playingChanged");
emit this->playingChanged(); emit this->playingChanged();
}); });
@@ -28,20 +72,10 @@ Player::~Player()
qDebug("Player::~Player(): Destructed"); qDebug("Player::~Player(): Destructed");
} }
bool Player::hasVideo() const
{
return this->player.isAvailable();
}
bool Player::loading() const // ********
{ // Read
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
{ {
@@ -53,15 +87,29 @@ float Player::volume() const
return this->output.volume(); return this->output.volume();
} }
// *********
// Write
// *********
void Player::setVolume(float newVolume) void Player::setVolume(float newVolume)
{ {
this->output.setVolume(newVolume); this->output.setVolume(newVolume);
} }
// Public slots void Player::setPosition(float newPosition)
{
this->player.setPosition(newPosition);
}
// ***********
// Methods
// ***********
void Player::loadVideo(QString id) void Player::loadVideo(QString id)
{ {
if (this->hasVideo()) if (this->m_active)
{ {
this->unloadVideo(); this->unloadVideo();
} }
@@ -82,8 +130,32 @@ void Player::loadVideo(QString id)
this->player.setSource(QUrl("https://youvideo.nonamesoft.xyz/youvideo/api/videofile/with_extension/" + id + data ["extension"].toString())); this->player.setSource(QUrl("https://youvideo.nonamesoft.xyz/youvideo/api/videofile/with_extension/" + id + data ["extension"].toString()));
emit this->hasVideoChanged(); this->m_title = data["name"].toString();
emit this->titleChanged();
this->m_description = data["description"].toString();
emit this->descriptionChanged();
this->m_id = id;
emit this->idChanged();
this->m_initialLoadFinished = false;
this->m_active = true;
emit this->activeChanged();
this->m_duration = data["metadata"]["duration"].toDouble() * 1000;
emit this->durationChanged();
this->m_position = 0;
emit this->positionChanged();
this->m_buffered = 0;
emit this->bufferedChanged();
this->m_loading = true;
emit this->loadingChanged(); emit this->loadingChanged();
this->m_failed = false; this->m_failed = false;
emit this->failedChanged(); emit this->failedChanged();
@@ -97,17 +169,14 @@ void Player::unloadVideo() {
this->player.setSource(QUrl("")); this->player.setSource(QUrl(""));
this->player.stop(); this->player.stop();
this->m_failed = false; this->m_failed = false;
emit this->activeChanged();
emit this->hasVideoChanged(); this->m_active = false;
emit this->failedChanged(); emit this->activeChanged();
emit this->loadingChanged();
emit this->playingChanged();
} }
void Player::play() void Player::play()
{ {
qDebug() << "Player::play(): Can't play video?" << this->hasVideo() << this->loading(); if (!this->m_active || this->m_loading)
if (!this->hasVideo() || this->loading())
{ {
return; return;
} }
@@ -116,8 +185,7 @@ void Player::play()
void Player::pause() void Player::pause()
{ {
qDebug() << "Player::pause(): Can't pause video?" << (!this->hasVideo() || this->loading()); if (!this->m_active || this->m_loading)
if (!this->hasVideo() || this->loading())
{ {
return; return;
} }
@@ -126,8 +194,7 @@ void Player::pause()
void Player::stop() void Player::stop()
{ {
qDebug() << "Player::stop(): Can't stop video?" << (!this->hasVideo() || this->loading()); if (!this->m_active || this->m_loading)
if (!this->hasVideo() || this->loading())
{ {
return; return;
} }

View File

@@ -13,22 +13,26 @@ class Player : public QObject
QML_SINGLETON QML_SINGLETON
QML_ELEMENT QML_ELEMENT
Q_PROPERTY(bool hasVideo READ hasVideo NOTIFY hasVideoChanged FINAL) Q_PROPERTY(QString title MEMBER m_title NOTIFY titleChanged FINAL)
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged FINAL) Q_PROPERTY(QString description MEMBER m_description NOTIFY descriptionChanged FINAL)
Q_PROPERTY(bool failed READ failed NOTIFY failedChanged FINAL) Q_PROPERTY(QString id MEMBER m_id NOTIFY idChanged FINAL)
Q_PROPERTY(bool playing READ playing NOTIFY playingChanged FINAL) Q_PROPERTY(bool active MEMBER m_active NOTIFY activeChanged FINAL)
Q_PROPERTY(float volume READ volume WRITE setVolume NOTIFY volumeChanged FINAL) Q_PROPERTY(float duration MEMBER m_duration NOTIFY durationChanged FINAL)
Q_PROPERTY(float position MEMBER m_position WRITE setPosition NOTIFY positionChanged FINAL)
Q_PROPERTY(float buffered MEMBER m_buffered NOTIFY bufferedChanged FINAL)
Q_PROPERTY(bool loading MEMBER m_loading NOTIFY loadingChanged FINAL)
Q_PROPERTY(bool failed MEMBER m_failed NOTIFY failedChanged FINAL)
Q_PROPERTY(bool playing READ playing NOTIFY playingChanged 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 hasVideo() const;
bool loading() const;
bool failed() const;
bool playing() const; bool playing() const;
float volume() const; float volume() const;
void setPosition(float newPosition);
void setVolume(float newVolume); void setVolume(float newVolume);
public slots: public slots:
@@ -39,7 +43,13 @@ public slots:
void stop(); void stop();
signals: signals:
void hasVideoChanged(); void titleChanged();
void descriptionChanged();
void idChanged();
void activeChanged();
void durationChanged();
void positionChanged();
void bufferedChanged();
void loadingChanged(); void loadingChanged();
void failedChanged(); void failedChanged();
void playingChanged(); void playingChanged();
@@ -50,5 +60,14 @@ private:
QAudioOutput output; QAudioOutput output;
QNetworkAccessManager manager; QNetworkAccessManager manager;
QString m_title = "";
QString m_description = "";
QString m_id = "";
float m_duration = 0;
float m_position = 0;
float m_buffered = 0;
bool m_initialLoadFinished = false;
bool m_active = false;
bool m_loading = false;
bool m_failed = false; bool m_failed = false;
}; };

96
resources/qyouvideo.rc Normal file
View File

@@ -0,0 +1,96 @@
// 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", "QYouVideo"
VALUE "FileVersion", "1.0.0.1"
VALUE "InternalName", "qyouvideo"
VALUE "LegalCopyright", "Copyright (C) Ghostfox 2025"
//VALUE "OriginalFilename", "appqyouvideo.exe"
VALUE "ProductName", "QYouVideo"
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