mirror of
https://github.com/Team-Resurgent/XBMC4Xbox.git
synced 2026-08-15 11:18:13 -07:00
If ever adding the XBMC4Xbox source to GitHub use "git add -f -A" or it wont add all the files.
466 lines
15 KiB
C++
466 lines
15 KiB
C++
/*
|
|
* DAAP Support for XBMC
|
|
* Copyright (c) 2004 Forza (Chris Barnett)
|
|
* Portions Copyright (c) by the authors of libOpenDAAP
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "utils/log.h"
|
|
#include "DAAPFile.h"
|
|
#include "DAAPDirectory.h"
|
|
#include "SectionLoader.h"
|
|
#include "utils/URIUtils.h"
|
|
#include "music/tags/MusicInfoTag.h"
|
|
#include "FileItem.h"
|
|
|
|
namespace XFILE
|
|
{
|
|
|
|
// these are the different request urls that exist.. i think the first one would always work, but take safe route
|
|
#define REQUEST42 "daap://%s/databases/%i/items/%i.%s?session-id=%i&revision-id=%i"
|
|
#define REQUEST45 "daap://%s/databases/%i/items/%i.%s?session-id=%i"
|
|
|
|
const char unknownArtistAlbum[] = "Unknown";
|
|
|
|
CDAAPDirectory::CDAAPDirectory(void)
|
|
{
|
|
CSectionLoader::Load("LIBXDAAP");
|
|
// m_currLevel holds where we are in the playlist/artist/album/songs hierarchy (0,1,2,3)
|
|
m_currLevel = -1;
|
|
m_thisHost = NULL;
|
|
m_artisthead = NULL;
|
|
m_currentSongItems = NULL;
|
|
m_currentSongItemCount = 0;
|
|
}
|
|
|
|
CDAAPDirectory::~CDAAPDirectory(void)
|
|
{
|
|
//if (m_thisClient) DAAP_Client_Release(m_thisClient);
|
|
free_artists();
|
|
|
|
m_thisHost = NULL;
|
|
m_artisthead = NULL;
|
|
|
|
m_currentSongItems = NULL;
|
|
CSectionLoader::Unload("LIBXDAAP");
|
|
}
|
|
|
|
bool CDAAPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
|
|
{
|
|
int c;
|
|
//wchar_t wStrFile[1024]; // buffer for converting strings
|
|
|
|
CURL url(strPath);
|
|
|
|
CStdString strRoot = strPath;
|
|
URIUtils::AddSlashAtEnd(strRoot);
|
|
|
|
CStdString host = url.GetHostName();
|
|
if (url.HasPort())
|
|
host.Format("%s:%i",url.GetHostName(),url.GetPort());
|
|
m_thisHost = g_DaapClient.GetHost(host);
|
|
if (!m_thisHost)
|
|
return false;
|
|
|
|
// find out where we are in the folder hierarchy
|
|
m_currLevel = GetCurrLevel(strRoot);
|
|
CLog::Log(LOGDEBUG, "DAAPDirectory: Current Level is %i", m_currLevel);
|
|
|
|
// if we have at least one database we should show it's contents
|
|
if (m_thisHost->nDatabases)
|
|
{
|
|
CLog::Log(LOGDEBUG, "Have %i databases", m_thisHost->nDatabases);
|
|
//Store the first database
|
|
g_DaapClient.m_iDatabase = m_thisHost->databases[0].id;
|
|
|
|
m_currentSongItems = m_thisHost->dbitems[0].items;
|
|
m_currentSongItemCount = m_thisHost->dbitems[0].nItems;
|
|
|
|
// Get the songs from the database if we haven't already
|
|
if (!m_artisthead && (m_currLevel >= 0 && m_currLevel < 2))
|
|
{
|
|
CLog::Log(LOGDEBUG, "Getting songs from the database. Have %i", m_currentSongItemCount);
|
|
// Add each artist and album to an array
|
|
int c;
|
|
for (c = 0; c < m_currentSongItemCount; c++)
|
|
{
|
|
AddToArtistAlbum(m_currentSongItems[c].songartist, m_currentSongItems[c].songalbum);
|
|
}
|
|
}
|
|
|
|
|
|
if (m_currLevel < 0) // root, so show playlists
|
|
{
|
|
for (c = 0; c < m_thisHost->dbplaylists->nPlaylists; c++)
|
|
{
|
|
CStdString strFile;
|
|
//size_t strLen;
|
|
|
|
// we use UTF-8 internally, so no need to convert
|
|
strFile = m_thisHost->dbplaylists->playlists[c].itemname;
|
|
|
|
// Add item to directory list
|
|
CLog::Log(LOGDEBUG, "DAAPDirectory: Adding item %s", strFile.c_str());
|
|
CFileItemPtr pItem(new CFileItem(strFile));
|
|
pItem->SetPath(strRoot + m_thisHost->dbplaylists->playlists[c].itemname + "/");
|
|
pItem->m_bIsFolder = true;
|
|
items.Add(pItem);
|
|
}
|
|
}
|
|
else if (m_currLevel == 0) // playlists, so show albums
|
|
{
|
|
CStdString strFolder;
|
|
bool bFoundMatch;
|
|
|
|
// find the playlist
|
|
bFoundMatch = false;
|
|
for (c = 0; c < m_thisHost->dbplaylists->nPlaylists; c++)
|
|
{
|
|
if (m_thisHost->dbplaylists->playlists[c].itemname == m_selectedPlaylist)
|
|
{
|
|
bFoundMatch = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if we found it show the songs contained ...
|
|
if (bFoundMatch)
|
|
{
|
|
|
|
// if selected playlist name == d/b name then show in artist/album/song formation
|
|
if (strcmp(m_thisHost->databases[0].name, m_thisHost->dbplaylists->playlists[c].itemname) == 0)
|
|
{
|
|
CStdString strBuffer;
|
|
artistPTR *cur = m_artisthead;
|
|
while (cur)
|
|
{
|
|
strBuffer = cur->artist;
|
|
CLog::Log(LOGDEBUG, "DAAPDirectory: Adding item %s", strBuffer.c_str());
|
|
CFileItemPtr pItem(new CFileItem(strBuffer));
|
|
pItem->SetPath(strRoot + cur->artist + "/");
|
|
pItem->m_bIsFolder = true;
|
|
items.Add(pItem);
|
|
cur = cur->next;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no support for playlist items in libOpenDAAP yet? - there is now :)
|
|
|
|
int j;
|
|
for (j = 0; j < m_thisHost->dbplaylists->playlists[c].count; j++)
|
|
{
|
|
// the playlist id is the song id, these do not directly match the array
|
|
// position so we've no choice but to cycle through all the songs until
|
|
// we find the one we want.
|
|
int i, idx;
|
|
idx = -1;
|
|
for (i = 0; i < m_currentSongItemCount; i ++)
|
|
{
|
|
if (m_currentSongItems[i].id == m_thisHost->dbplaylists->playlists[c].items[j].songid)
|
|
{
|
|
idx = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (idx > -1)
|
|
{
|
|
CLog::Log(LOGDEBUG, "DAAPDirectory: Adding item %s", m_currentSongItems[idx].itemname);
|
|
CFileItemPtr pItem(new CFileItem(m_currentSongItems[idx].itemname));
|
|
|
|
CStdString path;
|
|
if( m_thisHost->version_major != 3 )
|
|
{
|
|
path.Format(REQUEST42,
|
|
m_thisHost->host,
|
|
g_DaapClient.m_iDatabase,
|
|
m_currentSongItems[idx].id,
|
|
m_currentSongItems[idx].songformat,
|
|
m_thisHost->sessionid,
|
|
m_thisHost->revision_number);
|
|
|
|
}
|
|
else
|
|
{
|
|
path.Format(REQUEST45,
|
|
m_thisHost->host,
|
|
g_DaapClient.m_iDatabase,
|
|
m_currentSongItems[idx].id,
|
|
m_currentSongItems[idx].songformat,
|
|
m_thisHost->sessionid);
|
|
}
|
|
|
|
pItem->SetPath(path);
|
|
pItem->m_bIsFolder = false;
|
|
pItem->m_dwSize = m_currentSongItems[idx].songsize;
|
|
|
|
pItem->GetMusicInfoTag()->SetURL(pItem->GetPath());
|
|
pItem->GetMusicInfoTag()->SetTitle(m_currentSongItems[idx].itemname);
|
|
pItem->GetMusicInfoTag()->SetArtist(m_currentSongItems[idx].songartist);
|
|
pItem->GetMusicInfoTag()->SetAlbum(m_currentSongItems[idx].songalbum);
|
|
|
|
//pItem->m_musicInfoTag.SetTrackNumber(m_currentSongItems[idx].songtracknumber);
|
|
pItem->GetMusicInfoTag()->SetTrackNumber(m_thisHost->dbplaylists->playlists[c].items[j].songid);
|
|
//pItem->m_musicInfoTag.SetTrackNumber(j+1);
|
|
//pItem->m_musicInfoTag.SetPartOfSet(m_currentSongItems[idx].songdiscnumber);
|
|
pItem->GetMusicInfoTag()->SetDuration((int) (m_currentSongItems[idx].songtime / 1000));
|
|
pItem->GetMusicInfoTag()->SetLoaded(true);
|
|
|
|
items.Add(pItem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (m_currLevel == 1) // artists, so show albums
|
|
{
|
|
// Find the artist ...
|
|
artistPTR *cur = m_artisthead;
|
|
while (cur)
|
|
{
|
|
if (cur->artist == m_selectedArtist) break;
|
|
cur = cur->next;
|
|
}
|
|
|
|
// if we find it, then show albums for this artist
|
|
if (cur)
|
|
{
|
|
albumPTR *curAlbum = cur->albumhead;
|
|
while (curAlbum)
|
|
{
|
|
CLog::Log(LOGDEBUG, "DAAPDirectory: Adding item %s", curAlbum->album);
|
|
CFileItemPtr pItem(new CFileItem(curAlbum->album));
|
|
|
|
pItem->SetPath(strRoot + curAlbum->album + "/");
|
|
pItem->m_bIsFolder = true;
|
|
items.Add(pItem);
|
|
curAlbum = curAlbum->next;
|
|
}
|
|
}
|
|
}
|
|
else if (m_currLevel == 2) // albums, so show songs
|
|
{
|
|
int c;
|
|
for (c = 0; c < m_currentSongItemCount; c++)
|
|
{
|
|
// mt-daapd will sometimes give us null artist and album names
|
|
if (m_currentSongItems[c].songartist && m_currentSongItems[c].songalbum)
|
|
{
|
|
char *artist = m_currentSongItems[c].songartist;
|
|
char *album = m_currentSongItems[c].songalbum;
|
|
if (!strlen(artist)) artist = (char *)unknownArtistAlbum;
|
|
if (!strlen(album)) album = (char *)unknownArtistAlbum;
|
|
// if this song is for the current artist & album add it to the file list
|
|
if (artist == m_selectedArtist && album == m_selectedAlbum)
|
|
{
|
|
CLog::Log(LOGDEBUG, "DAAPDirectory: Adding item %s", m_currentSongItems[c].itemname);
|
|
CFileItemPtr pItem(new CFileItem(m_currentSongItems[c].itemname));
|
|
|
|
CStdString path;
|
|
if( m_thisHost->version_major != 3 )
|
|
{
|
|
path.Format(REQUEST42,
|
|
m_thisHost->host,
|
|
g_DaapClient.m_iDatabase,
|
|
m_currentSongItems[c].id,
|
|
m_currentSongItems[c].songformat,
|
|
m_thisHost->sessionid,
|
|
m_thisHost->revision_number);
|
|
|
|
}
|
|
else
|
|
{
|
|
path.Format(REQUEST45,
|
|
m_thisHost->host,
|
|
g_DaapClient.m_iDatabase,
|
|
m_currentSongItems[c].id,
|
|
m_currentSongItems[c].songformat,
|
|
m_thisHost->sessionid);
|
|
}
|
|
|
|
pItem->SetPath(path);
|
|
pItem->m_bIsFolder = false;
|
|
pItem->m_dwSize = m_currentSongItems[c].songsize;
|
|
|
|
pItem->GetMusicInfoTag()->SetURL(pItem->GetPath());
|
|
|
|
pItem->GetMusicInfoTag()->SetTitle(m_currentSongItems[c].itemname);
|
|
pItem->GetMusicInfoTag()->SetArtist(m_selectedArtist);
|
|
pItem->GetMusicInfoTag()->SetAlbum(m_selectedAlbum);
|
|
|
|
pItem->GetMusicInfoTag()->SetTrackNumber(m_currentSongItems[c].songtracknumber);
|
|
pItem->GetMusicInfoTag()->SetPartOfSet(m_currentSongItems[c].songdiscnumber);
|
|
pItem->GetMusicInfoTag()->SetDuration((int) (m_currentSongItems[c].songtime / 1000));
|
|
pItem->GetMusicInfoTag()->SetLoaded(true);
|
|
|
|
items.Add(pItem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CDAAPDirectory::free_albums(albumPTR *alb)
|
|
{
|
|
albumPTR *cur = alb;
|
|
while (cur)
|
|
{
|
|
albumPTR *next = cur->next;
|
|
if (cur->album) free(cur->album);
|
|
free(cur);
|
|
cur = next;
|
|
}
|
|
}
|
|
|
|
void CDAAPDirectory::free_artists()
|
|
{
|
|
artistPTR *cur = m_artisthead;
|
|
while (cur)
|
|
{
|
|
artistPTR *next = cur->next;
|
|
if (cur->artist) free(cur->artist);
|
|
if (cur->albumhead) free_albums(cur->albumhead);
|
|
free(cur);
|
|
cur = next;
|
|
}
|
|
m_artisthead = NULL;
|
|
}
|
|
|
|
void CDAAPDirectory::AddToArtistAlbum(char *artist_s, char *album_s)
|
|
{
|
|
/*if (artist_s && album_s)
|
|
CLog::Log(LOGDEBUG, "DAAP::AddToArtistAlbum(%s, %s)", artist_s, album_s);
|
|
else if (artist_s)
|
|
CLog::Log(LOGDEBUG, "DAAP::AddToArtistAlbum called with NULL album_s");
|
|
else if (album_s)
|
|
CLog::Log(LOGDEBUG, "DAAP::AddToArtistAlbum called with NULL artist_s");
|
|
else
|
|
CLog::Log(LOGDEBUG, "DAAP::AddToArtistAlbum called with NULL artist_s and NULL album_s");*/
|
|
|
|
// mt-daapd will sometimes give us null artist and album names
|
|
if (!artist_s || !album_s) return;
|
|
|
|
// check for empty strings
|
|
if (strlen(artist_s) == 0)
|
|
artist_s = (char *)unknownArtistAlbum;
|
|
if (strlen(album_s) == 0)
|
|
album_s = (char *)unknownArtistAlbum;
|
|
artistPTR *cur_artist = m_artisthead;
|
|
albumPTR *cur_album = NULL;
|
|
while (cur_artist)
|
|
{
|
|
if (strcmp(cur_artist->artist, artist_s) == 0)
|
|
break;
|
|
cur_artist = cur_artist->next;
|
|
}
|
|
if (!cur_artist)
|
|
{
|
|
artistPTR *newartist = (artistPTR *) malloc(sizeof(artistPTR));
|
|
|
|
newartist->artist = (char *) malloc(strlen(artist_s) + 1);
|
|
strcpy(newartist->artist, artist_s);
|
|
|
|
newartist->albumhead = NULL;
|
|
|
|
newartist->next = m_artisthead;
|
|
m_artisthead = newartist;
|
|
|
|
cur_artist = newartist;
|
|
}
|
|
cur_album = cur_artist->albumhead;
|
|
while (cur_album)
|
|
{
|
|
if (strcmp(cur_album->album, album_s) == 0)
|
|
break;
|
|
cur_album = cur_album->next;
|
|
}
|
|
if (!cur_album)
|
|
{
|
|
albumPTR *newalbum = (albumPTR *) malloc(sizeof(albumPTR));
|
|
|
|
newalbum->album = (char *) malloc(strlen(album_s) + 1);
|
|
strcpy(newalbum->album, album_s);
|
|
|
|
newalbum->next = cur_artist->albumhead;
|
|
cur_artist->albumhead = newalbum;
|
|
|
|
cur_album = newalbum;
|
|
}
|
|
}
|
|
|
|
int CDAAPDirectory::GetCurrLevel(CStdString strPath)
|
|
{
|
|
int intSPos;
|
|
int intEPos;
|
|
int intLevel;
|
|
int intCnt;
|
|
CStdString strJustPath;
|
|
|
|
intSPos = strPath.Find("://");
|
|
if (intSPos > -1)
|
|
strJustPath = strPath.Right(strPath.size() - (intSPos + 3));
|
|
else
|
|
strJustPath = strPath;
|
|
|
|
URIUtils::RemoveSlashAtEnd(strJustPath);
|
|
|
|
intLevel = -1;
|
|
intSPos = strPath.length();
|
|
while (intSPos > -1)
|
|
{
|
|
intSPos = strJustPath.ReverseFind("/", intSPos);
|
|
if (intSPos > -1) intLevel ++;
|
|
intSPos -= 2;
|
|
}
|
|
|
|
m_selectedPlaylist = "";
|
|
m_selectedArtist = "";
|
|
m_selectedAlbum = "";
|
|
intCnt = intLevel;
|
|
intEPos = (strJustPath.length() - 1);
|
|
while (intCnt >= 0)
|
|
{
|
|
intSPos = strJustPath.ReverseFind("/", intEPos);
|
|
if (intSPos > -1)
|
|
{
|
|
if (intCnt == 2) // album
|
|
{
|
|
m_selectedAlbum = strJustPath.substr(intSPos + 1, (intEPos - intSPos));
|
|
}
|
|
else if (intCnt == 1) // artist
|
|
{
|
|
m_selectedArtist = strJustPath.substr(intSPos + 1, (intEPos - intSPos));
|
|
}
|
|
else if (intCnt == 0) // playlist
|
|
{
|
|
m_selectedPlaylist = strJustPath.substr(intSPos + 1, (intEPos - intSPos));
|
|
}
|
|
|
|
intEPos = (intSPos - 1);
|
|
intCnt --;
|
|
}
|
|
}
|
|
|
|
return intLevel;
|
|
}
|
|
|
|
}
|
|
|