Source

libtaginfo / libtaginfo / mp4info.cc

/*
 * Copyright (C) 2008-2013 J.Rios <anonbeat@gmail.com>
 * Copyright (C) 2013 Jörn Magens
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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; see the file LICENSE.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth 
 * Floor, Boston, MA  02110-1301  USA
 * https://www.gnu.org/licenses/lgpl-2.1.txt
 *
 * Author:
 * 	Jörn Magens <shuerhaaken@googlemail.com>
 * 	Matias De lellis <mati86dl@gmail.com>
 * 	Pavel Vasin <rat4vier@gmail.com>
 */


#include "taginfo.h"
#include "taginfo_internal.h"


using namespace TagInfo;


int disk_amount;

Mp4Info::Mp4Info(const String &filename) : Info(filename) {
    disk_amount = 1;
    if(!file_name.isEmpty() && !create_file_ref())
        printf("Error creating file ref! %s\n", filename.toCString(false));
    if(taglib_file) {
        mp4_tag = ((TagLib::MP4::File *) taglib_file)->tag();
        if(!mp4_tag || mp4_tag->isEmpty()) { // Use fallback for id3v1 or extended header
            if(!mp4_tag)
                printf("Mp4tag null for %s\n", filename.toCString(false));
            //printf("Use fallback! %s\n", filename.c_str());
            if(!taglib_tag)
                taglib_tag = taglib_file->tag();
            if(!taglib_tag) {
                taglib_fileref = new TagLib::FileRef(filename.toCString(false),
                                                     true, TagLib::AudioProperties::Fast);
                taglib_tag = taglib_fileref->tag();
            }
            if(!taglib_tag) {
                printf("Cant get tag object from '%s'\n", file_name.toCString(false));
                valid = false;
            }
        }
    }
    else {
        printf("2Cant get tag from '%s'\n", file_name.toCString(false));
        mp4_tag = NULL;
        valid = false;
    }
}


Mp4Info::~Mp4Info() {
}


bool Mp4Info::create_file_ref() {
    if(file_name.isEmpty())
        return false;
    taglib_file = new TagLib::MP4::File(file_name.toCString(false), true, TagLib::AudioProperties::Fast);
    if(taglib_file) {
        return true;
    }
    else {
        printf("TagLib::File creation failed for '%s'\n", file_name.toCString(false));
        return false;
    }
}


bool Mp4Info::read(void) {
    if(Info::read()) {
        if(mp4_tag && !mp4_tag->isEmpty()) {
            if(!taglib_tag)
                read_virtual_tags((TagLib::Tag *)mp4_tag);
            if(mp4_tag->itemListMap().contains("aART")) {
                album_artist = mp4_tag->itemListMap()["aART"].toStringList().front();
            }
            if(mp4_tag->itemListMap().contains("\xA9wrt")) {
                composer = mp4_tag->itemListMap()["\xa9wrt"].toStringList().front();
            }
            if(mp4_tag->itemListMap().contains("disk")) {
                disk_number = mp4_tag->itemListMap()["disk"].toIntPair().first;
                disk_amount = mp4_tag->itemListMap()["disk"].toIntPair().second;
                if(disk_number <= 0)
                    disk_number = 1;
                if(disk_amount < disk_number)
                    disk_amount = disk_number;
            }
            if(mp4_tag->itemListMap().contains("cpil")) {
                is_compilation = mp4_tag->itemListMap()["cpil"].toBool();
            }
            // Rating
            if(mp4_tag->itemListMap().contains("----:com.apple.iTunes:RATING")) {
                long rat = 0;
                rat = atol(mp4_tag->itemListMap()["----:com.apple.iTunes:RATING"].toStringList().front().toCString(true));
                if(rat) {
                    if(rat > 5) {
                        rating = popularity_to_rating(rat);
                    }
                    else {
                        rating = rat;
                    }
                }
            }
            if(mp4_tag->itemListMap().contains("----:com.apple.iTunes:PLAY_COUNTER")) {
                long PlayCount = 0;
                PlayCount = atol(mp4_tag->itemListMap()["----:com.apple.iTunes:PLAY_COUNTER"].toStringList().front().toCString(true));
                playcount = PlayCount;
            }
            // Labels
            if(track_labels.size() == 0) {
                if(mp4_tag->itemListMap().contains("----:com.apple.iTunes:TRACK_LABELS")) {
                    track_labels_string = mp4_tag->itemListMap()["----:com.apple.iTunes:TRACK_LABELS"].toStringList().front();
                    track_labels = split(track_labels_string, "|");
                }
            }
            if(artist_labels.size() == 0) {
                if(mp4_tag->itemListMap().contains("----:com.apple.iTunes:ARTIST_LABELS")) {
                    artist_labels_string = mp4_tag->itemListMap()["----:com.apple.iTunes:ARTIST_LABELS"].toStringList().front();
                    artist_labels = split(artist_labels_string, "|");
                }
            }
            if(album_labels.size() == 0) {
                if(mp4_tag->itemListMap().contains("----:com.apple.iTunes:ALBUM_LABELS")) {
                    album_labels_string = mp4_tag->itemListMap()["----:com.apple.iTunes:ALBUM_LABELS"].toStringList().front();
                    album_labels = split(album_labels_string, "|");
                }
            }
            if(mp4_tag->itemListMap().contains("covr")) {
                TagLib::MP4::CoverArtList covers = mp4_tag->itemListMap()[ "covr" ].toCoverArtList();
                has_image = (covers.size() > 0);
            }
            return true;
        }
    }
    return false;
}


