/***************************************************************************
copyright : ( C ) 2005 , 2006 by Martin Aumueller
email : aumuell @ reserv . at
copyright : ( C ) 2004 by Christian Muehlhaeuser
email : chris @ chris . de
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/***************************************************************************
* This library is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License version 2 as *
* published by the Free Software Foundation . *
* *
* This library 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 *
* Lesser General Public License for more details . *
* *
* You should have received a copy of the GNU General Public License *
* along with this library ; if not , write to the Free Software *
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , *
* MA 02110 - 1301 USA *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define DEBUG_PREFIX "IpodMediaDevice"
# include <config.h>
# include "ipodmediadevice.h"
AMAROK_EXPORT_PLUGIN ( IpodMediaDevice )
# include <debug.h>
# include <metabundle.h>
# include <collectiondb.h>
# include <statusbar/statusbar.h>
# include <k3bexporter.h>
# include <playlist.h>
# include <collectionbrowser.h>
# include <playlistbrowser.h>
# include <tagdialog.h>
# include <threadmanager.h>
# include <metadata/tplugins.h>
# include <hintlineedit.h>
# include <tdeactionclasses.h>
# include <tdeapplication.h>
# include <kmountpoint.h>
# include <kpushbutton.h>
# include <kprogress.h>
# include <tdemessagebox.h>
# include <kiconloader.h>
# include <tdepopupmenu.h>
# include <tqcheckbox.h>
# include <tqdir.h>
# include <tqfileinfo.h>
# include <tqlabel.h>
# include <tqlineedit.h>
# include <tqregexp.h>
# include <tqtimer.h>
# include <tqtooltip.h>
# ifdef HAVE_STATVFS
# include <stdint.h>
# include <sys/statvfs.h>
# endif
# include <cstdlib>
# include <unistd.h>
# ifndef HAVE_ITDB_MEDIATYPE
# define mediatype unk208
# endif
# include "metadata/audible/taglib_audiblefile.h"
struct PodcastInfo
{
// per show
TQString url ;
TQString description ;
TQDateTime date ;
TQString author ;
bool listened ;
// per channel
TQString rss ;
PodcastInfo ( ) { listened = false ; }
} ;
class TrackList : public TQPtrList < Itdb_Track >
{
int compareItems ( TQPtrCollection : : Item track1 , TQPtrCollection : : Item track2 )
{
Itdb_Track * t1 = ( Itdb_Track * ) track1 ;
Itdb_Track * t2 = ( Itdb_Track * ) track2 ;
if ( t1 - > track_nr ! = t2 - > track_nr )
return t1 - > track_nr - t2 - > track_nr ;
return strcasecmp ( t1 - > title , t2 - > title ) ;
}
} ;
class IpodMediaItem : public MediaItem
{
public :
IpodMediaItem ( TQListView * parent , MediaDevice * dev )
: MediaItem ( parent ) { init ( dev ) ; }
IpodMediaItem ( TQListViewItem * parent , MediaDevice * dev )
: MediaItem ( parent ) { init ( dev ) ; }
IpodMediaItem ( TQListView * parent , TQListViewItem * after , MediaDevice * dev )
: MediaItem ( parent , after ) { init ( dev ) ; }
IpodMediaItem ( TQListViewItem * parent , TQListViewItem * after , MediaDevice * dev )
: MediaItem ( parent , after ) { init ( dev ) ; }
virtual ~ IpodMediaItem ( ) { delete m_podcastInfo ; }
void init ( MediaDevice * dev )
{
m_track = 0 ;
m_playlist = 0 ;
m_device = dev ;
m_podcastInfo = 0 ;
}
void bundleFromTrack ( Itdb_Track * track , const TQString & path )
{
MetaBundle * bundle = new MetaBundle ( ) ;
bundle - > setArtist ( TQString : : fromUtf8 ( track - > artist ) ) ;
bundle - > setComposer ( TQString : : fromUtf8 ( track - > composer ) ) ;
bundle - > setAlbum ( TQString : : fromUtf8 ( track - > album ) ) ;
bundle - > setTitle ( TQString : : fromUtf8 ( track - > title ) ) ;
bundle - > setComment ( TQString : : fromUtf8 ( track - > comment ) ) ;
bundle - > setGenre ( TQString : : fromUtf8 ( track - > genre ) ) ;
bundle - > setYear ( track - > year ) ;
bundle - > setTrack ( track - > track_nr ) ;
bundle - > setDiscNumber ( track - > cd_nr ) ;
bundle - > setBpm ( track - > BPM ) ;
bundle - > setLength ( track - > tracklen / 1000 ) ;
bundle - > setBitrate ( track - > bitrate ) ;
bundle - > setSampleRate ( track - > samplerate ) ;
bundle - > setPath ( path ) ;
bundle - > setFilesize ( track - > size ) ;
TQString rss ( track - > podcastrss ) ;
TQString url ( track - > podcasturl ) ;
TQString desc ( track - > description ) ;
TQString subtitle ( track - > subtitle ) ;
TQDateTime date ;
date . setTime_t ( itdb_time_mac_to_host ( track - > time_released ) ) ;
if ( ! rss . isEmpty ( ) | | ! url . isEmpty ( ) )
{
PodcastEpisodeBundle peb ( KURL : : fromPathOrURL ( url ) , KURL : : fromPathOrURL ( rss ) ,
track - > title , track - > artist , desc , date . toString ( Qt : : ISODate ) , TQString ( ) /*type*/ ,
bundle - > length ( ) , TQString ( ) /*guid*/ , track - > playcount < = 0 ) ;
bundle - > setPodcastBundle ( peb ) ;
}
setBundle ( bundle ) ;
}
Itdb_Track * m_track ;
Itdb_Playlist * m_playlist ;
PodcastInfo * m_podcastInfo ;
int played ( ) const { return m_track ? m_track - > playcount : 0 ; }
int recentlyPlayed ( ) const { return m_track ? m_track - > recent_playcount : 0 ; }
int rating ( ) const { return m_track ? m_track - > rating : 0 ; }
void setRating ( int rating )
{
if ( m_track ) m_track - > rating = m_track - > app_rating = rating ;
if ( dynamic_cast < IpodMediaDevice * > ( device ( ) ) )
static_cast < IpodMediaDevice * > ( device ( ) ) - > m_dbChanged = true ;
}
void setPlayCount ( int playcount )
{
if ( m_track )
m_track - > playcount = playcount ;
if ( dynamic_cast < IpodMediaDevice * > ( device ( ) ) )
static_cast < IpodMediaDevice * > ( device ( ) ) - > m_dbChanged = true ;
}
void setLastPlayed ( uint lastplay )
{
if ( m_track )
m_track - > time_played = itdb_time_host_to_mac ( lastplay ) ;
if ( dynamic_cast < IpodMediaDevice * > ( device ( ) ) )
static_cast < IpodMediaDevice * > ( device ( ) ) - > m_dbChanged = true ;
}
bool ratingChanged ( ) const { return m_track ? m_track - > rating ! = m_track - > app_rating : false ; }
void setListened ( bool l )
{
MediaItem : : setListened ( l ) ;
if ( type ( ) = = PODCASTITEM )
{
if ( m_podcastInfo )
m_podcastInfo - > listened = listened ( ) ;
if ( m_track )
m_track - > mark_unplayed = listened ( ) ? 0x01 : 0x02 ;
}
}
TQDateTime playTime ( ) const
{
TQDateTime t ;
if ( m_track )
t . setTime_t ( itdb_time_mac_to_host ( m_track - > time_played ) ) ;
return t ;
}
IpodMediaItem * findTrack ( Itdb_Track * track )
{
if ( m_track = = track )
return this ;
for ( IpodMediaItem * it = dynamic_cast < IpodMediaItem * > ( firstChild ( ) ) ;
it ;
it = dynamic_cast < IpodMediaItem * > ( it - > nextSibling ( ) ) )
{
IpodMediaItem * found = it - > findTrack ( track ) ;
if ( found )
return found ;
}
return 0 ;
}
} ;
IpodMediaDevice : : IpodMediaDevice ( )
: MediaDevice ( )
, m_masterPlaylist ( 0 )
, m_podcastPlaylist ( 0 )
, m_lockFile ( 0 )
, m_customAction ( 0 )
{
registerTaglibPlugins ( ) ;
m_podcastItem = 0 ;
m_staleItem = 0 ;
m_orphanedItem = 0 ;
m_invisibleItem = 0 ;
m_playlistItem = 0 ;
m_dbChanged = false ;
m_itdb = 0 ;
m_podcastItem = 0 ;
m_staleItem = 0 ;
m_orphanedItem = 0 ;
m_invisibleItem = 0 ;
m_playlistItem = 0 ;
m_supportsArtwork = true ;
m_supportsVideo = false ;
m_rockboxFirmware = false ;
m_isShuffle = false ;
m_isMobile = false ;
m_isIPhone = false ;
m_needsFirewireGuid = false ;
m_requireMount = true ;
m_name = " iPod " ;
// config stuff
m_autoConnect = true ;
m_syncStatsCheck = 0 ;
m_autoDeletePodcastsCheck = 0 ;
TDEActionCollection * ac = new TDEActionCollection ( this ) ;
TDEActionMenu * am = new TDEActionMenu ( i18n ( " iPod " ) , Amarok : : icon ( " device " ) , ac ) ;
m_customAction = am ;
m_customAction - > setEnabled ( false ) ;
am - > setDelayed ( false ) ;
TDEPopupMenu * menu = am - > popupMenu ( ) ;
connect ( menu , TQT_SIGNAL ( activated ( int ) ) , TQT_SLOT ( slotIpodAction ( int ) ) ) ;
menu - > insertItem ( i18n ( " Stale and Orphaned " ) , CHECK_INTEGRITY ) ;
menu - > insertItem ( i18n ( " Update Artwork " ) , UPDATE_ARTWORK ) ;
TDEPopupMenu * ipodGen = new TDEPopupMenu ( menu ) ;
menu - > insertItem ( i18n ( " Set iPod Model " ) , ipodGen ) ;
const Itdb_IpodInfo * table = itdb_info_get_ipod_info_table ( ) ;
if ( ! table )
return ;
bool infoFound = false ;
int generation = ITDB_IPOD_GENERATION_FIRST ;
do
{
const Itdb_IpodInfo * info = table ;
infoFound = false ;
TDEPopupMenu * gen = 0 ;
int index = SET_IPOD_MODEL ;
while ( info - > model_number )
{
if ( info - > ipod_generation = = generation )
{
if ( ! infoFound )
{
infoFound = true ;
gen = new TDEPopupMenu ( ipodGen ) ;
connect ( gen , TQT_SIGNAL ( activated ( int ) ) , TQT_SLOT ( slotIpodAction ( int ) ) ) ;
ipodGen - > insertItem (
itdb_info_get_ipod_generation_string ( info - > ipod_generation ) ,
gen ) ;
}
if ( info - > capacity > 0.f )
gen - > insertItem ( i18n ( " %1 GB %2 (x%3) " )
. arg ( TQString : : number ( info - > capacity ) ,
itdb_info_get_ipod_model_name_string ( info - > ipod_model ) ,
info - > model_number ) ,
index ) ;
else
gen - > insertItem ( i18n ( " %1 (x%2) " )
. arg ( itdb_info_get_ipod_model_name_string ( info - > ipod_model ) ,
info - > model_number ) ,
index ) ;
}
+ + info ;
+ + index ;
}
+ + generation ;
}
while ( infoFound ) ;
}
void
IpodMediaDevice : : slotIpodAction ( int id )
{
switch ( id )
{
case CHECK_INTEGRITY :
checkIntegrity ( ) ;
break ;
case UPDATE_ARTWORK :
updateArtwork ( ) ;
break ;
default :
if ( const Itdb_IpodInfo * table = itdb_info_get_ipod_info_table ( ) )
{
int index = id - SET_IPOD_MODEL ;
if ( m_itdb & & m_itdb - > device )
{
gchar model [ PATH_MAX ] ;
g_snprintf ( model , PATH_MAX , " x%s " , table [ index ] . model_number ) ;
itdb_device_set_sysinfo ( m_itdb - > device , " ModelNumStr " , model ) ;
detectModel ( ) ;
if ( m_isIPhone )
{
m_autoConnect = false ;
setConfigBool ( " AutoConnect " , m_autoConnect ) ;
}
// try to make sure that the Device directory exists
TQDir dir ;
TQString realPath ;
if ( ! pathExists ( itunesDir ( ) , & realPath ) )
{
dir . setPath ( realPath ) ;
dir . mkdir ( dir . absPath ( ) ) ;
}
if ( ! pathExists ( itunesDir ( " Device " ) , & realPath ) )
{
dir . setPath ( realPath ) ;
dir . mkdir ( dir . absPath ( ) ) ;
}
GError * err = 0 ;
gboolean success = itdb_device_write_sysinfo ( m_itdb - > device , & err ) ;
debug ( ) < < " success writing sysinfo to ipod? (return value " < < success < < " ) " < < endl ;
if ( ! success & & err )
{
g_error_free ( err ) ;
//FIXME: update i18n files for next message
Amarok : : StatusBar : : instance ( ) - > longMessage (
i18n ( " Could not write SysInfo file to iPod (check the permissions of the file \" %1 \" on your iPod) " ) . arg ( itunesDir ( " Device:SysInfo " ) ) ) ;
//FIXME: update i18n files for next message
Amarok : : StatusBar : : instance ( ) - > shortMessage (
i18n ( " Unable to set iPod model to %1 GB %2 (x%3) " )
. arg ( TQString : : number ( table [ index ] . capacity ) ,
itdb_info_get_ipod_model_name_string ( table [ index ] . ipod_model ) ,
table [ index ] . model_number ) ) ;
}
else
{
Amarok : : StatusBar : : instance ( ) - > shortMessage (
i18n ( " Setting iPod model to %1 GB %2 (x%3) " )
. arg ( TQString : : number ( table [ index ] . capacity ) ,
itdb_info_get_ipod_model_name_string ( table [ index ] . ipod_model ) ,
table [ index ] . model_number ) ) ;
}
MediaBrowser : : instance ( ) - > updateDevices ( ) ;
}
}
break ;
}
}
void
IpodMediaDevice : : init ( MediaBrowser * parent )
{
MediaDevice : : init ( parent ) ;
}
IpodMediaDevice : : ~ IpodMediaDevice ( )
{
if ( m_itdb )
itdb_free ( m_itdb ) ;
m_files . clear ( ) ;
}
bool
IpodMediaDevice : : isConnected ( )
{
return ( m_itdb ! = 0 ) ;
}
MediaItem *
IpodMediaDevice : : insertTrackIntoDB ( const TQString & pathname ,
const MetaBundle & metaBundle , const MetaBundle & propertiesBundle ,
const PodcastInfo * podcastInfo )
{
return updateTrackInDB ( 0 , pathname , metaBundle , propertiesBundle , podcastInfo ) ;
}
MediaItem *
IpodMediaDevice : : updateTrackInDB ( IpodMediaItem * item , const TQString & pathname ,
const MetaBundle & metaBundle , const MetaBundle & propertiesBundle ,
const PodcastInfo * podcastInfo )
{
if ( ! m_itdb )
return 0 ;
Itdb_Track * track = 0 ;
if ( item )
track = item - > m_track ;
if ( ! track )
track = itdb_track_new ( ) ;
if ( ! track )
{
delete item ;
return 0 ;
}
TQString type = TQString ( pathname . section ( ' . ' , - 1 ) ) . lower ( ) ;
track - > ipod_path = g_strdup ( ipodPath ( pathname ) . latin1 ( ) ) ;
debug ( ) < < " on iPod: " < < track - > ipod_path < < " , podcast= " < < podcastInfo < < endl ;
if ( metaBundle . isValidMedia ( ) | | ! metaBundle . title ( ) . isEmpty ( ) )
track - > title = g_strdup ( metaBundle . title ( ) . utf8 ( ) ) ;
else
track - > title = g_strdup ( metaBundle . url ( ) . filename ( ) . utf8 ( ) ) ;
track - > album = g_strdup ( metaBundle . album ( ) - > utf8 ( ) ) ;
track - > artist = g_strdup ( metaBundle . artist ( ) - > utf8 ( ) ) ;
track - > genre = g_strdup ( metaBundle . genre ( ) - > utf8 ( ) ) ;
track - > mediatype = ITDB_MEDIATYPE_AUDIO ;
bool audiobook = false ;
if ( type = = " wav " )
{
track - > filetype = g_strdup ( " wav " ) ;
}
else if ( type = = " mp3 " | | type = = " mpeg " )
{
track - > filetype = g_strdup ( " mpeg " ) ;
}
else if ( type = = " aac " | | type = = " m4a " | | ( ! m_supportsVideo & & type = = " mp4 " ) )
{
track - > filetype = g_strdup ( " mp4 " ) ;
}
else if ( type = = " m4b " )
{
audiobook = true ;
track - > filetype = g_strdup ( " mp4 " ) ;
}
else if ( type = = " m4v " | | type = = " mp4v " | | type = = " mov " | | type = = " mpg " | | type = = " mp4 " )
{
track - > filetype = g_strdup ( " m4v video " ) ;
track - > movie_flag = 0x01 ; // for videos
track - > mediatype = ITDB_MEDIATYPE_MOVIE ;
}
else if ( type = = " aa " )
{
audiobook = true ;
track - > filetype = g_strdup ( " audible " ) ;
TagLib : : Audible : : File f ( TQFile : : encodeName ( propertiesBundle . url ( ) . path ( ) ) ) ;
TagLib : : Audible : : Tag * t = f . getAudibleTag ( ) ;
if ( t )
track - > drm_userid = t - > userID ( ) ;
// libgpod also tries to set those, but this won't work
track - > unk126 = 0x01 ;
track - > unk144 = 0x0029 ;
}
else
{
track - > filetype = g_strdup ( type . utf8 ( ) ) ;
}
TQString genre = metaBundle . genre ( ) ;
if ( genre . startsWith ( " audiobook " , false ) )
audiobook = true ;
if ( audiobook )
{
track - > remember_playback_position | = 0x01 ;
track - > skip_when_shuffling | = 0x01 ;
track - > mediatype = ITDB_MEDIATYPE_AUDIOBOOK ;
}
track - > composer = g_strdup ( metaBundle . composer ( ) - > utf8 ( ) ) ;
track - > comment = g_strdup ( metaBundle . comment ( ) - > utf8 ( ) ) ;
track - > track_nr = metaBundle . track ( ) ;
track - > cd_nr = metaBundle . discNumber ( ) ;
track - > BPM = static_cast < int > ( metaBundle . bpm ( ) ) ;
track - > year = metaBundle . year ( ) ;
track - > size = propertiesBundle . filesize ( ) ;
if ( track - > size = = 0 )
{
debug ( ) < < " filesize is zero for " < < track - > ipod_path < < " , expect strange problems with your ipod " < < endl ;
}
track - > bitrate = propertiesBundle . bitrate ( ) ;
track - > samplerate = propertiesBundle . sampleRate ( ) ;
track - > tracklen = propertiesBundle . length ( ) * 1000 ;
//Get the createdate from database
QueryBuilder qb ;
qb . addReturnValue ( QueryBuilder : : tabSong , QueryBuilder : : valCreateDate ) ;
qb . addMatch ( QueryBuilder : : tabSong , QueryBuilder : : valURL , metaBundle . url ( ) . path ( ) ) ;
TQStringList values = qb . run ( ) ;
//Add to track info if present
if ( values . count ( ) ) {
uint createdate = values . first ( ) . toUInt ( ) ;
track - > time_added = itdb_time_host_to_mac ( createdate ) ;
track - > time_modified = itdb_time_host_to_mac ( createdate ) ;
}
if ( podcastInfo )
{
track - > skip_when_shuffling = 0x01 ; // skip when shuffling
track - > remember_playback_position = 0x01 ; // remember playback position
// FIXME: track->unk176 = 0x00020000; // for podcasts
track - > mark_unplayed = podcastInfo - > listened ? 0x01 : 0x02 ;
track - > mediatype =
track - > mediatype = = ITDB_MEDIATYPE_MOVIE
? ITDB_MEDIATYPE_PODCAST | ITDB_MEDIATYPE_MOVIE
: ITDB_MEDIATYPE_PODCAST ;
track - > flag4 = 0x01 ; // also show description on iPod
TQString plaindesc = podcastInfo - > description ;
plaindesc . replace ( TQRegExp ( " <[^>]*> " ) , " " ) ;
track - > description = g_strdup ( plaindesc . utf8 ( ) ) ;
track - > subtitle = g_strdup ( plaindesc . utf8 ( ) ) ;
track - > podcasturl = g_strdup ( podcastInfo - > url . utf8 ( ) ) ;
track - > podcastrss = g_strdup ( podcastInfo - > rss . utf8 ( ) ) ;
//track->category = g_strdup( i18n( "Unknown" ) );
track - > time_released = itdb_time_host_to_mac ( podcastInfo - > date . toTime_t ( ) ) ;
//track->compilation = 0x01; // this should have made the ipod play a sequence of podcasts
}
else
{
if ( metaBundle . compilation ( ) = = MetaBundle : : CompilationYes )
{
track - > compilation = 0x01 ;
}
else
{
track - > compilation = 0x00 ;
}
}
m_dbChanged = true ;
if ( m_supportsArtwork )
{
TQString image ;
if ( metaBundle . podcastBundle ( ) )
{
PodcastChannelBundle pcb ;
if ( CollectionDB : : instance ( ) - > getPodcastChannelBundle ( metaBundle . podcastBundle ( ) - > parent ( ) , & pcb ) )
image = CollectionDB : : instance ( ) - > podcastImage ( pcb . imageURL ( ) . url ( ) , 0 ) ;
}
if ( image . isEmpty ( ) )
image = CollectionDB : : instance ( ) - > albumImage ( metaBundle . artist ( ) , metaBundle . album ( ) , false , 0 ) ;
if ( ! image . endsWith ( " @nocover.png " ) )
{
debug ( ) < < " adding image " < < image < < " to " < < metaBundle . artist ( ) < < " : " < < metaBundle . album ( ) < < endl ;
itdb_track_set_thumbnails ( track , g_strdup ( TQFile : : encodeName ( image ) ) ) ;
}
}
if ( item )
{
MediaItem * parent = dynamic_cast < MediaItem * > ( item - > parent ( ) ) ;
if ( parent )
{
parent - > takeItem ( item ) ;
if ( parent - > childCount ( ) = = 0 & & ! isSpecialItem ( parent ) )
{
MediaItem * pp = dynamic_cast < MediaItem * > ( parent - > parent ( ) ) ;
delete parent ;
if ( pp & & pp - > childCount ( ) = = 0 & & ! isSpecialItem ( pp ) )
delete pp ;
}
}
}
else
{
itdb_track_add ( m_itdb , track , - 1 ) ;
if ( podcastInfo )
{
Itdb_Playlist * podcasts = itdb_playlist_podcasts ( m_itdb ) ;
if ( ! podcasts )
{
podcasts = itdb_playlist_new ( " Podcasts " , false ) ;
itdb_playlist_add ( m_itdb , podcasts , - 1 ) ;
itdb_playlist_set_podcasts ( podcasts ) ;
addPlaylistToView ( podcasts ) ;
}
itdb_playlist_add_track ( podcasts , track , - 1 ) ;
}
else
{
// gtkpod 0.94 does not like if not all songs in the db are on the master playlist
// but we try anyway
Itdb_Playlist * mpl = itdb_playlist_mpl ( m_itdb ) ;
if ( ! mpl )
{
mpl = itdb_playlist_new ( " iPod " , false ) ;
itdb_playlist_add ( m_itdb , mpl , - 1 ) ;
itdb_playlist_set_mpl ( mpl ) ;
addPlaylistToView ( mpl ) ;
}
itdb_playlist_add_track ( mpl , track , - 1 ) ;
}
}
return addTrackToView ( track , item ) ;
}
MediaItem *
IpodMediaDevice : : copyTrackToDevice ( const MetaBundle & bundle )
{
KURL url = determineURLOnDevice ( bundle ) ;
// check if path exists and make it if needed
TQFileInfo finfo ( url . path ( ) ) ;
TQDir dir = finfo . dir ( ) ;
while ( ! dir . exists ( ) )
{
TQString path = dir . absPath ( ) ;
TQDir parentdir ;
TQDir create ;
do
{
create . setPath ( path ) ;
path = path . section ( " / " , 0 , path . contains ( ' / ' ) - 1 ) ;
parentdir . setPath ( path ) ;
}
while ( ! path . isEmpty ( ) & & ! ( path = = mountPoint ( ) ) & & ! parentdir . exists ( ) ) ;
debug ( ) < < " trying to create \" " < < path < < " \" " < < endl ;
if ( ! create . mkdir ( create . absPath ( ) ) )
{
break ;
}
}
if ( ! dir . exists ( ) )
{
Amarok : : StatusBar : : instance ( ) - > longMessage (
i18n ( " Media Device: Creating directory for file %1 failed " ) . arg ( url . path ( ) ) ,
KDE : : StatusBar : : Error ) ;
return NULL ;
}
if ( ! kioCopyTrack ( bundle . url ( ) , url ) )
{
return NULL ;
}
PodcastInfo * podcastInfo = 0 ;
if ( bundle . podcastBundle ( ) )
{
PodcastEpisodeBundle * peb = bundle . podcastBundle ( ) ;
podcastInfo = new PodcastInfo ;
podcastInfo - > url = peb - > url ( ) . url ( ) ;
podcastInfo - > description = peb - > description ( ) ;
podcastInfo - > author = peb - > author ( ) ;
podcastInfo - > rss = peb - > parent ( ) . url ( ) ;
podcastInfo - > date = peb - > dateTime ( ) ;
podcastInfo - > listened = ! peb - > isNew ( ) ;
}
MetaBundle propertiesBundle ( url ) ;
MediaItem * ret = insertTrackIntoDB ( url . path ( ) , bundle , propertiesBundle , podcastInfo ) ;
delete podcastInfo ;
return ret ;
}
MediaItem *
IpodMediaDevice : : tagsChanged ( MediaItem * item , const MetaBundle & bundle )
{
return updateTrackInDB ( dynamic_cast < IpodMediaItem * > ( item ) , item - > url ( ) . path ( ) , bundle , bundle , NULL ) ;
}
void
IpodMediaDevice : : synchronizeDevice ( )
{
# if 1
debug ( ) < < " Syncing iPod! " < < endl ;
Amarok : : StatusBar : : instance ( ) - > newProgressOperation ( this )
. setDescription ( i18n ( " Flushing iPod filesystem transfer cache " ) )
. setTotalSteps ( 1 ) ;
writeITunesDB ( ) ;
Amarok : : StatusBar : : instance ( ) - > endProgressOperation ( this ) ;
# else
m_dbChanged = true ;
debug ( ) < < " Deferring sync of iPod! " < < endl ;
# endif
}
MediaItem *
IpodMediaDevice : : trackExists ( const MetaBundle & bundle )
{
return getTrack ( bundle . artist ( ) ,
bundle . album ( ) ,
bundle . title ( ) ,
bundle . discNumber ( ) ,
bundle . track ( ) ,
bundle . podcastBundle ( ) ) ;
}
MediaItem *
IpodMediaDevice : : newPlaylist ( const TQString & name , MediaItem * parent , TQPtrList < MediaItem > items )
{
m_dbChanged = true ;
IpodMediaItem * item = new IpodMediaItem ( parent , this ) ;
item - > setType ( MediaItem : : PLAYLIST ) ;
item - > setText ( 0 , name ) ;
addToPlaylist ( item , 0 , items ) ;
return item ;
}
void
IpodMediaDevice : : addToPlaylist ( MediaItem * mlist , MediaItem * after , TQPtrList < MediaItem > items )
{
IpodMediaItem * list = dynamic_cast < IpodMediaItem * > ( mlist ) ;
if ( ! list )
return ;
m_dbChanged = true ;
if ( list - > m_playlist )
{
itdb_playlist_remove ( list - > m_playlist ) ;
list - > m_playlist = 0 ;
}
int order ;
IpodMediaItem * it ;
if ( after )
{
order = after - > m_order + 1 ;
it = dynamic_cast < IpodMediaItem * > ( after - > nextSibling ( ) ) ;
}
else
{
order = 0 ;
it = dynamic_cast < IpodMediaItem * > ( list - > firstChild ( ) ) ;
}
for ( ; it ; it = dynamic_cast < IpodMediaItem * > ( it - > nextSibling ( ) ) )
{
it - > m_order + = items . count ( ) ;
}
for ( IpodMediaItem * it = dynamic_cast < IpodMediaItem * > ( items . first ( ) ) ;
it ;
it = dynamic_cast < IpodMediaItem * > ( items . next ( ) ) )
{
if ( ! it - > m_track )
continue ;
IpodMediaItem * add ;
if ( it - > parent ( ) = = list )
{
add = it ;
if ( after )
{
it - > moveItem ( after ) ;
}
else
{
list - > takeItem ( it ) ;
list - > insertItem ( it ) ;
}
}
else
{
if ( after )
{
add = new IpodMediaItem ( list , after , this ) ;
}
else
{
add = new IpodMediaItem ( list , this ) ;
}
}
after = add ;
add - > setType ( MediaItem : : PLAYLISTITEM ) ;
add - > m_track = it - > m_track ;
add - > bundleFromTrack ( add - > m_track , realPath ( add - > m_track - > ipod_path ) ) ;
add - > setText ( 0 , TQString : : fromUtf8 ( it - > m_track - > artist ) + " - " + TQString : : fromUtf8 ( it - > m_track - > title ) ) ;
add - > m_order = order ;
order + + ;
}
// make numbering consecutive
int i = 0 ;
for ( IpodMediaItem * it = dynamic_cast < IpodMediaItem * > ( list - > firstChild ( ) ) ;
it ;
it = dynamic_cast < IpodMediaItem * > ( it - > nextSibling ( ) ) )
{
it - > m_order = i ;
i + + ;
}
playlistFromItem ( list ) ;
}
int
IpodMediaDevice : : deleteItemFromDevice ( MediaItem * mediaitem , int flags )
{
IpodMediaItem * item = dynamic_cast < IpodMediaItem * > ( mediaitem ) ;
if ( ! item )
return - 1 ;
if ( isCanceled ( ) )
return 0 ;
if ( ! item - > isVisible ( ) )
return 0 ;
int count = 0 ;
switch ( item - > type ( ) )
{
case MediaItem : : PLAYLISTITEM :
if ( ! ( flags & DeleteTrack ) )
{
// FIXME possibly wrong instance of track is removed
itdb_playlist_remove_track ( item - > m_playlist , item - > m_track ) ;
delete item ;
m_dbChanged = true ;
break ;
}
// else fall through
case MediaItem : : STALE :
case MediaItem : : TRACK :
case MediaItem : : INVISIBLE :
case MediaItem : : PODCASTITEM :
if ( ! ( flags & OnlyPlayed ) | | item - > played ( ) > 0 )
{
bool stale = item - > type ( ) = = MediaItem : : STALE ;
Itdb_Track * track = item - > m_track ;
delete item ;
// delete from playlists
for ( IpodMediaItem * it = static_cast < IpodMediaItem * > ( m_playlistItem ) - > findTrack ( track ) ;
it ;
it = static_cast < IpodMediaItem * > ( m_playlistItem ) - > findTrack ( track ) )
{
delete it ;
}
// delete all other occurrences
for ( IpodMediaItem * it = getTrack ( track ) ;
it ;
it = getTrack ( track ) )
{
delete it ;
}
if ( ! stale )
{
// delete file
KURL url ;
url . setPath ( realPath ( track - > ipod_path ) ) ;
deleteFile ( url ) ;
count + + ;
}
// remove from database
if ( ! removeDBTrack ( track ) )
count = - 1 ;
}
break ;
case MediaItem : : ORPHANED :
deleteFile ( item - > url ( ) ) ;
delete item ;
if ( count > = 0 )
count + + ;
break ;
case MediaItem : : PLAYLISTSROOT :
case MediaItem : : PODCASTSROOT :
case MediaItem : : INVISIBLEROOT :
case MediaItem : : STALEROOT :
case MediaItem : : ORPHANEDROOT :
case MediaItem : : ARTIST :
case MediaItem : : ALBUM :
case MediaItem : : PODCASTCHANNEL :
case MediaItem : : PLAYLIST :
// just recurse
{
IpodMediaItem * next = 0 ;
for ( IpodMediaItem * it = dynamic_cast < IpodMediaItem * > ( item - > firstChild ( ) ) ;
it ;
it = next )
{
if ( isCanceled ( ) )
break ;
next = dynamic_cast < IpodMediaItem * > ( it - > nextSibling ( ) ) ;
int ret = deleteItemFromDevice ( it , flags ) ;
if ( ret > = 0 & & count > = 0 )
count + = ret ;
else
count = - 1 ;
}
}
if ( item - > type ( ) = = MediaItem : : PLAYLIST & & ! isCanceled ( ) )
{
m_dbChanged = true ;
itdb_playlist_remove ( item - > m_playlist ) ;
}
if ( item - > type ( ) ! = MediaItem : : PLAYLISTSROOT
& & item - > type ( ) ! = MediaItem : : PODCASTSROOT
& & item - > type ( ) ! = MediaItem : : INVISIBLEROOT
& & item - > type ( ) ! = MediaItem : : STALEROOT
& & item - > type ( ) ! = MediaItem : : ORPHANEDROOT )
{
if ( ! ( flags & OnlyPlayed ) | | item - > played ( ) > 0 | | item - > childCount ( ) = = 0 )
{
if ( item - > childCount ( ) > 0 )
debug ( ) < < " recursive deletion should have removed all children from " < < item < < " ( " < < item - > text ( 0 ) < < " ) " < < endl ;
else
delete item ;
}
}
break ;
case MediaItem : : DIRECTORY :
case MediaItem : : UNKNOWN :
// this should not happen
count = - 1 ;
break ;
}
updateRootItems ( ) ;
return count ;
}
bool
IpodMediaDevice : : createLockFile ( bool silent )
{
TQString lockFilePath ;
pathExists ( itunesDir ( " iTunes:iTunesLock " ) , & lockFilePath ) ;
m_lockFile = new TQFile ( lockFilePath ) ;
TQString msg ;
bool ok = true ;
if ( m_lockFile - > exists ( ) )
{
ok = false ;
msg = i18n ( " Media Device: iPod mounted at %1 already locked. " ) . arg ( mountPoint ( ) ) ;
msg + = i18n ( " If you are sure that this is an error, then remove the file %1 and try again. " )
. arg ( lockFilePath ) ;
if ( ! silent )
{
if ( KMessageBox : : warningContinueCancel ( m_parent , msg , i18n ( " Remove iTunes Lock File? " ) ,
KGuiItem ( i18n ( " &Remove " ) , " editdelete " ) , TQString ( ) , KMessageBox : : Dangerous )
= = KMessageBox : : Continue )
{
msg = i18n ( " Media Device: removing lockfile %1 failed: %2. " )
. arg ( lockFilePath , m_lockFile - > errorString ( ) ) ;
ok = m_lockFile - > remove ( ) ;
}
else
{
msg = " " ;
}
}
}
if ( ok & & ! m_lockFile - > open ( IO_WriteOnly ) )
{
ok = false ;
msg = i18n ( " Media Device: failed to create lockfile on iPod mounted at %1: %2 " )
. arg ( mountPoint ( ) , m_lockFile - > errorString ( ) ) ;
}
if ( ok )
return true ;
delete m_lockFile ;
m_lockFile = 0 ;
if ( ! msg . isEmpty ( ) )
Amarok : : StatusBar : : instance ( ) - > longMessage ( msg , KDE : : StatusBar : : Sorry ) ;
return false ;
}
bool
IpodMediaDevice : : initializeIpod ( )
{
TQDir dir ( mountPoint ( ) ) ;
if ( ! dir . exists ( ) )
{
Amarok : : StatusBar : : instance ( ) - > longMessage (
i18n ( " Media device: Mount point %1 does not exist " ) . arg ( mountPoint ( ) ) ,
KDE : : StatusBar : : Error ) ;
return false ;
}
debug ( ) < < " initializing iPod mounted at " < < mountPoint ( ) < < endl ;
// initialize iPod
m_itdb = itdb_new ( ) ;
if ( m_itdb = = 0 )
return false ;
// in order to get directories right
detectModel ( ) ;
itdb_set_mountpoint ( m_itdb , TQFile : : encodeName ( mountPoint ( ) ) ) ;
Itdb_Playlist * mpl = itdb_playlist_new ( " iPod " , false ) ;
itdb_playlist_set_mpl ( mpl ) ;
Itdb_Playlist * podcasts = itdb_playlist_new ( " Podcasts " , false ) ;
itdb_playlist_set_podcasts ( podcasts ) ;
itdb_playlist_add ( m_itdb , podcasts , - 1 ) ;
itdb_playlist_add ( m_itdb , mpl , 0 ) ;
TQString realPath ;
if ( ! pathExists ( itunesDir ( ) , & realPath ) )
{
dir . setPath ( realPath ) ;
dir . mkdir ( dir . absPath ( ) ) ;
}
if ( ! dir . exists ( ) )
return false ;
if ( ! pathExists ( itunesDir ( " Music " ) , & realPath ) )
{
dir . setPath ( realPath ) ;
dir . mkdir ( dir . absPath ( ) ) ;
}
if ( ! dir . exists ( ) )
return false ;
if ( ! pathExists ( itunesDir ( " iTunes " ) , & realPath ) )
{
dir . setPath ( realPath ) ;
dir . mkdir ( dir . absPath ( ) ) ;
}
if ( ! dir . exists ( ) )
return false ;
if ( ! writeITunesDB ( false ) )
return false ;
Amarok : : StatusBar : : instance ( ) - > longMessage (
i18n ( " Media Device: Initialized iPod mounted at %1 " ) . arg ( mountPoint ( ) ) ,
KDE : : StatusBar : : Information ) ;
return true ;
}
bool
IpodMediaDevice : : openDevice ( bool silent )
{
m_isShuffle = false ;
m_isMobile = false ;
m_isIPhone = false ;
m_supportsArtwork = false ;
m_supportsVideo = false ;
m_needsFirewireGuid = false ;
m_rockboxFirmware = false ;
m_dbChanged = false ;
m_files . clear ( ) ;
if ( m_itdb )
{
Amarok : : StatusBar : : instance ( ) - > longMessage (
i18n ( " Media Device: iPod at %1 already opened " ) . arg ( mountPoint ( ) ) ,
KDE : : StatusBar : : Sorry ) ;
return false ;
}
// try to find a mounted ipod
bool ipodFound = false ;
bool canInitialize = false ;
KMountPoint : : List currentmountpoints = KMountPoint : : currentMountPoints ( ) ;
for ( KMountPoint : : List : : Iterator mountiter = currentmountpoints . begin ( ) ;
mountiter ! = currentmountpoints . end ( ) ;
+ + mountiter )
{
canInitialize = false ;
TQString devicenode = ( * mountiter ) - > mountedFrom ( ) ;
TQString mountpoint = ( * mountiter ) - > mountPoint ( ) ;
if ( mountpoint . startsWith ( " /proc " ) | |
mountpoint . startsWith ( " /sys " ) | |
mountpoint . startsWith ( " /dev " ) | |
mountpoint . startsWith ( " /boot " ) )
continue ;
if ( ! mountPoint ( ) . isEmpty ( ) )
{
if ( mountpoint ! = mountPoint ( ) )
continue ;
canInitialize = true ;
}
else if ( ! deviceNode ( ) . isEmpty ( ) )
{
if ( devicenode ! = deviceNode ( ) )
continue ;
canInitialize = true ;
}
GError * err = 0 ;
m_itdb = itdb_parse ( TQFile : : encodeName ( mountpoint ) , & err ) ;
if ( err )
{
g_error_free ( err ) ;
if ( m_itdb )
{
itdb_free ( m_itdb ) ;
m_itdb = 0 ;
}
if ( ! canInitialize )
continue ;
}
if ( mountPoint ( ) . isEmpty ( ) )
m_medium . setMountPoint ( mountpoint ) ;
ipodFound = true ;
break ;
}
if ( ! ipodFound & & ! canInitialize )
{
if ( ! silent )
{
Amarok : : StatusBar : : instance ( ) - > longMessage (
i18n ( " Media Device: No mounted iPod found " ) ,
KDE : : StatusBar : : Sorry ) ;
}
return false ;
}
if ( ! m_itdb & & canInitialize )
{
TQString msg = i18n ( " Media Device: could not find iTunesDB on device mounted at %1. "
" Should I try to initialize your iPod? " ) . arg ( mountPoint ( ) ) ;
if ( ! silent
& & KMessageBox : : warningContinueCancel ( m_parent , msg , i18n ( " Initialize iPod? " ) ,
KGuiItem ( i18n ( " &Initialize " ) , " new " ) ) = = KMessageBox : : Continue )
{
if ( ! initializeIpod ( ) )
{
if ( m_itdb )
{
itdb_free ( m_itdb ) ;
m_itdb = 0 ;
}
Amarok : : StatusBar : : instance ( ) - > longMessage (
i18n ( " Media Device: Failed to initialize iPod mounted at %1 " ) . arg ( mountPoint ( ) ) ,
KDE : : StatusBar : : Sorry ) ;
return false ;
}
}
else
return false ;
}
detectModel ( ) ;
if ( ! createLockFile ( silent ) )
{
if ( m_itdb )
{
itdb_free ( m_itdb ) ;
m_itdb = 0 ;
}
return false ;
}
for ( int i = 0 ; i < itdb_musicdirs_number ( m_itdb ) ; i + + )
{
TQString real ;
TQString ipod ;
ipod . sprintf ( itunesDir ( " Music:f%02d " ) . latin1 ( ) , i ) ;
if ( ! pathExists ( ipod , & real ) )
{
TQDir dir ( real ) ;
dir . mkdir ( real ) ;
dir . setPath ( real ) ;
if ( ! dir . exists ( ) )
{
debug ( ) < < " failed to create hash dir " < < real < < endl ;
Amarok : : StatusBar : : instance ( ) - > longMessage (
i18n ( " Media device: Failed to create directory %1 " ) . arg ( real ) ,
KDE : : StatusBar : : Error ) ;
return false ;
}
}
}
if ( ! silent )
kapp - > processEvents ( 100 ) ;
initView ( ) ;
GList * cur = m_itdb - > playlists ;
for ( ; cur ; cur = cur - > next )
{
Itdb_Playlist * playlist = ( Itdb_Playlist * ) cur - > data ;
addPlaylistToView ( playlist ) ;
}
if ( ! silent )
kapp - > processEvents ( 100 ) ;
for ( cur = m_itdb - > tracks ; cur ; cur = cur - > next )
{
Itdb_Track * track = ( Itdb_Track * ) cur - > data ;
addTrackToView ( track , 0 /*parent*/ , false /*checkintegrity*/ , true /*batchmode*/ ) ;
}
if ( ! silent )
kapp - > processEvents ( 100 ) ;
updateRootItems ( ) ;
m_customAction - > setEnabled ( true ) ;
m_dbChanged = true ; // write at least once for synchronising new stats
return true ;
}
void
IpodMediaDevice : : detectModel ( )
{
// set some sane default values
m_isShuffle = false ;
m_supportsArtwork = true ;
m_supportsVideo = false ;
m_isIPhone = false ;
m_needsFirewireGuid = false ;
m_rockboxFirmware = false ;
// needs recent libgpod-0.3.3 from cvs
bool guess = false ;
if ( m_itdb & & m_itdb - > device )
{
const Itdb_IpodInfo * ipodInfo = itdb_device_get_ipod_info ( m_itdb - > device ) ;
const gchar * modelString = 0 ;
m_supportsArtwork = itdb_device_supports_artwork ( m_itdb - > device ) ;
if ( ipodInfo )
{
modelString = itdb_info_get_ipod_model_name_string ( ipodInfo - > ipod_model ) ;
switch ( ipodInfo - > ipod_model )
{
case ITDB_IPOD_MODEL_SHUFFLE :
# ifdef HAVE_LIBGPOD_060
case ITDB_IPOD_MODEL_SHUFFLE_SILVER :
case ITDB_IPOD_MODEL_SHUFFLE_PINK :
case ITDB_IPOD_MODEL_SHUFFLE_BLUE :
case ITDB_IPOD_MODEL_SHUFFLE_GREEN :
case ITDB_IPOD_MODEL_SHUFFLE_ORANGE :
case ITDB_IPOD_MODEL_SHUFFLE_PURPLE :
# endif
m_isShuffle = true ;
break ;
# ifdef HAVE_LIBGPOD_060
case ITDB_IPOD_MODEL_IPHONE_1 :
case ITDB_IPOD_GENERATION_TOUCH_1 :
m_isIPhone = true ;
debug ( ) < < " detected iPhone/iPod Touch " < < endl ;
break ;
case ITDB_IPOD_MODEL_CLASSIC_SILVER :
case ITDB_IPOD_MODEL_CLASSIC_BLACK :
# endif
case ITDB_IPOD_MODEL_VIDEO_WHITE :
case ITDB_IPOD_MODEL_VIDEO_BLACK :
case ITDB_IPOD_MODEL_VIDEO_U2 :
m_supportsVideo = true ;
debug ( ) < < " detected video-capable iPod " < < endl ;
break ;
case ITDB_IPOD_MODEL_MOBILE_1 :
m_isMobile = true ;
m_supportsArtwork = true ;
debug ( ) < < " detected iTunes phone " < < endl ;
break ;
case ITDB_IPOD_MODEL_INVALID :
case ITDB_IPOD_MODEL_UNKNOWN :
modelString = 0 ;
guess = true ;
break ;
default :
break ;
}
# ifdef HAVE_LIBGPOD_060
switch ( ipodInfo - > ipod_generation )
{
case ITDB_IPOD_GENERATION_CLASSIC_1 :
case ITDB_IPOD_GENERATION_NANO_3 :
case ITDB_IPOD_GENERATION_TOUCH_1 :
m_needsFirewireGuid = true ;
m_supportsVideo = true ;
break ;
case ITDB_IPOD_GENERATION_VIDEO_1 :
case ITDB_IPOD_GENERATION_VIDEO_2 :
m_supportsVideo = true ;
break ;
case ITDB_IPOD_GENERATION_SHUFFLE_1 :
case ITDB_IPOD_GENERATION_SHUFFLE_2 :
case ITDB_IPOD_GENERATION_SHUFFLE_3 :
m_isShuffle = true ;
break ;
default :
break ;
}
# endif
}
if ( modelString )
m_name = TQString ( " iPod %1 " ) . arg ( TQString : : fromUtf8 ( modelString ) ) ;
if ( m_needsFirewireGuid )
{
gchar * fwid = itdb_device_get_sysinfo ( m_itdb - > device , " FirewireGuid " ) ;
if ( ! fwid )
{
Amarok : : StatusBar : : instance ( ) - > longMessage (
i18n ( " Your iPod's Firewire GUID is required for correctly updating its music database, but it is not known. See %1 for more information. " ) . arg ( " http://amarok.kde.org/wiki/Media_Device:IPod " ) ) ;
}
else
g_free ( fwid ) ;
}
}
else
{
debug ( ) < < " iPod type detection failed, no video support " < < endl ;
Amarok : : StatusBar : : instance ( ) - > longMessage (
i18n ( " iPod type detection failed: no support for iPod Shuffle, for artwork or video " ) ) ;
guess = true ;
}
if ( guess )
{
if ( pathExists ( " :iTunes:iTunes_Control " ) )
{
debug ( ) < < " iTunes/iTunes_Control found - assuming itunes phone " < < endl ;
m_isMobile = true ;
}
else if ( pathExists ( " :iTunes_Control " ) )
{
debug ( ) < < " iTunes_Control found - assuming iPhone/iPod Touch " < < endl ;
m_isIPhone = true ;
}
}
if ( m_isIPhone )
{
m_supportsVideo = true ;
m_supportsArtwork = true ;
}
if ( pathExists ( " :.rockbox " ) )
{
debug ( ) < < " RockBox firmware detected " < < endl ;
m_rockboxFirmware = true ;
}
}
void
IpodMediaDevice : : initView ( )
{
m_view - > clear ( ) ;
m_playlistItem = new IpodMediaItem ( m_view , this ) ;
m_playlistItem - > setText ( 0 , i18n ( " Playlists " ) ) ;
m_playlistItem - > m_order = - 6 ;
m_playlistItem - > setType ( MediaItem : : PLAYLISTSROOT ) ;
m_podcastItem = new IpodMediaItem ( m_view , this ) ;
m_podcastItem - > setText ( 0 , i18n ( " Podcasts " ) ) ;
m_podcastItem - > m_order = - 5 ;
m_podcastItem - > setType ( MediaItem : : PODCASTSROOT ) ;
m_invisibleItem = new IpodMediaItem ( m_view , this ) ;
m_invisibleItem - > setText ( 0 , i18n ( " Invisible " ) ) ;
m_invisibleItem - > m_order = - 4 ;
m_invisibleItem - > setType ( MediaItem : : INVISIBLEROOT ) ;
m_staleItem = new IpodMediaItem ( m_view , this ) ;
m_staleItem - > setText ( 0 , i18n ( " Stale " ) ) ;
m_staleItem - > m_order = - 3 ;
m_staleItem - > setType ( MediaItem : : STALEROOT ) ;
m_orphanedItem = new IpodMediaItem ( m_view , this ) ;
m_orphanedItem - > setText ( 0 , i18n ( " Orphaned " ) ) ;
m_orphanedItem - > m_order = - 2 ;
m_orphanedItem - > setType ( MediaItem : : ORPHANEDROOT ) ;
updateRootItems ( ) ;
}
void
IpodMediaDevice : : updateArtwork ( )
{
if ( ! m_supportsArtwork )
return ;
TQPtrList < MediaItem > items ;
m_view - > getSelectedLeaves ( 0 , & items , false ) ;
int updateCount = 0 ;
for ( TQPtrList < MediaItem > : : iterator it = items . begin ( ) ;
it ! = items . end ( ) ;
it + + )
{
IpodMediaItem * i = dynamic_cast < IpodMediaItem * > ( * it ) ;
if ( ! i | | i - > type ( ) = = MediaItem : : PLAYLISTITEM )
continue ;
const MetaBundle * bundle = i - > bundle ( ) ;
TQString image ;
if ( i - > m_podcastInfo & & ! i - > m_podcastInfo - > rss . isEmpty ( ) )
{
PodcastChannelBundle pcb ;
if ( CollectionDB : : instance ( ) - > getPodcastChannelBundle ( i - > m_podcastInfo - > rss , & pcb ) )
image = CollectionDB : : instance ( ) - > podcastImage ( pcb . imageURL ( ) . url ( ) , 0 ) ;
}
if ( image . isEmpty ( ) )
image = CollectionDB : : instance ( ) - > albumImage ( bundle - > artist ( ) , bundle - > album ( ) , false , 0 ) ;
if ( ! image . endsWith ( " @nocover.png " ) )
{
debug ( ) < < " adding image " < < image < < " to " < < bundle - > artist ( ) < < " : "
< < bundle - > album ( ) < < endl ;
itdb_track_set_thumbnails ( i - > m_track , g_strdup ( TQFile : : encodeName ( image ) ) ) ;
+ + updateCount ;
}
}
Amarok : : StatusBar : : instance ( ) - > shortMessage (
i18n ( " Updated artwork for one track " , " Updated artwork for %n tracks " , updateCount ) ) ;
if ( ! m_dbChanged )
m_dbChanged = updateCount > 0 ;
}
bool
IpodMediaDevice : : checkIntegrity ( )
{
if ( ! m_itdb )
return false ;
initView ( ) ;
GList * cur = m_itdb - > tracks ;
while ( cur )
{
Itdb_Track * track = ( Itdb_Track * ) cur - > data ;
addTrackToView ( track , 0 , true ) ;
cur = cur - > next ;
}
cur = m_itdb - > playlists ;
for ( ; cur ; cur = cur - > next )
{
Itdb_Playlist * playlist = ( Itdb_Playlist * ) cur - > data ;
addPlaylistToView ( playlist ) ;
}
TQString musicpath ;
if ( ! pathExists ( itunesDir ( " Music " ) , & musicpath ) )
return false ;
TQDir dir ( musicpath , TQString ( ) , TQDir : : Unsorted , TQDir : : Dirs ) ;
for ( unsigned i = 0 ; i < dir . count ( ) ; i + + )
{
if ( dir [ i ] = = " . " | | dir [ i ] = = " .. " )
continue ;
TQString hashpath = musicpath + ' / ' + dir [ i ] ;
TQDir hashdir ( hashpath , TQString ( ) , TQDir : : Unsorted , TQDir : : Files ) ;
for ( unsigned j = 0 ; j < hashdir . count ( ) ; j + + )
{
TQString filename = hashpath + ' / ' + hashdir [ j ] ;
TQString ipodPath = itunesDir ( " Music: " ) + dir [ i ] + ' : ' + hashdir [ j ] ;
Itdb_Track * track = m_files [ ipodPath . lower ( ) ] ;
if ( ! track )
{
debug ( ) < < " file: " < < filename < < " is orphaned " < < endl ;
IpodMediaItem * item = new IpodMediaItem ( m_orphanedItem , this ) ;
item - > setType ( MediaItem : : ORPHANED ) ;
KURL url = KURL : : fromPathOrURL ( filename ) ;
MetaBundle * bundle = new MetaBundle ( url ) ;
item - > setBundle ( bundle ) ;
TQString title = bundle - > artist ( ) + " - " + bundle - > title ( ) ;
item - > setText ( 0 , title ) ;
}
}
}
updateRootItems ( ) ;
Amarok : : StatusBar : : instance ( ) - > shortMessage (
i18n ( " Scanning for stale and orphaned tracks finished " ) ) ;
return true ;
}
bool
IpodMediaDevice : : closeDevice ( ) //SLOT
{
m_customAction - > setEnabled ( false ) ;
writeITunesDB ( ) ;
m_view - > clear ( ) ;
m_podcastItem = 0 ;
m_playlistItem = 0 ;
m_orphanedItem = 0 ;
m_staleItem = 0 ;
m_invisibleItem = 0 ;
if ( m_lockFile )
{
m_lockFile - > remove ( ) ;
m_lockFile - > close ( ) ;
delete m_lockFile ;
m_lockFile = 0 ;
}
m_files . clear ( ) ;
itdb_free ( m_itdb ) ;
m_itdb = 0 ;
m_masterPlaylist = 0 ;
m_podcastPlaylist = 0 ;
m_name = " iPod " ;
return true ;
}
void
IpodMediaDevice : : renameItem ( TQListViewItem * i ) // SLOT
{
IpodMediaItem * item = dynamic_cast < IpodMediaItem * > ( i ) ;
if ( ! item )
return ;
if ( ! item - > type ( ) = = MediaItem : : PLAYLIST )
return ;
m_dbChanged = true ;
g_free ( item - > m_playlist - > name ) ;
item - > m_playlist - > name = g_strdup ( item - > text ( 0 ) . utf8 ( ) ) ;
}
void
IpodMediaDevice : : playlistFromItem ( IpodMediaItem * item )
{
if ( ! m_itdb )
return ;
m_dbChanged = true ;
item - > m_playlist = itdb_playlist_new ( item - > text ( 0 ) . utf8 ( ) , false /* dumb playlist */ ) ;
itdb_playlist_add ( m_itdb , item - > m_playlist , - 1 ) ;
for ( IpodMediaItem * it = dynamic_cast < IpodMediaItem * > ( item - > firstChild ( ) ) ;
it ;
it = dynamic_cast < IpodMediaItem * > ( it - > nextSibling ( ) ) )
{
itdb_playlist_add_track ( item - > m_playlist , it - > m_track , - 1 ) ;
it - > m_playlist = item - > m_playlist ;
}
}
IpodMediaItem *
IpodMediaDevice : : addTrackToView ( Itdb_Track * track , IpodMediaItem * item , bool checkIntegrity , bool batchmode )
{
bool visible = false ;
bool stale = false ;
if ( checkIntegrity )
{
if ( ! pathExists ( track - > ipod_path ) )
{
stale = true ;
debug ( ) < < " track: " < < track - > artist < < " - " < < track - > album < < " - " < < track - > title < < " is stale: " < < track - > ipod_path < < " does not exist " < < endl ;
if ( item )
m_staleItem - > insertItem ( item ) ;
else
item = new IpodMediaItem ( m_staleItem , this ) ;
item - > setType ( MediaItem : : STALE ) ;
TQString title = TQString : : fromUtf8 ( track - > artist ) + " - "
+ TQString : : fromUtf8 ( track - > title ) ;
item - > setText ( 0 , title ) ;
item - > m_track = track ;
}
else
{
m_files . insert ( TQString ( track - > ipod_path ) . lower ( ) , track ) ;
}
}
if ( ! stale & & m_masterPlaylist & & itdb_playlist_contains_track ( m_masterPlaylist , track )
& & ( ! m_podcastPlaylist | | ! itdb_playlist_contains_track ( m_podcastPlaylist , track ) ) )
{
visible = true ;
TQString artistName ;
if ( track - > compilation )
artistName = i18n ( " Various Artists " ) ;
else
artistName = TQString : : fromUtf8 ( track - > artist ) ;
IpodMediaItem * artist = getArtist ( artistName ) ;
if ( ! artist )
{
artist = new IpodMediaItem ( m_view , this ) ;
artist - > setText ( 0 , artistName ) ;
artist - > setType ( MediaItem : : ARTIST ) ;
if ( artistName = = i18n ( " Various Artists " ) )
artist - > m_order = - 1 ;
}
TQString albumName ( TQString : : fromUtf8 ( track - > album ) ) ;
MediaItem * album = artist - > findItem ( albumName ) ;
if ( ! album )
{
album = new IpodMediaItem ( artist , this ) ;
album - > setText ( 0 , albumName ) ;
album - > setType ( MediaItem : : ALBUM ) ;
}
if ( item )
album - > insertItem ( item ) ;
else
{
item = new IpodMediaItem ( album , this ) ;
}
TQString titleName = TQString : : fromUtf8 ( track - > title ) ;
if ( track - > compilation )
item - > setText ( 0 , TQString : : fromUtf8 ( track - > artist ) + i18n ( " - " ) + titleName ) ;
else
item - > setText ( 0 , titleName ) ;
item - > setType ( MediaItem : : TRACK ) ;
item - > m_track = track ;
item - > bundleFromTrack ( track , realPath ( track - > ipod_path ) ) ;
item - > m_order = track - > track_nr ;
}
if ( ! stale & & m_podcastPlaylist & & itdb_playlist_contains_track ( m_podcastPlaylist , track ) )
{
visible = true ;
TQString channelName ( TQString : : fromUtf8 ( track - > album ) ) ;
IpodMediaItem * channel = dynamic_cast < IpodMediaItem * > ( m_podcastItem - > findItem ( channelName ) ) ;
if ( ! channel )
{
channel = new IpodMediaItem ( m_podcastItem , this ) ;
channel - > setText ( 0 , channelName ) ;
channel - > setType ( MediaItem : : PODCASTCHANNEL ) ;
channel - > m_podcastInfo = new PodcastInfo ;
}
if ( item )
channel - > insertItem ( item ) ;
else
item = new IpodMediaItem ( channel , this ) ;
item - > setText ( 0 , TQString : : fromUtf8 ( track - > title ) ) ;
item - > setType ( MediaItem : : PODCASTITEM ) ;
item - > m_track = track ;
item - > bundleFromTrack ( track , realPath ( track - > ipod_path ) ) ;
PodcastInfo * info = new PodcastInfo ;
item - > m_podcastInfo = info ;
info - > url = TQString : : fromUtf8 ( track - > podcasturl ) ;
info - > rss = TQString : : fromUtf8 ( track - > podcastrss ) ;
info - > description = TQString : : fromUtf8 ( track - > description ) ;
info - > date . setTime_t ( itdb_time_mac_to_host ( track - > time_released ) ) ;
if ( ! info - > rss . isEmpty ( ) & & channel - > m_podcastInfo - > rss . isEmpty ( ) )
{
channel - > m_podcastInfo - > rss = info - > rss ;
}
}
if ( ! stale & & ! visible )
{
debug ( ) < < " invisible, title= " < < track - > title < < endl ;
if ( item )
m_invisibleItem - > insertItem ( item ) ;
else
item = new IpodMediaItem ( m_invisibleItem , this ) ;
TQString title = TQString : : fromUtf8 ( track - > artist ) + " - "
+ TQString : : fromUtf8 ( track - > title ) ;
item - > setText ( 0 , title ) ;
item - > setType ( MediaItem : : INVISIBLE ) ;
item - > m_track = track ;
item - > bundleFromTrack ( track , realPath ( track - > ipod_path ) ) ;
}
if ( ! batchmode )
updateRootItems ( ) ;
return item ;
}
void
IpodMediaDevice : : addPlaylistToView ( Itdb_Playlist * pl )
{
if ( itdb_playlist_is_mpl ( pl ) )
{
m_masterPlaylist = pl ;
return ;
}
if ( itdb_playlist_is_podcasts ( pl ) )
{
m_podcastPlaylist = pl ;
return ;
}
if ( pl - > is_spl )
{
debug ( ) < < " playlist " < < pl - > name < < " is a smart playlist " < < endl ;
}
TQString name ( TQString : : fromUtf8 ( pl - > name ) ) ;
IpodMediaItem * playlist = dynamic_cast < IpodMediaItem * > ( m_playlistItem - > findItem ( name ) ) ;
if ( ! playlist )
{
playlist = new IpodMediaItem ( m_playlistItem , this ) ;
playlist - > setText ( 0 , name ) ;
playlist - > setType ( MediaItem : : PLAYLIST ) ;
playlist - > m_playlist = pl ;
}
int i = 0 ;
GList * cur = pl - > members ;
while ( cur )
{
Itdb_Track * track = ( Itdb_Track * ) cur - > data ;
IpodMediaItem * item = new IpodMediaItem ( playlist , this ) ;
TQString title = TQString : : fromUtf8 ( track - > artist ) + " - "
+ TQString : : fromUtf8 ( track - > title ) ;
item - > setText ( 0 , title ) ;
item - > setType ( MediaItem : : PLAYLISTITEM ) ;
item - > m_playlist = pl ;
item - > m_track = track ;
item - > bundleFromTrack ( track , realPath ( track - > ipod_path ) ) ;
item - > m_order = i ;
cur = cur - > next ;
i + + ;
}
}
TQString
IpodMediaDevice : : itunesDir ( const TQString & p ) const
{
TQString base ( " :iPod_Control " ) ;
if ( m_isMobile )
base = " :iTunes:iTunes_Control " ;
else if ( m_isIPhone )
base = " :iTunes_Control " ;
if ( ! p . startsWith ( " : " ) )
base + = ' : ' ;
return base + p ;
}
TQString
IpodMediaDevice : : realPath ( const char * ipodPath )
{
TQString path ;
if ( m_itdb )
{
path = TQFile : : decodeName ( itdb_get_mountpoint ( m_itdb ) ) ;
path . append ( TQString ( ipodPath ) . replace ( ' : ' , " / " ) ) ;
}
return path ;
}
TQString
IpodMediaDevice : : ipodPath ( const TQString & realPath )
{
if ( m_itdb )
{
TQString mp = TQFile : : decodeName ( itdb_get_mountpoint ( m_itdb ) ) ;
if ( realPath . startsWith ( mp ) )
{
TQString path = realPath ;
path = path . mid ( mp . length ( ) ) ;
path = path . replace ( ' / ' , " : " ) ;
return path ;
}
}
return TQString ( ) ;
}
class IpodWriteDBJob : public ThreadManager : : DependentJob
{
public :
IpodWriteDBJob ( TQObject * parent , Itdb_iTunesDB * itdb , bool isShuffle , bool * resultPtr )
: ThreadManager : : DependentJob ( parent , " IpodWriteDBJob " )
, m_itdb ( itdb )
, m_isShuffle ( isShuffle )
, m_resultPtr ( resultPtr )
, m_return ( true )
{ }
private :
virtual bool doJob ( )
{
if ( ! m_itdb )
{
m_return = false ;
}
GError * error = 0 ;
if ( m_return & & ! itdb_write ( m_itdb , & error ) )
{ /* an error occurred */
m_return = false ;
if ( error )
{
if ( error - > message )
debug ( ) < < " itdb_write error: " < < error - > message < < endl ;
else
debug ( ) < < " itdb_write error: " < < " error->message == 0! " < < endl ;
g_error_free ( error ) ;
}
error = 0 ;
}
if ( m_return & & m_isShuffle )
{
/* write shuffle data */
if ( ! itdb_shuffle_write ( m_itdb , & error ) )
{ /* an error occurred */
m_return = false ;
if ( error )
{
if ( error - > message )
debug ( ) < < " itdb_shuffle_write error: " < < error - > message < < endl ;
else
debug ( ) < < " itdb_shuffle_write error: " < < " error->message == 0! " < < endl ;
g_error_free ( error ) ;
}
error = 0 ;
}
}
return true ;
}
virtual void completeJob ( )
{
* m_resultPtr = m_return ;
}
Itdb_iTunesDB * m_itdb ;
bool m_isShuffle ;
bool * m_resultPtr ;
bool m_return ;
} ;
bool
IpodMediaDevice : : writeITunesDB ( bool threaded )
{
if ( ! m_itdb )
return false ;
if ( m_dbChanged )
{
bool ok = false ;
if ( ! threaded | | MediaBrowser : : instance ( ) - > isQuitting ( ) )
{
if ( ! m_itdb )
{
return false ;
}
ok = true ;
GError * error = 0 ;
if ( ! itdb_write ( m_itdb , & error ) )
{ /* an error occurred */
if ( error )
{
if ( error - > message )
debug ( ) < < " itdb_write error: " < < error - > message < < endl ;
else
debug ( ) < < " itdb_write error: " < < " error->message == 0! " < < endl ;
g_error_free ( error ) ;
}
error = 0 ;
ok = false ;
}
if ( m_isShuffle )
{
/* write shuffle data */
if ( ! itdb_shuffle_write ( m_itdb , & error ) )
{ /* an error occurred */
if ( error )
{
if ( error - > message )
debug ( ) < < " itdb_shuffle_write error: " < < error - > message < < endl ;
else
debug ( ) < < " itdb_shuffle_write error: " < < " error->message == 0! " < < endl ;
g_error_free ( error ) ;
}
error = 0 ;
ok = false ;
}
}
}
else
{
ThreadManager : : instance ( ) - > queueJob ( new IpodWriteDBJob ( this , m_itdb , m_isShuffle , & ok ) ) ;
while ( ThreadManager : : instance ( ) - > isJobPending ( " IpodWriteDBJob " ) )
{
kapp - > processEvents ( ) ;
usleep ( 10000 ) ;
}
}
if ( ok )
{
m_dbChanged = false ;
}
else
{
Amarok : : StatusBar : : instance ( ) - > longMessage (
i18n ( " Media device: failed to write iPod database " ) ,
KDE : : StatusBar : : Error ) ;
}
return ok ;
}
return true ;
}
IpodMediaItem *
IpodMediaDevice : : getArtist ( const TQString & artist )
{
for ( IpodMediaItem * it = dynamic_cast < IpodMediaItem * > ( m_view - > firstChild ( ) ) ;
it ;
it = dynamic_cast < IpodMediaItem * > ( it - > nextSibling ( ) ) )
{
if ( it - > m_type = = MediaItem : : ARTIST & & artist = = it - > text ( 0 ) )
return it ;
}
return 0 ;
}
IpodMediaItem *
IpodMediaDevice : : getAlbum ( const TQString & artist , const TQString & album )
{
IpodMediaItem * item = getArtist ( artist ) ;
if ( item )
return dynamic_cast < IpodMediaItem * > ( item - > findItem ( album ) ) ;
return 0 ;
}
IpodMediaItem *
IpodMediaDevice : : getTrack ( const TQString & artist , const TQString & album , const TQString & title ,
int discNumber , int trackNumber , const PodcastEpisodeBundle * peb )
{
IpodMediaItem * item = getAlbum ( artist , album ) ;
if ( item )
{
for ( IpodMediaItem * track = dynamic_cast < IpodMediaItem * > ( item - > findItem ( title ) ) ;
track ;
track = dynamic_cast < IpodMediaItem * > ( item - > findItem ( title , track ) ) )
{
if ( ( discNumber = = - 1 | | track - > bundle ( ) - > discNumber ( ) = = discNumber )
& & ( trackNumber = = - 1 | | track - > bundle ( ) - > track ( ) = = trackNumber ) )
return track ;
}
}
item = getAlbum ( i18n ( " Various Artists " ) , album ) ;
if ( item )
{
TQString t = artist + i18n ( " - " ) + title ;
for ( IpodMediaItem * track = dynamic_cast < IpodMediaItem * > ( item - > findItem ( t ) ) ;
track ;
track = dynamic_cast < IpodMediaItem * > ( item - > findItem ( t , track ) ) )
{
if ( ( discNumber = = - 1 | | track - > bundle ( ) - > discNumber ( ) = = discNumber )
& & ( trackNumber = = - 1 | | track - > bundle ( ) - > track ( ) = = trackNumber ) )
return track ;
}
}
if ( m_podcastItem )
{
item = dynamic_cast < IpodMediaItem * > ( m_podcastItem - > findItem ( album ) ) ;
if ( item )
{
for ( IpodMediaItem * track = dynamic_cast < IpodMediaItem * > ( item - > findItem ( title ) ) ;
track ;
track = dynamic_cast < IpodMediaItem * > ( item - > findItem ( title , track ) ) )
{
if ( ( discNumber = = - 1 | | track - > bundle ( ) - > discNumber ( ) = = discNumber )
& & ( trackNumber = = - 1 | | track - > bundle ( ) - > track ( ) = = trackNumber )
& & ( ! track - > bundle ( ) - > podcastBundle ( ) | | ! peb
| | track - > bundle ( ) - > podcastBundle ( ) - > url ( ) = = peb - > url ( ) ) )
return track ;
}
}
}
return 0 ;
}
IpodMediaItem *
IpodMediaDevice : : getTrack ( const Itdb_Track * itrack )
{
TQString artist = TQString : : fromUtf8 ( itrack - > artist ) ;
TQString album = TQString : : fromUtf8 ( itrack - > album ) ;
TQString title = TQString : : fromUtf8 ( itrack - > title ) ;
IpodMediaItem * item = getAlbum ( artist , album ) ;
if ( item )
{
for ( IpodMediaItem * track = dynamic_cast < IpodMediaItem * > ( item - > findItem ( title ) ) ;
track ;
track = dynamic_cast < IpodMediaItem * > ( item - > findItem ( title , track ) ) )
{
if ( track - > m_track = = itrack )
return track ;
}
}
item = getAlbum ( i18n ( " Various Artists " ) , album ) ;
if ( item )
{
TQString t = artist + i18n ( " - " ) + title ;
for ( IpodMediaItem * track = dynamic_cast < IpodMediaItem * > ( item - > findItem ( t ) ) ;
track ;
track = dynamic_cast < IpodMediaItem * > ( item - > findItem ( t , track ) ) )
{
if ( track - > m_track = = itrack )
return track ;
}
}
if ( m_podcastItem )
{
item = dynamic_cast < IpodMediaItem * > ( m_podcastItem - > findItem ( album ) ) ;
if ( item )
{
for ( IpodMediaItem * track = dynamic_cast < IpodMediaItem * > ( item - > findItem ( title ) ) ;
track ;
track = dynamic_cast < IpodMediaItem * > ( item - > findItem ( title , track ) ) )
{
if ( track - > m_track = = itrack )
return track ;
}
}
}
return 0 ;
}
KURL
IpodMediaDevice : : determineURLOnDevice ( const MetaBundle & bundle )
{
if ( ! m_itdb )
{
debug ( ) < < " m_itdb is NULL " < < endl ;
return KURL ( ) ;
}
TQString local = bundle . filename ( ) ;
TQString type = TQString ( local . section ( ' . ' , - 1 ) ) . lower ( ) ;
TQString trackpath ;
TQString realpath ;
do
{
int num = std : : rand ( ) % 1000000 ;
int music_dirs = itdb_musicdirs_number ( m_itdb ) > 1 ? itdb_musicdirs_number ( m_itdb ) : 20 ;
int dir = num % music_dirs ;
TQString dirname ;
dirname . sprintf ( " %s:Music:f%02d " , itunesDir ( ) . latin1 ( ) , dir ) ;
if ( ! pathExists ( dirname ) )
{
TQString realdir = realPath ( dirname . latin1 ( ) ) ;
TQDir qdir ( realdir ) ;
qdir . mkdir ( realdir ) ;
}
TQString filename ;
filename . sprintf ( " :kpod%07d.%s " , num , type . latin1 ( ) ) ;
trackpath = dirname + filename ;
}
while ( pathExists ( trackpath , & realpath ) ) ;
return realpath ;
}
bool
IpodMediaDevice : : removeDBTrack ( Itdb_Track * track )
{
if ( ! m_itdb )
return false ;
if ( ! track )
return false ;
if ( track - > itdb ! = m_itdb )
{
return false ;
}
m_dbChanged = true ;
Itdb_Playlist * mpl = itdb_playlist_mpl ( m_itdb ) ;
while ( itdb_playlist_contains_track ( mpl , track ) )
{
itdb_playlist_remove_track ( mpl , track ) ;
}
GList * cur = m_itdb - > playlists ;
while ( cur )
{
Itdb_Playlist * pl = ( Itdb_Playlist * ) cur - > data ;
while ( itdb_playlist_contains_track ( pl , track ) )
{
itdb_playlist_remove_track ( pl , track ) ;
}
cur = cur - > next ;
}
// also frees track's memory
itdb_track_remove ( track ) ;
return true ;
}
bool
IpodMediaDevice : : getCapacity ( TDEIO : : filesize_t * total , TDEIO : : filesize_t * available )
{
if ( ! m_itdb )
return false ;
# ifdef HAVE_STATVFS
TQString path ;
if ( ! pathExists ( itunesDir ( ) , & path ) )
return false ;
struct statvfs buf ;
if ( statvfs ( TQFile : : encodeName ( path ) , & buf ) ! = 0 )
{
* total = 0 ;
* available = 0 ;
return false ;
}
* total = buf . f_blocks * ( TDEIO : : filesize_t ) buf . f_frsize ;
* available = buf . f_bavail * ( TDEIO : : filesize_t ) buf . f_frsize ;
return * total > 0 ;
# else
return false ;
# endif
}
void
IpodMediaDevice : : rmbPressed ( TQListViewItem * qitem , const TQPoint & point , int )
{
MediaItem * item = dynamic_cast < MediaItem * > ( qitem ) ;
bool locked = m_mutex . locked ( ) ;
KURL : : List urls = m_view - > nodeBuildDragList ( 0 ) ;
TDEPopupMenu menu ( m_view ) ;
enum Actions { CREATE_PLAYLIST , APPEND , LOAD , QUEUE ,
COPY_TO_COLLECTION ,
BURN_ARTIST , BURN_ALBUM , BURN_DATACD , BURN_AUDIOCD ,
RENAME , SUBSCRIBE ,
MAKE_PLAYLIST , ADD_TO_PLAYLIST , ADD ,
DELETE_PLAYED , DELETE_FROM_IPOD , REMOVE_FROM_PLAYLIST ,
FIRST_PLAYLIST } ;
TDEPopupMenu * playlistsMenu = 0 ;
if ( item )
{
if ( item - > type ( ) = = MediaItem : : PLAYLISTSROOT )
{
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " add_playlist " ) ) ,
i18n ( " Create Playlist... " ) , CREATE_PLAYLIST ) ;
}
else
{
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " playlist " ) ) , i18n ( " &Load " ) , LOAD ) ;
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " add_playlist " ) ) , i18n ( " &Append to Playlist " ) , APPEND ) ;
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " fastforward " ) ) , i18n ( " &Queue Tracks " ) , QUEUE ) ;
}
menu . insertSeparator ( ) ;
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " collection " ) ) , i18n ( " &Copy Files to Collection... " ) , COPY_TO_COLLECTION ) ;
switch ( item - > type ( ) )
{
case MediaItem : : ARTIST :
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " cdrom_unmount " ) ) , i18n ( " Burn All Tracks by This Artist " ) , BURN_ARTIST ) ;
menu . setItemEnabled ( BURN_ARTIST , K3bExporter : : isAvailable ( ) ) ;
break ;
case MediaItem : : ALBUM :
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " cdrom_unmount " ) ) , i18n ( " Burn This Album " ) , BURN_ALBUM ) ;
menu . setItemEnabled ( BURN_ALBUM , K3bExporter : : isAvailable ( ) ) ;
break ;
default :
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " cdrom_unmount " ) ) , i18n ( " Burn to CD as Data " ) , BURN_DATACD ) ;
menu . setItemEnabled ( BURN_DATACD , K3bExporter : : isAvailable ( ) ) ;
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " cdaudio_unmount " ) ) , i18n ( " Burn to CD as Audio " ) , BURN_AUDIOCD ) ;
menu . setItemEnabled ( BURN_AUDIOCD , K3bExporter : : isAvailable ( ) ) ;
break ;
}
menu . insertSeparator ( ) ;
if ( ( item - > type ( ) = = MediaItem : : PODCASTITEM
| | item - > type ( ) = = MediaItem : : PODCASTCHANNEL ) )
{
IpodMediaItem * it = static_cast < IpodMediaItem * > ( item ) ;
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " podcast " ) ) , i18n ( " Subscribe to This Podcast " ) , SUBSCRIBE ) ;
//menu.setItemEnabled( SUBSCRIBE, item->bundle()->podcastBundle() && item->bundle()->podcastBundle()->parent().isValid() );
menu . setItemEnabled ( SUBSCRIBE , it - > m_podcastInfo & & ! it - > m_podcastInfo - > rss . isEmpty ( ) ) ;
menu . insertSeparator ( ) ;
}
switch ( item - > type ( ) )
{
case MediaItem : : ARTIST :
case MediaItem : : ALBUM :
case MediaItem : : TRACK :
case MediaItem : : PODCASTCHANNEL :
case MediaItem : : PODCASTSROOT :
case MediaItem : : PODCASTITEM :
if ( m_playlistItem )
{
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " playlist " ) ) , i18n ( " Make Media Device Playlist " ) , MAKE_PLAYLIST ) ;
menu . setItemEnabled ( MAKE_PLAYLIST , ! locked ) ;
playlistsMenu = new TDEPopupMenu ( & menu ) ;
int i = 0 ;
for ( MediaItem * it = dynamic_cast < MediaItem * > ( m_playlistItem - > firstChild ( ) ) ;
it ;
it = dynamic_cast < MediaItem * > ( it - > nextSibling ( ) ) )
{
playlistsMenu - > insertItem ( SmallIconSet ( Amarok : : icon ( " playlist " ) ) , it - > text ( 0 ) , FIRST_PLAYLIST + i ) ;
i + + ;
}
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " playlist " ) ) , i18n ( " Add to Playlist " ) , playlistsMenu , ADD_TO_PLAYLIST ) ;
menu . setItemEnabled ( ADD_TO_PLAYLIST , ! locked & & m_playlistItem - > childCount ( ) > 0 ) ;
menu . insertSeparator ( ) ;
}
if ( item - > type ( ) = = MediaItem : : ARTIST | |
item - > type ( ) = = MediaItem : : ALBUM | |
item - > type ( ) = = MediaItem : : TRACK | |
item - > type ( ) = = MediaItem : : ORPHANED )
{
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " edit " ) ) ,
i18n ( " Edit &Information... " , " Edit &Information for %n Tracks... " , urls . count ( ) ) ,
RENAME ) ;
}
break ;
case MediaItem : : ORPHANED :
case MediaItem : : ORPHANEDROOT :
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " edit " ) ) , i18n ( " Add to Database " ) , ADD ) ;
menu . setItemEnabled ( ADD , ! locked ) ;
break ;
case MediaItem : : PLAYLIST :
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " edit " ) ) , i18n ( " Rename " ) , RENAME ) ;
menu . setItemEnabled ( RENAME , ! locked ) ;
break ;
default :
break ;
}
if ( item - > type ( ) = = MediaItem : : PLAYLIST | | item - > type ( ) = = MediaItem : : PLAYLISTITEM )
{
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " remove_from_playlist " ) ) ,
item - > type ( ) = = MediaItem : : PLAYLIST ? i18n ( " Remove Playlist " ) : i18n ( " Remove from Playlist " ) ,
REMOVE_FROM_PLAYLIST ) ;
menu . setItemEnabled ( REMOVE_FROM_PLAYLIST , ! locked ) ;
}
if ( item - > type ( ) = = MediaItem : : PODCASTSROOT | | item - > type ( ) = = MediaItem : : PODCASTCHANNEL )
{
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " remove " ) ) , i18n ( " Delete Podcasts Already Played " ) , DELETE_PLAYED ) ;
menu . setItemEnabled ( DELETE_PLAYED , ! locked ) ;
}
menu . insertItem ( SmallIconSet ( Amarok : : icon ( " remove " ) ) ,
i18n ( " Delete Track from iPod " , " Delete %n Tracks from iPod " , urls . count ( ) ) ,
DELETE_FROM_IPOD ) ;
menu . setItemEnabled ( DELETE_FROM_IPOD , ! locked & & urls . count ( ) > 0 ) ;
}
int id = menu . exec ( point ) ;
switch ( id )
{
case CREATE_PLAYLIST :
break ;
case LOAD :
Playlist : : instance ( ) - > insertMedia ( urls , Playlist : : Replace ) ;
break ;
case APPEND :
Playlist : : instance ( ) - > insertMedia ( urls , Playlist : : Append ) ;
break ;
case QUEUE :
Playlist : : instance ( ) - > insertMedia ( urls , Playlist : : Queue ) ;
break ;
case COPY_TO_COLLECTION :
{
TQPtrList < MediaItem > items ;
m_view - > getSelectedLeaves ( 0 , & items ) ;
KURL : : List urls ;
for ( MediaItem * it = items . first ( ) ;
it ;
it = items . next ( ) )
{
if ( it - > url ( ) . isValid ( ) )
urls < < it - > url ( ) ;
}
CollectionView : : instance ( ) - > organizeFiles ( urls , i18n ( " Copy Files To Collection " ) , true ) ;
}
break ;
case BURN_ARTIST :
K3bExporter : : instance ( ) - > exportArtist ( item - > text ( 0 ) ) ;
break ;
case BURN_ALBUM :
K3bExporter : : instance ( ) - > exportAlbum ( item - > text ( 0 ) ) ;
break ;
case BURN_DATACD :
K3bExporter : : instance ( ) - > exportTracks ( urls , K3bExporter : : DataCD ) ;
break ;
case BURN_AUDIOCD :
K3bExporter : : instance ( ) - > exportTracks ( urls , K3bExporter : : AudioCD ) ;
break ;
case SUBSCRIBE :
PlaylistBrowser : : instance ( ) - > addPodcast ( static_cast < IpodMediaItem * > ( item ) - > m_podcastInfo - > rss ) ;
break ;
case RENAME :
if ( item - > type ( ) = = MediaItem : : PLAYLIST )
{
m_view - > rename ( item , 0 ) ;
}
else
{
TagDialog * dialog = NULL ;
if ( urls . count ( ) = = 1 )
dialog = new TagDialog ( urls . first ( ) , m_view ) ;
else
dialog = new TagDialog ( urls , m_view ) ;
dialog - > show ( ) ;
}
break ;
default :
break ;
}
if ( ! m_mutex . locked ( ) )
{
switch ( id )
{
case CREATE_PLAYLIST :
case MAKE_PLAYLIST :
{
TQPtrList < MediaItem > items ;
if ( id = = MAKE_PLAYLIST )
m_view - > getSelectedLeaves ( 0 , & items ) ;
TQString base ( i18n ( " New Playlist " ) ) ;
TQString name = base ;
int i = 1 ;
while ( m_playlistItem - > findItem ( name ) )
{
TQString num ;
num . setNum ( i ) ;
name = base + ' ' + num ;
i + + ;
}
MediaItem * pl = newPlaylist ( name , m_playlistItem , items ) ;
m_view - > ensureItemVisible ( pl ) ;
m_view - > rename ( pl , 0 ) ;
}
break ;
case ADD :
{
int dupes = 0 ;
if ( item - > type ( ) = = MediaItem : : ORPHANEDROOT )
{
MediaItem * next = 0 ;
for ( MediaItem * it = dynamic_cast < MediaItem * > ( item - > firstChild ( ) ) ;
it ;
it = next )
{
next = dynamic_cast < MediaItem * > ( it - > nextSibling ( ) ) ;
if ( trackExists ( * it - > bundle ( ) ) )
{
dupes + + ;
continue ;
}
item - > takeItem ( it ) ;
insertTrackIntoDB ( it - > url ( ) . path ( ) , * it - > bundle ( ) , * it - > bundle ( ) , 0 ) ;
delete it ;
}
}
else
{
TQPtrList < MediaItem > items ;
m_view - > getSelectedLeaves ( 0 , & items ) ;
for ( TQPtrList < MediaItem > : : iterator it = items . begin ( ) ;
it ! = items . end ( ) ;
it + + )
{
IpodMediaItem * i = dynamic_cast < IpodMediaItem * > ( * it ) ;
if ( ! i | | i - > type ( ) ! = MediaItem : : ORPHANED )
continue ;
if ( trackExists ( * i - > bundle ( ) ) )
{
dupes + + ;
continue ;
}
i - > parent ( ) - > takeItem ( i ) ;
insertTrackIntoDB ( i - > url ( ) . path ( ) , * i - > bundle ( ) , * i - > bundle ( ) , 0 ) ;
delete i ;
}
}
if ( dupes > 0 )
Amarok : : StatusBar : : instance ( ) - > shortMessage ( i18n (
" One duplicate track not added to database " ,
" %n duplicate tracks not added to database " , dupes ) ) ;
}
break ;
case DELETE_PLAYED :
{
MediaItem * podcasts = 0 ;
if ( item - > type ( ) = = MediaItem : : PODCASTCHANNEL )
podcasts = dynamic_cast < MediaItem * > ( item - > parent ( ) ) ;
else
podcasts = item ;
deleteFromDevice ( podcasts , true ) ;
}
break ;
case REMOVE_FROM_PLAYLIST :
deleteFromDevice ( m_playlistItem , None ) ;
break ;
case DELETE_FROM_IPOD :
deleteFromDevice ( ) ;
break ;
default :
if ( playlistsMenu & & id > = FIRST_PLAYLIST )
{
TQString name = playlistsMenu - > text ( id ) ;
if ( name ! = TQString ( ) )
{
MediaItem * list = m_playlistItem - > findItem ( name ) ;
if ( list )
{
MediaItem * after = 0 ;
for ( MediaItem * it = dynamic_cast < MediaItem * > ( list - > firstChild ( ) ) ;
it ;
it = dynamic_cast < MediaItem * > ( it - > nextSibling ( ) ) )
after = it ;
TQPtrList < MediaItem > items ;
m_view - > getSelectedLeaves ( 0 , & items ) ;
addToPlaylist ( list , after , items ) ;
}
}
}
break ;
}
if ( m_dbChanged & & lockDevice ( true ) )
{
synchronizeDevice ( ) ;
unlockDevice ( ) ;
}
}
}
TQStringList
IpodMediaDevice : : supportedFiletypes ( )
{
TQStringList list ;
list < < " mp3 " ;
list < < " m4a " ;
list < < " m4b " ;
list < < " wav " ;
list < < " mp4 " ;
list < < " aa " ;
if ( m_supportsVideo )
{
list < < " m4v " ;
list < < " mp4v " ;
list < < " mov " ;
list < < " mpg " ;
}
if ( m_rockboxFirmware )
{
list < < " ogg " ;
list < < " mpc " ;
list < < " ac3 " ;
list < < " adx " ;
list < < " aiff " ;
list < < " flac " ;
list < < " mid " ;
list < < " midi " ;
list < < " shn " ;
list < < " wv " ;
list < < " ape " ;
list < < " tta " ;
}
return list ;
}
void
IpodMediaDevice : : addConfigElements ( TQWidget * parent )
{
m_autoDeletePodcastsCheck = new TQCheckBox ( parent ) ;
m_autoDeletePodcastsCheck - > setText ( i18n ( " &Automatically delete podcasts " ) ) ;
TQToolTip : : add ( m_autoDeletePodcastsCheck , i18n ( " Automatically delete podcast shows already played when connecting device " ) ) ;
m_autoDeletePodcastsCheck - > setChecked ( m_autoDeletePodcasts ) ;
m_syncStatsCheck = new TQCheckBox ( parent ) ;
m_syncStatsCheck - > setText ( i18n ( " &Synchronize with Amarok statistics " ) ) ;
TQToolTip : : add ( m_syncStatsCheck , i18n ( " Synchronize with Amarok statistics and submit tracks played to last.fm " ) ) ;
m_syncStatsCheck - > setChecked ( m_syncStats ) ;
}
void
IpodMediaDevice : : removeConfigElements ( TQWidget * /*parent*/ )
{
delete m_syncStatsCheck ;
m_syncStatsCheck = 0 ;
delete m_autoDeletePodcastsCheck ;
m_autoDeletePodcastsCheck = 0 ;
}
void
IpodMediaDevice : : applyConfig ( )
{
m_autoDeletePodcasts = m_autoDeletePodcastsCheck - > isChecked ( ) ;
m_syncStats = m_syncStatsCheck - > isChecked ( ) ;
setConfigBool ( " SyncStats " , m_syncStats ) ;
setConfigBool ( " AutoDeletePodcasts " , m_autoDeletePodcasts ) ;
}
void
IpodMediaDevice : : loadConfig ( )
{
MediaDevice : : loadConfig ( ) ;
m_syncStats = configBool ( " SyncStats " , false ) ;
m_autoDeletePodcasts = configBool ( " AutoDeletePodcasts " , false ) ;
m_autoConnect = configBool ( " AutoConnect " , true ) ;
}
bool
IpodMediaDevice : : pathExists ( const TQString & ipodPath , TQString * realPath )
{
TQDir curDir ( mountPoint ( ) ) ;
curDir . setFilter ( curDir . filter ( ) | TQDir : : Hidden ) ;
TQString curPath = mountPoint ( ) ;
TQStringList components = TQStringList : : split ( " : " , ipodPath ) ;
bool found = false ;
TQStringList : : iterator it = components . begin ( ) ;
for ( ; it ! = components . end ( ) ; + + it )
{
found = false ;
for ( uint i = 0 ; i < curDir . count ( ) ; i + + )
{
if ( curDir [ i ] . lower ( ) = = ( * it ) . lower ( ) )
{
curPath + = ' / ' + curDir [ i ] ;
curDir . cd ( curPath ) ;
found = true ;
break ;
}
}
if ( ! found )
break ;
}
for ( ; it ! = components . end ( ) ; + + it )
curPath + = ' / ' + * it ;
//debug() << ipodPath << ( found ? "" : " not" ) << " found, actually " << curPath << endl;
if ( realPath )
* realPath = curPath ;
return found ;
}
void
IpodMediaDevice : : fileDeleted ( TDEIO : : Job * job ) //SLOT
{
if ( job - > error ( ) )
{
debug ( ) < < " file deletion failed: " < < job - > errorText ( ) < < endl ;
}
m_waitForDeletion = false ;
m_parent - > updateStats ( ) ;
}
void
IpodMediaDevice : : deleteFile ( const KURL & url )
{
debug ( ) < < " deleting " < < url . prettyURL ( ) < < endl ;
m_waitForDeletion = true ;
TDEIO : : Job * job = TDEIO : : file_delete ( url , false ) ;
connect ( job , TQT_SIGNAL ( result ( TDEIO : : Job * ) ) ,
this , TQT_SLOT ( fileDeleted ( TDEIO : : Job * ) ) ) ;
do
{
kapp - > processEvents ( 100 ) ;
if ( isCanceled ( ) )
break ;
usleep ( 10000 ) ;
} while ( m_waitForDeletion ) ;
if ( ! isTransferring ( ) )
setProgress ( progress ( ) + 1 ) ;
}
# include "ipodmediadevice.moc"