Skip to content

Commit

Permalink
add audiobook functions
Browse files Browse the repository at this point in the history
Signed-off-by: Conrad Hübler <Conrad.Huebler@gmx.net>
  • Loading branch information
conradhuebler committed Jan 1, 2025
1 parent 0824768 commit 8b85797
Show file tree
Hide file tree
Showing 12 changed files with 545 additions and 45 deletions.
69 changes: 63 additions & 6 deletions qml/components/PlaylistManager.qml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import QtQuick 2.0
import io.thp.pyotherside 1.5


Item {
id: root

Expand Down Expand Up @@ -214,55 +215,111 @@ Item {
playlistPython.playTrack(id)
currentTrackIndex()
}

/*
function playPosition(id) {
console.log(id)
playlistPython.canNext = false
mediaController.blockAutoNext = true
playlistPython.playPosition(id)
currentTrackIndex()
}

*/
function insertTrack(id) {
console.log("PlaylistManager.insertTrack", id)
playlistPython.insertTrack(id)
currentTrackIndex()
}

/*
function nextTrack() {
console.log("Next track called", mediaController.playbackState)
playlistPython.nextTrack()
currentTrackIndex()
}

*/
function nextTrackClicked() {
console.log("Next track clicked")
mediaController.blockAutoNext = true
playlistPython.nextTrack()
currentTrackIndex()
mediaController.blockAutoNext = false
if (playlistStorage.currentPlaylistName) {
playlistStorage.updatePosition(playlistStorage.currentPlaylistName, currentIndex);
}
}

function restartTrack(id) {
playlistPython.restartTrack()
currentTrackIndex()
}

/*
function previousTrack() {
playlistPython.canNext = false
playlistPython.previousTrack()
currentTrackIndex()
}

*/
function previousTrackClicked() {
playlistPython.canNext = false
mediaController.blockAutoNext = true
playlistPython.previousTrack()
currentTrackIndex()
if (playlistStorage.currentPlaylistName) {
playlistStorage.updatePosition(playlistStorage.currentPlaylistName, currentIndex);
}
}

function generateList() {
console.log("Playlist changed from main.qml")
playlistPython.generateList()
}

// Neue Funktionen zum Speichern/Laden
function saveCurrentPlaylist(name) {
var trackIds = [];
for(var i = 0; i < size; i++) {
trackIds.push(requestPlaylistItem(i));
}
playlistStorage.savePlaylist(name, trackIds, currentIndex);
playlistStorage.currentPlaylistName = name;
}

function loadSavedPlaylist(name) {
playlistStorage.loadPlaylist(name);
}

// Überschreibe die Navigation-Funktionen
function nextTrack() {
console.log("Next track called", mediaController.playbackState)
playlistPython.nextTrack()
currentTrackIndex()
// Speichere Fortschritt
if (playlistStorage.currentPlaylistName) {
playlistStorage.updatePosition(playlistStorage.currentPlaylistName, currentIndex);
}
}

function previousTrack() {
playlistPython.canNext = false
playlistPython.previousTrack()
currentTrackIndex()
// Speichere Fortschritt
if (playlistStorage.currentPlaylistName) {
playlistStorage.updatePosition(playlistStorage.currentPlaylistName, currentIndex);
}
}

function playPosition(position) {
playlistPython.canNext = false
mediaController.blockAutoNext = true
playlistPython.playPosition(position)
currentTrackIndex()
// Speichere Fortschritt
if (playlistStorage.currentPlaylistName) {
playlistStorage.updatePosition(playlistStorage.currentPlaylistName, position);
}
}

function getSavedPlaylists() {
return playlistStorage.getPlaylistInfo();
}
}
158 changes: 158 additions & 0 deletions qml/components/PlaylistStorage.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import QtQuick 2.0
import QtQuick.LocalStorage 2.0

