/* * Copyright (c) 2021, Cesar Torres * * SPDX-License-Identifier: BSD-2-Clause */ #include "M3UParser.h" #include #include #include #include #include M3UParser::M3UParser() { } NonnullOwnPtr M3UParser::from_file(const String path) { auto file_result = Core::File::open(path, Core::OpenMode::ReadOnly); VERIFY(!file_result.is_error()); auto contents = file_result.value()->read_all(); auto use_utf8 = path.ends_with(".m3u8", CaseSensitivity::CaseInsensitive); return from_memory(String { contents, NoChomp }, use_utf8); } NonnullOwnPtr M3UParser::from_memory(const String& m3u_contents, bool utf8) { auto parser = make(); VERIFY(!m3u_contents.is_null() && !m3u_contents.is_empty() && !m3u_contents.is_whitespace()); parser->m_m3u_raw_data = m3u_contents; parser->m_use_utf8 = utf8; return parser; } NonnullOwnPtr> M3UParser::parse(bool include_extended_info) { auto vec = make>(); if (m_use_utf8) { //TODO: Implement M3U8 parsing TODO(); return vec; } auto lines = m_m3u_raw_data.split_view('\n'); bool has_extended_info_tag = include_extended_info && (lines[0] == "#EXTM3U"); M3UExtendedInfo metadata_for_next_file {}; for (auto& line : lines) { line = line.trim_whitespace(); if (!has_extended_info_tag || !line.starts_with('#')) { vec->append({ line, metadata_for_next_file }); metadata_for_next_file = {}; continue; } auto tag = [&line](StringView tag_name) -> Optional { if (line.starts_with(tag_name)) { auto value = line.substring_view(tag_name.length()); VERIFY(!value.is_empty()); return value; } return {}; }; if (auto ext_inf = tag("#EXTINF:"); ext_inf.has_value()) { auto separator = ext_inf.value().find(','); VERIFY(separator.has_value()); auto seconds = ext_inf.value().substring_view(0, separator.value()); VERIFY(!seconds.is_whitespace() && !seconds.is_null() && !seconds.is_empty()); metadata_for_next_file.track_length_in_seconds = seconds.to_uint(); auto display_name = ext_inf.value().substring_view(seconds.length() + 1); VERIFY(!display_name.is_empty() && !display_name.is_null() && !display_name.is_empty()); metadata_for_next_file.track_display_title = display_name; //TODO: support the alternative, non-standard #EXTINF value of a key=value dictionary continue; } if (auto playlist = tag("#PLAYLIST:"); playlist.has_value()) m_parsed_playlist_title = move(playlist.value()); else if (auto ext_grp = tag("#EXTGRP:"); ext_grp.has_value()) metadata_for_next_file.group_name = move(ext_grp.value()); else if (auto ext_alb = tag("#EXTALB:"); ext_alb.has_value()) metadata_for_next_file.album_title = move(ext_alb.value()); else if (auto ext_art = tag("#EXTART:"); ext_art.has_value()) metadata_for_next_file.album_artist = move(ext_art.value()); else if (auto ext_genre = tag("#EXTGENRE:"); ext_genre.has_value()) metadata_for_next_file.album_genre = move(ext_genre.value()); //TODO: Support M3A files (M3U files with embedded mp3 files) } return vec; }