void mp4_check_label_frame(TagLib::MP4::Tag * mp4tag, const char * description, const String &value) {
    if(mp4tag->itemListMap().contains(description)) {
            if(!value.isEmpty()) {
            mp4tag->itemListMap()[ description ] = TagLib::MP4::Item(TagLib::StringList(value));
        }
        else {
            mp4tag->itemListMap().erase(description);
        }
    }
    else {
            if(!value.isEmpty()) {
            mp4tag->itemListMap().insert(description, TagLib::MP4::Item(TagLib::StringList(value)));
        }
    }
}


bool Mp4Info::write(void) {
    if(mp4_tag) {
        if(changedflag) {
            if(changedflag & CHANGED_DATA_ALBUMARTIST)
                mp4_tag->itemListMap()["aART"] = TagLib::StringList(album_artist);
            if(changedflag & CHANGED_COMPOSER_TAG)
                mp4_tag->itemListMap()["\xA9wrt"] = TagLib::StringList(composer);
            if(changedflag & CHANGED_DATA_DISK_NUM) {
                if(disk_amount < disk_number)
                    disk_amount = disk_number;
                mp4_tag->itemListMap()["disk"] = TagLib::MP4::Item(disk_number, disk_amount);
            }
            if(changedflag & CHANGED_IS_COMPILATION_TAG)
                mp4_tag->itemListMap()["cpil"] = TagLib::MP4::Item(is_compilation);
            if(changedflag & CHANGED_DATA_RATING) {
                mp4_tag->itemListMap()["----:com.apple.iTunes:RATING" ] =
                    TagLib::MP4::Item(format("%u", rating_to_popularity(rating)));
                
            }
            if(changedflag & CHANGED_DATA_PLAYCOUNT) {
                mp4_tag->itemListMap()[ "----:com.apple.iTunes:PLAY_COUNTER" ] =
                    TagLib::MP4::Item(format("%u", playcount));
            }
            // The Labels
            if(changedflag & CHANGED_ARTIST_LABELS)
                mp4_check_label_frame(mp4_tag, "----:com.apple.iTunes:ARTIST_LABELS", artist_labels_string);
            if(changedflag & CHANGED_ALBUM_LABELS)
                mp4_check_label_frame(mp4_tag, "----:com.apple.iTunes:ALBUM_LABELS", album_labels_string);
            if(changedflag & CHANGED_TRACK_LABELS)
                mp4_check_label_frame(mp4_tag, "----:com.apple.iTunes:TRACK_LABELS", track_labels_string);
            
            write_virtual_tags((TagLib::Tag *)mp4_tag);
        }
    }
    return Info::write();
}

bool Mp4Info::can_handle_images(void) const {
    return true;
}

bool Mp4Info::get_image(char*& data, int &data_length, ImageType &image_type) const {
    if(mp4_tag) {
        return get_mp4_cover_art(mp4_tag, data, data_length, image_type);
    }
    return false;
}

bool Mp4Info::set_image(const char* data, int data_length, ImageType image_type) {
    if(mp4_tag) {
        return set_mp4_cover_art(mp4_tag, data, data_length, image_type);
    }
    return false;
}

bool Mp4Info::can_handle_lyrics(void) const {
    return true;
}


String Mp4Info::get_lyrics(void) const {
    return get_mp4_lyrics(mp4_tag);
}


bool Mp4Info::set_lyrics(const String &lyrics) {
    return set_mp4_lyrics(mp4_tag, lyrics);
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.