mtpmediadevice.cpp
来自「Amarok是一款在LINUX或其他类UNIX操作系统中运行的音频播放器软件。 」· C++ 代码 · 共 1,669 行 · 第 1/4 页
CPP
1,669 行
/*************************************************************************** * copyright : (C) 2006 Andy Kelk <andy@mopoke.co.uk> * ***************************************************************************//*************************************************************************** * * * 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. * * * ***************************************************************************/ /** * Based on njb mediadevice with some code hints from the libmtp * example tools */ /** * MTP media device * @author Andy Kelk <andy@mopoke.co.uk> * @see http://libmtp.sourceforge.net/ */#define DEBUG_PREFIX "MtpMediaDevice"#include <config.h>#include "mtpmediadevice.h"AMAROK_EXPORT_PLUGIN( MtpMediaDevice )// Amarok#include <debug.h>#include <metabundle.h>#include <statusbar/statusbar.h>#include <statusbar/popupMessage.h>#include <collectionbrowser.h>// KDE#include <kapplication.h>#include <kiconloader.h>#include <kpopupmenu.h>#include <kmessagebox.h>#include <ktoolbarbutton.h>#include <ktempdir.h>// Qt#include <qdir.h>#include <qlistview.h>#include <qtooltip.h>#include <qlineedit.h>#include <qregexp.h>#include <qbuffer.h>#include <qmap.h>/** * MtpMediaDevice Class */MtpMediaDevice::MtpMediaDevice() : MediaDevice(){ m_name = i18n("MTP Media Device"); m_device = 0; m_folders = 0; m_playlistItem = 0; setDisconnected(); m_hasMountPoint = false; m_syncStats = false; m_transcode = false; m_transcodeAlways = false; m_transcodeRemove = false; m_configure = false; m_customButton = true; m_transfer = true; KToolBarButton *customButton = MediaBrowser::instance()->getToolBar()->getButton( MediaBrowser::CUSTOM ); customButton->setText( i18n("Special device functions") ); QToolTip::remove( customButton ); QToolTip::add( customButton, i18n( "Special functions of your device" ) ); mtpFileTypes[LIBMTP_FILETYPE_WAV] = "wav"; mtpFileTypes[LIBMTP_FILETYPE_MP3] = "mp3"; mtpFileTypes[LIBMTP_FILETYPE_WMA] = "wma"; mtpFileTypes[LIBMTP_FILETYPE_OGG] = "ogg"; mtpFileTypes[LIBMTP_FILETYPE_AUDIBLE] = "aa"; // audible mtpFileTypes[LIBMTP_FILETYPE_MP4] = "mp4"; mtpFileTypes[LIBMTP_FILETYPE_UNDEF_AUDIO] = "undef-audio"; mtpFileTypes[LIBMTP_FILETYPE_WMV] = "wmv"; mtpFileTypes[LIBMTP_FILETYPE_AVI] = "avi"; mtpFileTypes[LIBMTP_FILETYPE_MPEG] = "mpg"; mtpFileTypes[LIBMTP_FILETYPE_ASF] = "asf"; mtpFileTypes[LIBMTP_FILETYPE_QT] = "mov"; mtpFileTypes[LIBMTP_FILETYPE_UNDEF_VIDEO] = "undef-video"; mtpFileTypes[LIBMTP_FILETYPE_JPEG] = "jpg"; mtpFileTypes[LIBMTP_FILETYPE_JFIF] = "jpg"; mtpFileTypes[LIBMTP_FILETYPE_TIFF] = "tiff"; mtpFileTypes[LIBMTP_FILETYPE_BMP] = "bmp"; mtpFileTypes[LIBMTP_FILETYPE_GIF] = "gif"; mtpFileTypes[LIBMTP_FILETYPE_PICT] = "pict"; mtpFileTypes[LIBMTP_FILETYPE_PNG] = "png"; mtpFileTypes[LIBMTP_FILETYPE_VCALENDAR1] = "vcs"; // vcal1 mtpFileTypes[LIBMTP_FILETYPE_VCALENDAR2] = "vcs"; // vcal2 mtpFileTypes[LIBMTP_FILETYPE_VCARD2] = "vcf"; // vcard2 mtpFileTypes[LIBMTP_FILETYPE_VCARD3] = "vcf"; // vcard3 mtpFileTypes[LIBMTP_FILETYPE_WINDOWSIMAGEFORMAT] = "wim"; // windows image format mtpFileTypes[LIBMTP_FILETYPE_WINEXEC] = "exe"; mtpFileTypes[LIBMTP_FILETYPE_TEXT] = "txt"; mtpFileTypes[LIBMTP_FILETYPE_HTML] = "html"; mtpFileTypes[LIBMTP_FILETYPE_UNKNOWN] = "unknown"; m_newTracks = new QPtrList<MediaItem>;}voidMtpMediaDevice::init( MediaBrowser *parent ){ MediaDevice::init( parent );}boolMtpMediaDevice::isConnected(){ return !( m_device == 0 );}/** * File types that we support */QStringListMtpMediaDevice::supportedFiletypes(){ return m_supportedFiles;}intMtpMediaDevice::progressCallback( uint64_t const sent, uint64_t const total, void const * const data ){ Q_UNUSED( sent ); Q_UNUSED( total ); kapp->processEvents( 100 ); MtpMediaDevice *dev = (MtpMediaDevice*)(data); if( dev->isCanceled() ) { debug() << "Canceling transfer operation" << endl; dev->setCanceled( true ); return 1; } return 0;}/** * Copy a track to the device */MediaItem*MtpMediaDevice::copyTrackToDevice( const MetaBundle &bundle ){ DEBUG_BLOCK QString genericError = i18n( "Could not send track" ); LIBMTP_track_t *trackmeta = LIBMTP_new_track_t(); trackmeta->item_id = 0; debug() << "filetype : " << bundle.fileType() << endl; if( bundle.fileType() == MetaBundle::mp3 ) { trackmeta->filetype = LIBMTP_FILETYPE_MP3; } else if( bundle.fileType() == MetaBundle::ogg ) { trackmeta->filetype = LIBMTP_FILETYPE_OGG; } else if( bundle.fileType() == MetaBundle::wma ) { trackmeta->filetype = LIBMTP_FILETYPE_WMA; } else if( bundle.fileType() == MetaBundle::mp4 ) { trackmeta->filetype = LIBMTP_FILETYPE_MP4; } else { // Couldn't recognise an Amarok filetype. // fallback to checking the extension (e.g. .wma, .ogg, etc) debug() << "No filetype found by Amarok filetype" << endl; const QString extension = bundle.url().path().section( ".", -1 ).lower(); int libmtp_type = m_supportedFiles.findIndex( extension ); if( libmtp_type >= 0 ) { int keyIndex = mtpFileTypes.values().findIndex( extension ); libmtp_type = mtpFileTypes.keys()[keyIndex]; trackmeta->filetype = (LIBMTP_filetype_t) libmtp_type; debug() << "set filetype to " << libmtp_type << " based on extension of ." << extension << endl; } else { debug() << "We don't support the extension ." << extension << endl; Amarok::StatusBar::instance()->shortLongMessage( genericError, i18n( "Cannot determine a valid file type" ), KDE::StatusBar::Error ); return 0; } } if( bundle.title().isEmpty() ) { trackmeta->title = qstrdup( i18n( "Unknown title" ).utf8() ); } else { trackmeta->title = qstrdup( bundle.title().utf8() ); } if( bundle.album().isEmpty() ) { trackmeta->album = qstrdup( i18n( "Unknown album" ).utf8() ); } else { trackmeta->album = qstrdup( bundle.album().string().utf8() ); } if( bundle.artist().isEmpty() ) { trackmeta->artist = qstrdup( i18n( "Unknown artist" ).utf8() ); } else { trackmeta->artist = qstrdup( bundle.artist().string().utf8() ); } if( bundle.genre().isEmpty() ) { trackmeta->genre = qstrdup( i18n( "Unknown genre" ).utf8() ); } else { trackmeta->genre = qstrdup( bundle.genre().string().utf8() ); } if( bundle.year() > 0 ) { QString date; QTextOStream( &date ) << bundle.year() << "0101T0000.0"; trackmeta->date = qstrdup( date.utf8() ); } else { trackmeta->date = qstrdup( "00010101T0000.0" ); } if( bundle.track() > 0 ) { trackmeta->tracknumber = bundle.track(); } if( bundle.length() > 0 ) { // Multiply by 1000 since this is in milliseconds trackmeta->duration = bundle.length() * 1000; } if( !bundle.filename().isEmpty() ) { trackmeta->filename = qstrdup( bundle.filename().utf8() ); } trackmeta->filesize = bundle.filesize(); // try and create the requested folder structure uint32_t parent_id = 0; if( !m_folderStructure.isEmpty() ) { parent_id = checkFolderStructure( bundle ); if( parent_id == 0 ) { debug() << "Couldn't create new parent (" << m_folderStructure << ")" << endl; Amarok::StatusBar::instance()->shortLongMessage( genericError, i18n( "Cannot create parent folder. Check your structure." ), KDE::StatusBar::Error ); return 0; } } else { parent_id = getDefaultParentId(); } debug() << "Parent id : " << parent_id << endl; m_critical_mutex.lock(); debug() << "Sending track... " << bundle.url().path().utf8() << endl; int ret = LIBMTP_Send_Track_From_File( m_device, bundle.url().path().utf8(), trackmeta, progressCallback, this, parent_id ); m_critical_mutex.unlock(); if( ret < 0 ) { debug() << "Could not write file " << ret << endl; Amarok::StatusBar::instance()->shortLongMessage( genericError, i18n( "File write failed" ), KDE::StatusBar::Error ); return 0; } MetaBundle temp( bundle ); MtpTrack *taggedTrack = new MtpTrack( trackmeta ); taggedTrack->setBundle( temp ); taggedTrack->setFolderId( parent_id ); LIBMTP_destroy_track_t( trackmeta ); kapp->processEvents( 100 ); // add track to view and to new tracks list MediaItem *newItem = addTrackToView( taggedTrack ); m_newTracks->append( newItem ); return newItem;}/** * Get the cover image for a track, convert it to a format supported on the * device and set it as the cover art. */voidMtpMediaDevice::sendAlbumArt( QPtrList<MediaItem> *items ){ QString image; image = CollectionDB::instance()->albumImage(items->first()->bundle()->artist(), items->first()->bundle()->album(), false, 100); if( ! image.endsWith( "@nocover.png" ) ) { debug() << "image " << image << " found for " << items->first()->bundle()->album() << endl; QByteArray *imagedata = getSupportedImage( image ); if( imagedata == 0 ) { debug() << "Cannot generate a supported image format" << endl; return; } if( imagedata->size() ) { m_critical_mutex.lock(); LIBMTP_album_t *album_object = getOrCreateAlbum( items ); if( album_object ) { LIBMTP_filesampledata_t *imagefile = LIBMTP_new_filesampledata_t(); imagefile->data = (char *) imagedata->data(); imagefile->size = imagedata->size(); imagefile->filetype = LIBMTP_FILETYPE_JPEG; int ret = LIBMTP_Send_Representative_Sample( m_device, album_object->album_id, imagefile ); if( ret != 0 ) { debug() << "image send failed : " << ret << endl; } } m_critical_mutex.unlock(); } }}uint32_tMtpMediaDevice::getDefaultParentId( void ){ // Decide which folder to send it to: // If the device gave us a parent_folder setting, we use it uint32_t parent_id = 0; if( m_default_parent_folder ) { parent_id = m_default_parent_folder; } // Otherwise look for a folder called "Music" else if( m_folders != 0 ) { parent_id = folderNameToID( "Music", m_folders ); if( !parent_id ) { debug() << "Parent folder could not be found. Going to use top level." << endl; } } // Give up and don't set a parent folder, let the device deal with it else { debug() << "No folders found. Going to use top level." << endl; } return parent_id;}/** * Takes path to an existing cover image and converts it to a format * supported on the device */QByteArray*MtpMediaDevice::getSupportedImage( QString path ){ if( m_format == 0 ) return 0; debug() << "Will convert image to " << m_format << endl; // open image const QImage original( path ); // save as new image QImage newformat( original ); QByteArray *newimage = new QByteArray(); QBuffer buffer( *newimage ); buffer.open( IO_WriteOnly ); if( newformat.save( &buffer, m_format.ascii() ) ) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?