Skip to content

Instantly share code, notes, and snippets.

@richienyhus
Created March 17, 2013 15:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save richienyhus/5182083 to your computer and use it in GitHub Desktop.
Save richienyhus/5182083 to your computer and use it in GitHub Desktop.
Adds support to ArmyKnife for adding and viewing of cover art
Index: Makefile_armyknife_tte
===================================================================
--- Makefile_armyknife_tte (revision 63)
+++ Makefile_armyknife_tte (working copy)
@@ -45,7 +45,7 @@
DEFINES := -D_TTE_
# libraries
-SYS_LIBS := -lbe -lroot
+SYS_LIBS := -lbe -lroot -ltranslation
SRC_LIBS := -ltag -lsanta -ltracker
# directories
Index: source/armyknife/albumpictureview.h
===================================================================
--- source/armyknife/albumpictureview.h (revision 0)
+++ source/armyknife/albumpictureview.h (revision 0)
@@ -0,0 +1,35 @@
+#ifndef __ALBUM_PICTURE_VIEW_H__
+#define __ALBUM_PICTURE_VIEW_H__
+
+#include <TranslationUtils.h>
+#include <be/interface/View.h>
+
+#include <id3v2tag.h>
+#include <mpegfile.h>
+#include <id3v2frame.h>
+#include <id3v2header.h>
+#include <attachedpictureframe.h>
+
+class BBitmap;
+class BRect;
+class BFont;
+class BPath;
+
+class AlbumPictureView : public BView
+{
+ public:
+ AlbumPictureView(BRect frame, const char *name);
+ ~AlbumPictureView();
+ void UpdatePicture(const char* path);
+ void NoImage();
+ void Draw(BRect rect);
+ void SetPicture(const char* path);
+ virtual void MessageReceived(BMessage *message);
+ private:
+ void Clear();
+ bool ProcessRefs(BMessage *message);
+ BBitmap *m_bitmap;
+ bool m_attached_to_track;
+};
+
+#endif
Index: source/armyknife/entryrefitem.cpp
===================================================================
--- source/armyknife/entryrefitem.cpp (revision 63)
+++ source/armyknife/entryrefitem.cpp (working copy)
@@ -181,7 +181,7 @@
EntryRefItem::HasID3V2Tag()
{
PRINT(("EntryRefItem::HasID3V2Tag()\n"));
-
+
return m_has_id3v2;
}
Index: source/armyknife/editorview.cpp
===================================================================
--- source/armyknife/editorview.cpp (revision 63)
+++ source/armyknife/editorview.cpp (working copy)
@@ -18,6 +18,8 @@
#include <be/storage/Path.h>
#include <be/support/Debug.h>
#include <be/support/List.h>
+#include <Path.h>
+
#include "audioattributes.h"
#include "genrelist.h"
#include "id3tags.h"
@@ -28,6 +30,7 @@
#include "editorview.h"
#include "entryrefitem.h"
#include "guistrings.h"
+#include "albumpictureview.h"
EditorView::EditorView(BRect frame, Preferences * preferences)
: AddOnView (frame, EDITOR_MODE_NAME),
@@ -35,6 +38,7 @@
{
PRINT(("EditorView::EditorView(BRect)\n"));
+ m_album_picture_changed = false;
InitView();
}
@@ -54,7 +58,7 @@
BCheckBox cb(BRect(0,0,0,0),0,0,0);
cb.ResizeToPreferred();
-
+
m_attribute_radiobutton = new BRadioButton(BRect(0,0,0,0),0,ATTRIBUTES_LABEL,
new BMessage(RADIO_BUTTON_EVENT));
m_attribute_radiobutton->ResizeToPreferred();
@@ -64,7 +68,8 @@
new BMessage(RADIO_BUTTON_EVENT));
m_tag_radiobutton->ResizeToPreferred();
- m_apply_checkbox = new BCheckBox(BRect(0,0,0,0),0,APPLY_TO_ATTRIBUTES,new BMessage(MSG_APPLY_TO_BOTH));
+ m_apply_checkbox = new BCheckBox(BRect(0,0,0,0),0,APPLY_TO_ATTRIBUTES,
+ new BMessage(MSG_APPLY_TO_BOTH));
m_apply_checkbox->ResizeToPreferred();
m_apply_checkbox->SetValue(B_CONTROL_OFF);
m_apply_checkbox->SetLabel(APPLY_TO_TAGS);
@@ -94,10 +99,20 @@
m_tag_radiobutton->MoveBy(2*space+m_attribute_radiobutton->Frame().Width(),space);
m_apply_checkbox->MoveBy(space,2*space+m_attribute_radiobutton->Frame().Height());
+ m_picture_checkbox = new BCheckBox(BRect(0,0,0,0),0,"",
+ new BMessage(MSG_PICTURE_CHECKBOX));
+ m_picture_checkbox->ResizeToPreferred();
+ frame = m_picture_checkbox->Frame();
+ m_album_picture = new AlbumPictureView(BRect(0, 0, 160, 160), "bitmap_view");
+ // Has to be initialized here because of the layout
+
m_artist_checkbox = new BCheckBox(BRect(0,0,0,0),0,ARTIST_LABEL,
new BMessage(MSG_ARTIST_CHECKBOX));
m_artist_checkbox->ResizeToPreferred();
- frame = m_artist_checkbox->Frame();
+ if(m_artist_checkbox->Frame().Width() > frame.Width())
+ {
+ frame = m_artist_checkbox->Frame();
+ }
m_album_checkbox = new BCheckBox(BRect(0,0,0,0),0,ALBUM_LABEL,
new BMessage(MSG_ALBUM_CHECKBOX));
@@ -185,12 +200,17 @@
m_clear_all_checkbox->ResizeToPreferred();
if(m_clear_all_checkbox->Frame().Width() > frame.Width())
{
- frame = m_genre_checkbox->Frame();
+ frame = m_clear_all_checkbox->Frame();
}
+ // Set chekboxes' positions
float x,y;
x = space;
y = m_edit_box->Frame().bottom + 2*space;
+ m_picture_checkbox->MoveTo(x,y + m_album_picture->Bounds().Height() / 2 -
+ m_picture_checkbox->Bounds().Height() / 2);
+ m_album_picture->MoveTo(x + m_picture_checkbox->Frame().Width(),y);
+ y += m_album_picture->Bounds().Height() + space;
m_artist_checkbox->MoveTo(x,y);
y += frame.Height() + space;
m_album_checkbox->MoveTo(x,y);
@@ -291,6 +311,9 @@
ResizeToPreferred();
PRINT_OBJECT(Frame());
+
+ AddChild(m_picture_checkbox);
+ AddChild(m_album_picture);
AddChild(m_artist_checkbox);
AddChild(m_artist_textcontrol);
@@ -399,6 +422,7 @@
EditorView::SelectionChanged(BList* list)
{
AddOnView::SelectionChanged(list);
+ m_album_picture_changed = false;
PRINT(("EditorView::SelectionChanged(BList* list)\n"));
@@ -474,6 +498,8 @@
int numSelected = m_selected_items->CountItems();
if (numSelected == 0 || m_list_view->HasSelectionOfOnlyAcceptedItems() == false)
{
+ m_album_picture->NoImage();
+ m_picture_checkbox->SetValue(B_CONTROL_OFF);
m_artist_checkbox->SetValue(B_CONTROL_OFF);
m_album_checkbox->SetValue(B_CONTROL_OFF);
m_title_checkbox->SetValue(B_CONTROL_OFF);
@@ -490,6 +516,7 @@
}
else if(numSelected == 1)
{
+ m_picture_checkbox->SetValue(B_CONTROL_ON);
m_artist_checkbox->SetValue(B_CONTROL_ON);
m_album_checkbox->SetValue(B_CONTROL_ON);
m_title_checkbox->SetValue(B_CONTROL_ON);
@@ -506,6 +533,7 @@
}
else if(numSelected > 1)
{
+ m_picture_checkbox->SetValue(B_CONTROL_ON);
m_artist_checkbox->SetValue(B_CONTROL_ON);
m_album_checkbox->SetValue(B_CONTROL_ON);
m_title_checkbox->SetValue(B_CONTROL_OFF);
@@ -524,7 +552,7 @@
if(numSelected > 0)
{
EntryRefItem* item = (EntryRefItem*)m_selected_items->ItemAt(0);
-
+
const char* artist;
const char* album;
const char* title;
@@ -543,6 +571,8 @@
if(m_attribute_radiobutton->Value() == B_CONTROL_ON)
{
+ m_picture_checkbox->SetValue(B_CONTROL_OFF);
+ m_album_picture->NoImage();
AudioAttributes attributes(& audioFile);
artist = attributes.Artist();
if(!artist)
@@ -635,6 +665,15 @@
}
else if(item->IsSupportedByTaglib())
{
+ // Add album art
+ BPath filePath;
+ BEntry *entry = new BEntry(item->EntryRef());
+ if (item->IsMP3() && entry->GetPath(&filePath) == B_OK)
+ {
+ m_album_picture->UpdatePicture(filePath.Path());
+ }
+ delete entry;
+
ID3Tags tags(item);
artist = tags.Artist();
@@ -727,6 +766,8 @@
int numSelected = m_selected_items->CountItems();
if (numSelected == 0 || m_list_view->HasSelectionOfOnlyAcceptedItems() == false)
{
+ m_album_picture->NoImage();
+ m_picture_checkbox->SetEnabled(false);
m_artist_checkbox->SetEnabled(false);
m_album_checkbox->SetEnabled(false);
m_title_checkbox->SetEnabled(false);
@@ -758,6 +799,7 @@
}
else if(numSelected > 0)
{
+ m_picture_checkbox->SetEnabled(true);
m_artist_checkbox->SetEnabled(true);
m_album_checkbox->SetEnabled(true);
m_title_checkbox->SetEnabled(true);
@@ -774,6 +816,11 @@
m_track_textcontrol->SetEnabled(true);
m_genre_menufield->SetEnabled(true);
m_genre_textcontrol->SetEnabled(true);
+
+ if(m_attribute_radiobutton->Value() == B_CONTROL_ON)
+ m_picture_checkbox->SetEnabled(false);
+ else
+ m_picture_checkbox->SetEnabled(true);
#ifdef _TTE_
if(m_attribute_radiobutton->Value() == B_CONTROL_ON)
@@ -992,6 +1039,16 @@
if(doTags && refItem->IsSupportedByTaglib())
{
+ if (view->m_picture_checkbox->Value() == B_CONTROL_ON)
+ {
+ BPath filePath;
+ BEntry *entry = new BEntry(refItem->EntryRef());
+ if (refItem->IsMP3() && entry->GetPath(&filePath) == B_OK)
+ {
+ view->m_album_picture->SetPicture(filePath.Path());
+ }
+ delete entry;
+ }
ID3Tags tags(refItem);
if(view->m_artist_checkbox->Value() == B_CONTROL_ON)
{
@@ -1136,6 +1193,7 @@
void
EditorView::CheckAllBoxes(int32 value)
{
+ m_picture_checkbox->SetValue(value);
m_artist_checkbox->SetValue(value);
m_album_checkbox->SetValue(value);
m_title_checkbox->SetValue(value);
Index: source/armyknife/albumpictureview.cpp
===================================================================
--- source/armyknife/albumpictureview.cpp (revision 0)
+++ source/armyknife/albumpictureview.cpp (revision 0)
@@ -0,0 +1,272 @@
+#include "albumpictureview.h"
+
+#include <be/interface/Rect.h>
+#include <be/interface/Font.h>
+#include <be/interface/Bitmap.h>
+#include <be/translation/TranslatorRoster.h>
+#include <be/translation/BitmapStream.h>
+#include <be/storage/Path.h>
+
+#include "entryrefitem.h"
+
+AlbumPictureView::AlbumPictureView(BRect frame, const char *name)
+ : BView(frame, name, B_FOLLOW_H_CENTER, B_WILL_DRAW)
+{
+ m_attached_to_track = false;
+ NoImage();
+}
+
+AlbumPictureView::~AlbumPictureView()
+{
+}
+
+
+void
+AlbumPictureView::MessageReceived(BMessage *message)
+{
+ switch (message->what)
+ {
+ case B_REFS_RECEIVED:
+ // Supposed to fallthrough
+ case B_SIMPLE_DATA:
+ // If there wasn't just one image, we pass it further
+ if (ProcessRefs(message))
+ break;
+ default:
+ BView::MessageReceived(message);
+ }
+}
+
+
+// Get image from the message and load it.
+// If there is more than one file passed (or no files)
+// or some error occured return false.
+bool
+AlbumPictureView::ProcessRefs(BMessage *message)
+{
+ // Count number of files passed.
+ // If it does not equal one, return false
+ int32 refCount;
+ message->GetInfo("refs", NULL, &refCount);
+ if (refCount != 1)
+ return false;
+
+ // Find first item in the refs list and
+ // load it if it is a picture
+ // or return false otherwise
+ entry_ref tempRef;
+ delete m_bitmap;
+ m_bitmap = NULL;
+ BPath filePath;
+
+ if (message->FindRef("refs", &tempRef) == B_NO_ERROR &&
+ BEntry(&tempRef).GetPath(&filePath) == B_OK &&
+ (m_bitmap = BTranslationUtils::GetBitmap(filePath.Path())) != NULL)
+ {
+ // Draw only if we a track is chosen in the list
+ if (m_attached_to_track)
+ DrawBitmap(m_bitmap, BRect(0, 0,
+ Bounds().Width(),
+ Bounds().Height()));
+ return true;
+ }
+ return false;
+}
+
+
+void
+AlbumPictureView::Draw(BRect rect)
+{
+ Clear();
+ if (m_bitmap != NULL)
+ DrawBitmap(m_bitmap, BRect(0, 0,
+ Bounds().Width(),
+ Bounds().Height()));
+ else
+ NoImage();
+}
+
+
+// Clears the image
+void
+AlbumPictureView::Clear()
+{
+ SetHighColor(255,255,255);
+ FillRect(Bounds());
+}
+
+
+// Sets album picture for the file specified
+void
+AlbumPictureView::SetPicture(const char *path)
+{
+ if (m_bitmap == NULL)
+ return;
+
+ TagLib::MPEG::File file(path);
+ TagLib::ID3v2::Tag *fileTags = file.ID3v2Tag();
+ TagLib::ID3v2::FrameList foundFrames = fileTags->frameList("APIC");
+
+ // Delete all the covers in this file
+ if (!foundFrames.isEmpty())
+ {
+ TagLib::ID3v2::FrameList::ConstIterator it = foundFrames.begin();
+ for (;it != foundFrames.end(); ++it)
+ {
+ TagLib::ID3v2::AttachedPictureFrame *currentFrame =
+ static_cast<TagLib::ID3v2::AttachedPictureFrame *>(*it);
+
+ if (currentFrame->type() ==
+ TagLib::ID3v2::AttachedPictureFrame::FrontCover)
+ fileTags->removeFrame(currentFrame, true);
+ }
+ }
+
+ // Find the translator type that suits us
+ BTranslatorRoster *roster = BTranslatorRoster::Default();
+ translator_id *translators;
+ int32 numTranslators;
+ uint32 foundType = 0;
+ const char *mimeName = "image/jpeg";
+
+ roster->GetAllTranslators(&translators, &numTranslators);
+
+ for (int32 i = 0; i < numTranslators && foundType == 0; ++i)
+ {
+ const translation_format *formats;
+ int32 numFormats;
+
+ roster->GetOutputFormats(translators[i], &formats, &numFormats);
+
+ for (int32 j = 0; j < numFormats && foundType == 0; ++j)
+ {
+ if (!strcasecmp(formats[j].MIME, mimeName))
+ foundType = formats[j].type;
+ }
+ }
+
+ // Convert bitmap to jpeg
+ BMallocIO *buffer = new BMallocIO();
+ BBitmapStream *stream = new BBitmapStream(m_bitmap);
+ roster->Translate(stream, NULL, NULL, buffer, foundType);
+
+ // Write jpeg to tags and save the file
+ TagLib::ID3v2::AttachedPictureFrame *pictureFrame =
+ new TagLib::ID3v2::AttachedPictureFrame();
+ pictureFrame->setMimeType(mimeName);
+ pictureFrame->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
+ pictureFrame->setPicture(
+ TagLib::ByteVector(static_cast<char*>(buffer->Buffer()), buffer->BufferLength() + 1));
+ printf("drag:%i\n", fileTags->frameList("APIC").size());
+ fileTags->addFrame(pictureFrame);
+ printf("drag:%i\n", fileTags->frameList("APIC").size());
+ file.save();
+
+ delete buffer;
+}
+
+
+// Loads album art for the song, path to which is specified
+void
+AlbumPictureView::UpdatePicture(const char *path)
+{
+ Clear();
+ if (path == NULL)
+ {
+ NoImage();
+ return;
+ }
+ bool success = true;
+ const char *pictureTagIdName = "APIC";
+ TagLib::MPEG::File file(path);
+ TagLib::ID3v2::Tag *fileTags = file.ID3v2Tag();
+ TagLib::ID3v2::FrameList frame;
+ TagLib::ID3v2::AttachedPictureFrame *pictureFrame = NULL;
+
+ if (fileTags != NULL)
+ {
+ // Find frame containing pictures
+ frame = fileTags->frameList(pictureTagIdName);
+ if (!frame.isEmpty())
+ {
+ // Search for the album image
+ // (one frame can contain multiple images)
+ TagLib::ID3v2::FrameList::ConstIterator it = frame.begin();
+ for (;it != frame.end(); ++it)
+ {
+ TagLib::ID3v2::AttachedPictureFrame *currentFrame =
+ static_cast<TagLib::ID3v2::AttachedPictureFrame *>(*it);
+ if (currentFrame->type() ==
+ TagLib::ID3v2::AttachedPictureFrame::FrontCover)
+ pictureFrame = currentFrame;
+ }
+ if (pictureFrame != NULL)
+ {
+ // WARNING: HACK
+ // This loop is needed because
+ // sometimes the image cannot be loaded
+ // in first few runs (idk why that happens)
+ // P.S. It still fails sometimes
+ delete m_bitmap;
+ m_bitmap = NULL;
+ const uint32 maxCount = 50;
+ for (int counter = 0; counter < maxCount && m_bitmap == NULL;
+ ++counter)
+ {
+ delete m_bitmap;
+
+ BMemoryIO *memStream = new BMemoryIO(
+ pictureFrame->picture().data(),
+ pictureFrame->picture().size());
+
+ m_bitmap = BTranslationUtils::GetBitmap(memStream);
+
+ delete memStream;
+ }
+ if (m_bitmap != NULL)
+ {
+ DrawBitmap(m_bitmap,
+ BRect(0,0,
+ Bounds().Width(),
+ Bounds().Height()));
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ if (!success)
+ {
+ NoImage();
+ }
+ m_attached_to_track = true;
+}
+
+// Notify user that track does not contain artwork
+void
+AlbumPictureView::NoImage()
+{
+ delete m_bitmap;
+ m_bitmap = NULL;
+ Clear();
+ SetHighColor(0,0,0);
+ BFont font;
+ font.SetSize(12.0);
+ SetFont(&font);
+
+ const char* noImageText = "No image";
+ DrawString(noImageText,
+ BPoint(Bounds().Width() / 2 - StringWidth(noImageText) / 2,
+ Bounds().Height() / 2));
+ m_attached_to_track = false;
+}
Index: source/armyknife/id3tag.cpp
===================================================================
--- source/armyknife/id3tag.cpp (revision 63)
+++ source/armyknife/id3tag.cpp (working copy)
@@ -64,12 +64,10 @@
case YEAR_TAG:
m_value.Truncate(0);
m_value << m_tag->year(); // t->setYear(value.toInt());
- printf("ID3Tag::Read() value << tag->year(); value.String():%s\n", m_value.String());
break;
case TRACK_TAG:
m_value.Truncate(0);
m_value << m_tag->track(); // t->setTrack(value.toInt());
- printf("ID3Tag::Read() value << tag->track(); value.String():%s\n", m_value.String());
break;
default:
break;
@@ -95,8 +93,6 @@
UTF8 = 3
};
-// TagLib::String::Type type = UTF8;
-
TagLib::String string (m_value.String(), (TagLib::String::Type) 3); // 3 = UTF8
switch (m_tag_item)
@@ -117,12 +113,7 @@
m_tag->setGenre(string);
break;
case YEAR_TAG:
- PRINT(("ID3Tag::Write() *** value.String(): %s\n", m_value.String()));
- PRINT(("ID3Tag::Write() *** tag->year(): %u\n", m_tag->year()));
- PRINT(("ID3Tag::Write() *** tag->year(): %u\n", m_tag->year()));
m_tag->setYear(atoi(m_value.String()));
- PRINT(("ID3Tag::Write() atoi(value.String(): %ld\n", atoi(m_value.String())));
- PRINT(("ID3Tag::Write() *** tag->year(): %u\n", m_tag->year()));
break;
case TRACK_TAG:
m_tag->setTrack(atoi(m_value.String()));
Index: source/armyknife/appview.cpp
===================================================================
--- source/armyknife/appview.cpp (revision 63)
+++ source/armyknife/appview.cpp (working copy)
@@ -112,24 +112,28 @@
BRect inframe = m_pick_list_view->BoxBounds();
AddOnView * aView;
+ // Edit view
aView = new EditorView(inframe, m_preferences);
if (aView->InitCheck() == B_OK)
m_pick_list_view->AddView(aView);
else
delete aView;
+ // Copy view
aView = new TAView(inframe, m_preferences);
if (aView->InitCheck() == B_OK)
m_pick_list_view->AddView(aView);
else
delete aView;
+ // Name view
aView = new NAView(inframe, m_preferences);
if (aView->InitCheck() == B_OK)
m_pick_list_view->AddView(aView);
else
delete aView;
+ // MPEG view
aView = new MPEGView(inframe, m_preferences);
if (aView->InitCheck() == B_OK)
m_pick_list_view->AddView(aView);
Index: source/armyknife/armyknife.rsrc
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: source/armyknife/commandconstants.h
===================================================================
--- source/armyknife/commandconstants.h (revision 63)
+++ source/armyknife/commandconstants.h (working copy)
@@ -15,6 +15,7 @@
#define MSG_APPLY_TO_BOTH '012'
#define MSG_CLEAR_LIST '013'
+#define MSG_PICTURE_CHECKBOX '015'
#define MSG_ARTIST_CHECKBOX '016'
#define MSG_ALBUM_CHECKBOX '017'
#define MSG_TITLE_CHECKBOX '020'
Index: source/armyknife/editorview.h
===================================================================
--- source/armyknife/editorview.h (revision 63)
+++ source/armyknife/editorview.h (working copy)
@@ -3,6 +3,7 @@
#include "addonview.h"
#include "preferences.h"
+#include "albumpictureview.h"
class BCheckBox;
class BList;
@@ -37,15 +38,18 @@
void WidgetsSetValues();
void WidgetsSetEnabled();
void WidgetsRBValues();
+
+ AlbumPictureView* m_album_picture;
BRadioButton* m_tag_radiobutton;
BRadioButton* m_attribute_radiobutton;
BCheckBox* m_apply_checkbox;
+ BCheckBox* m_picture_checkbox;
BCheckBox* m_artist_checkbox;
BCheckBox* m_album_checkbox;
BCheckBox* m_title_checkbox;
BCheckBox* m_year_checkbox;
- BCheckBox* m_comment_checkbox;
+ BCheckBox* m_comment_checkbox;
BCheckBox* m_track_checkbox;
BCheckBox* m_genre_checkbox;
#ifdef _TTE_
@@ -73,7 +77,9 @@
BBox* m_edit_box;
BBox* m_genre_box;
- Preferences * m_preferences;
+ bool m_album_picture_changed;
+
+ Preferences * m_preferences;
};
#endif
Index: source/armyknife/armyknife_tte.rsrc
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: Makefile_armyknife
===================================================================
--- Makefile_armyknife (revision 63)
+++ Makefile_armyknife (working copy)
@@ -45,7 +45,7 @@
#DEFINES :=
# libraries
-SYS_LIBS := -lbe -lroot
+SYS_LIBS := -lbe -lroot -ltranslation
SRC_LIBS := -ltag -lsanta -ltracker
# directories
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment