Archive / / / / PlaySource.cc
2008-10-21 13:50:16 UTC
previous next
/* Echo Media Player * Copyright (C) 2008 Shane O'Connell * * [ The original file includes a copyright header in this location describing * the file as being released under the terms of the GNU General Public * License. It has been removed in order to display the file as part of the * archive. ] */ #include "PlaySource.h" #include <mpegfile.h> #include <tag.h> using namespace std; int ModPlaySource::insert_from_uris(int index, const list<string>& uris) { int tracks_added = 0; for (list<string>::const_iterator iter = uris.begin(); iter != uris.end(); iter++) tracks_added += insert_from_uri(index, *iter); return tracks_added; } int ModPlaySource::insert_from_uri(int index, const string& uri, bool playlists_ok, bool directories_ok) { // TODO set PlaySource to be readonly before this call and unset it after? // (this may or may not be necessary.. need to think about it) while (Glib::MainContext::get_default()->pending()) Glib::MainContext::get_default()->iteration(false); int tracks_added = 0; try { Glib::RefPtr<Gio::File> file = Gio::File::create_for_uri(uri); Glib::RefPtr<Gio::FileInfo> file_info = file->query_info("standard::type,standard::fast-content-type"); if (directories_ok && file_info->get_file_type() == Gio::FILE_TYPE_DIRECTORY) { Glib::RefPtr<Gio::FileEnumerator> children = file->enumerate_children("standard::display-name"); Glib::RefPtr<Gio::FileInfo> child; list<Glib::ustring> child_names; while (child = children->next_file()) child_names.push_back(child->get_display_name()); child_names.sort(caseless_sort); for (list<Glib::ustring>::iterator iter = child_names.begin(); iter != child_names.end(); iter++) { if (iter->size() >= 1 && iter->at(0) != '.') { // TODO add some kind of protection against infinitely recursive directories int tracks_added_from_child = insert_from_uri(index, file->get_child_for_display_name(*iter)->get_uri(), false, true); tracks_added += tracks_added_from_child; index += tracks_added_from_child; } } } else { string content_type = file_info->get_attribute_string("standard::fast-content-type"); if (playlists_ok && content_type == "audio/x-mpegurl") { // M3U playlist tracks_added += insert_m3u_playlist(index, file); } else if (file->is_native() && content_type == "audio/mpeg") // MP3 { // TODO trim whitespace at either side of the mp3 title/artist/album etc. TagLib::MPEG::File file_tags(file->get_path().c_str()); TrackRef track = TrackRef(new Track( uri, file_tags.tag()->title().to8Bit(true), file_tags.tag()->artist().to8Bit(true), file_tags.tag()->album().to8Bit(true), file_tags.tag()->track())); // TODO make sure tags are okay before accepting // if they aren't okay use the filename as the title insert_track(index, track); tracks_added++; } } } catch (Gio::Error e) { // TODO show error message to user when this happens return tracks_added; } return tracks_added; } int ModPlaySource::insert_m3u_playlist(int index, Glib::RefPtr<Gio::File> file) { int tracks_added = 0; char buf[512]; int buf_filled = 0; int offset = 0; string line = ""; string ext_line = ""; Glib::RefPtr<Gio::FileInputStream> stream = file->read(); buf_filled = stream->read(buf, 512); if (buf_filled < 0) throw Gio::Error(Gio::Error::FAILED, "read() returned -1"); if (buf_filled == 0) return 0; // I guess this is an empty file? while (true) { int line_end; for (line_end = offset; buf[line_end] != '\n' && buf[line_end] != '\r' && line_end < buf_filled; line_end++); line.append(buf + offset, line_end - offset); if (line_end >= buf_filled) { buf_filled = stream->read(buf, 512); if (buf_filled < 0) throw Gio::Error(Gio::Error::FAILED, "read() returned -1"); if (buf_filled == 0) break; offset = 0; } else { // ------------------- Start processing this line --------------------- if (line.substr(0, 8) == "#EXTINF:") { ext_line = line; } else if (line.substr(0, 1) != "#" && line.size() != 0) { Glib::ustring title; if (ext_line.size() > 0) { int comma = ext_line.find(','); string time = ext_line.substr(8, comma - 8); title = ext_line.substr(comma + 1, ext_line.size() - (comma + 1)); ext_line = ""; } else { title = line; } int tracks_added_from_line = insert_from_uri(index, line, false, false); if (tracks_added_from_line) { // TODO keep M3UEXT info if the file doesn't have tag information index += tracks_added_from_line; tracks_added += tracks_added_from_line; } else { // TODO show a better error message title = string("Error reading: ") + title; insert_track(index, TrackRef(new Track(line, title, "", "", -1))); tracks_added++; } } // ----------------- Finished processing this line -------------- line = ""; // Move to next line for(offset = line_end; (buf[offset] == '\n' || buf[offset] == '\r') && offset < buf_filled; offset++); if (offset >= buf_filled) { buf_filled = stream->read(buf, 512); if (buf_filled < 0) throw Gio::Error(Gio::Error::FAILED, "read() returned -1"); if (buf_filled == 0) break; offset = 0; } } } return tracks_added; }