Item {
id: root

// Signale für Playlist-Events
signal playlistSaved(string name, var trackIds)
signal playlistLoaded(string name, var trackIds, int position)
signal playlistsChanged()
signal playlistDeleted(string name)

// Initialisiere Datenbank
function getDatabase() {
return LocalStorage.openDatabaseSync(
"TidalPlayerDB",
"1.0",
"Tidal Player Playlist Storage",
1000000
);
}

// Erstelle Tabellen
function initDatabase() {
var db = getDatabase();
db.transaction(function(tx) {
// Erweiterte Tabelle mit Position und Timestamp
tx.executeSql('CREATE TABLE IF NOT EXISTS playlists(
name TEXT PRIMARY KEY,
tracks TEXT,
position INTEGER DEFAULT 0,
last_played TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)');
});
}

// Speichere Playlist mit Position
function savePlaylist(name, trackIds, position) {
var db = getDatabase();
var tracksJson = JSON.stringify(trackIds);

db.transaction(function(tx) {
tx.executeSql('INSERT OR REPLACE INTO playlists (name, tracks, position, last_played) VALUES(?, ?, ?, CURRENT_TIMESTAMP)',
[name, tracksJson, position]);
});

playlistSaved(name, trackIds);
playlistsChanged();
}

// Lade Playlist mit Position
function loadPlaylist(name) {
var db = getDatabase();
var result;

db.transaction(function(tx) {
result = tx.executeSql('SELECT tracks, position FROM playlists WHERE name = ?', [name]);
if (result.rows.length > 0) {
var trackIds = JSON.parse(result.rows.item(0).tracks);
var position = result.rows.item(0).position;

// Aktualisiere last_played
tx.executeSql('UPDATE playlists SET last_played = CURRENT_TIMESTAMP WHERE name = ?', [name]);

playlistLoaded(name, trackIds, position);
}
});
}

// Update Position einer Playlist
function updatePosition(name, position) {
var db = getDatabase();

db.transaction(function(tx) {
tx.executeSql('UPDATE playlists SET position = ?, last_played = CURRENT_TIMESTAMP WHERE name = ?',
[position, name]);
});
}

// Lösche Playlist
function deletePlaylist(name) {
var db = getDatabase();

db.transaction(function(tx) {
tx.executeSql('DELETE FROM playlists WHERE name = ?', [name]);
});

playlistDeleted(name);
playlistsChanged();
}

// Hole alle Playlist-Namen mit Zusatzinformationen
function getPlaylistInfo() {
var db = getDatabase();
var playlists = [];

db.transaction(function(tx) {
var result = tx.executeSql('SELECT name, position, tracks, last_played FROM playlists ORDER BY last_played DESC');
for (var i = 0; i < result.rows.length; i++) {
var item = result.rows.item(i);
var tracks = JSON.parse(item.tracks);
playlists.push({
name: item.name,
position: item.position,
trackCount: tracks.length,
lastPlayed: item.last_played
});
}
});

return playlists;
}

// In PlaylistManager.qml oder wo der PlaylistStorage verwendet wird
function saveCurrentPlaylistState() {
var trackIds = []
for(var i = 0; i < playlistManager.size; i++) {
var id = playlistManager.requestPlaylistItem(i)
trackIds.push(id)
}
// Speichere als spezielle Playlist "_current"
playlistStorage.savePlaylist("_current", trackIds, playlistManager.currentIndex)
}

// Beim Laden
function loadCurrentPlaylistState() {
var currentPlaylist = playlistStorage.loadPlaylist("_current")
if (currentPlaylist && currentPlaylist.tracks.length > 0) {
playlistManager.clearPlayList()
for (var i = 0; i < currentPlaylist.tracks.length; i++) {
playlistManager.appendTrack(currentPlaylist.tracks[i])
}
// Position wiederherstellen
if (currentPlaylist.position >= 0) {
playlistManager.playPosition(currentPlaylist.position)
}
}
}
Component.onCompleted: {
initDatabase();
loadCurrentPlaylistState()
}
// Bei App-Beendigung
Component.onDestruction: {
saveCurrentPlaylistState()
}

// Optional: Bei wichtigen Playlist-Änderungen
Connections {
target: playlistManager
onListChanged: {
saveCurrentPlaylistState()
}
onCurrentIndexChanged: {
saveCurrentPlaylistState()
}
}
}
1 change: 1 addition & 0 deletions qml/components/TidalCache.qml
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ id: root
bio: result.bio,
timestamp: Date.now(),
}
console.log("Adding to cache ...")

saveArtistToCache(artistData)
return artistData
Expand Down
40 changes: 40 additions & 0 deletions qml/dialogs/saveplaylist.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import QtQuick 2.0
import Sailfish.Silica 1.0

Dialog {
id: dialog

property string playlistName: nameField.text
property string suggestedName: "" // Wird von der AlbumPage übergeben

canAccept: nameField.text.length > 0

Column {
width: parent.width
spacing: Theme.paddingMedium

DialogHeader {
title: qsTr("Save as Playlist")
}

TextField {
id: nameField
width: parent.width
placeholderText: qsTr("Enter playlist name")
label: qsTr("Playlist name")
text: suggestedName // Verwendet den übergebenen Albumtitel
EnterKey.enabled: text.length > 0
EnterKey.iconSource: "image://theme/icon-m-enter-accept"
EnterKey.onClicked: dialog.accept()
}

Label {
x: Theme.horizontalPageMargin
width: parent.width - 2*x
text: qsTr("This will create a new playlist from all tracks in this album.")
wrapMode: Text.Wrap
font.pixelSize: Theme.fontSizeSmall
color: Theme.secondaryColor
}
}
}
21 changes: 21 additions & 0 deletions qml/harbour-tidalplayer.qml
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,34 @@ ApplicationWindow
tidalApi.playTrackId(track)
}
}

}

TidalCache
{
id: cacheManager
}

PlaylistStorage {
id: playlistStorage

property string currentPlaylistName: ""

onPlaylistLoaded: {
// Wenn eine Playlist geladen wird
currentPlaylistName = name;
playlistManager.clearPlayList();
trackIds.forEach(function(trackId) {
playlistManager.appendTrack(trackId);
});
// Setze die gespeicherte Position
if (position >= 0) {
playlistManager.playPosition(position);
}
}
}


MediaController
{
id: mediaController
Expand Down
Loading

0 comments on commit 8b85797

Please sign in to comment.