[Metadata] Add getSyncLyrics to MetadataHandle 23/248423/3
authorPiotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics <p.kosko@samsung.com>
Thu, 26 Nov 2020 08:55:11 +0000 (09:55 +0100)
committerPiotr Kosko <p.kosko@samsung.com>
Wed, 9 Dec 2020 06:03:07 +0000 (06:03 +0000)
[ACR] https://code.sec.samsung.net/jira/browse/TWDAPI-271

[Verification] Code compiles withotu errors.
Works well for mp3 file with SYLT data.

// Prectondition - file preparation (with python code)
// important - SYLT need to be UTF-8 or ISO-8859 encoded to be supported on Tizen device
from mutagen.id3 import ID3, SYLT, Encoding

tag = ID3("sample.mp3")
sync_lrc = [("TEST lyrics 1", 100),
            ("another TEST lyrics - 2", 2000),
            ("yet another TEST lyrics", 4000)]  # [(lrc, millisecond), ]
tag.setall("SYLT", [SYLT(encoding=Encoding.UTF8, lang='eng', format=2, type=1, text=sync_lrc)])
tag.save()

tag.getall("SYLT")

// then push file to device

// then run below code in chrome console
var path = "videos/sample.mp3";
var fileHandle = tizen.metadata.createFileHandle(path);
var lyrics_num = fileHandle.get("SYNCLYRICS_NUM");

for (var i = 0; i < lyrics_num; ++i) {
    var lyrics = fileHandle.getSyncLyrics(i);
    console.log("Lyrics " + i + " (" + lyrics.timestamp  + "ms): " + lyrics.lyrics);
}

// expected return be like
console-via-logger.js:173 Lyrics 0 (100ms): TEST lyrics 1
console-via-logger.js:173 Lyrics 1 (2000ms): another TEST lyrics - 2
console-via-logger.js:173 Lyrics 2 (4000ms): yet another TEST lyrics

Change-Id: I01a502f40655532a37fc4055480e35826bb7a697

src/metadata/metadata_api.js
src/metadata/metadata_file_handle.cc
src/metadata/metadata_file_handle.h
src/metadata/metadata_instance.cc
src/metadata/metadata_instance.h

index 236b758e5951c504ed6e3b04fd2f68459b4beb42..6126c4a22e2702ceb5d7a1e43f2cd5d6bcee7bff 100755 (executable)
@@ -195,5 +195,30 @@ MetadataFileHandle.prototype.getFrameAtTime = function() {
     return new Blob([encodedData]);
 };
 
+MetadataFileHandle.prototype.getSyncLyrics = function() {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'index', type: types_.UNSIGNED_LONG }
+    ]);
+
+    var data = {
+        uri: this.uri,
+        id: this._id,
+        index: args.index
+    };
+
+    var result = native_.callSync('MetadataFileHandleGetSyncLyrics', data);
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
+    return new MetadataSyncLyrics(native_.getResultObject(result));
+};
+
+function MetadataSyncLyrics(data) {
+    Object.defineProperties(this, {
+        timestamp: { value: data.timestamp, writable: false, enumerable: true },
+        lyrics: { value: data.lyrics, writable: false, enumerable: true }
+    });
+}
+
 // Exports
 exports = new MetadataManager();
index b3d97613a458f23d39a97fb955f0be2890b9b9f5..2dfe00209320b673e2060f66e2aeb3e8b5747edc 100644 (file)
@@ -107,13 +107,13 @@ std::string convertUriToPath(const std::string& str) {
   }
 }
 
-MetadataFileHandle::MetadataFileHandle(int id) : handle_(nullptr), id_(id), width_(0), height_(0) {
+MetadataFileHandle::MetadataFileHandle(int id) : handle_(nullptr), id_(id), width_(0), height_(0), lyrics_num_(0) {
   ScopeLogger();
 }
 
 // 'this' owns a handle_, and uri_ and invalidates 'o'
 MetadataFileHandle::MetadataFileHandle(MetadataFileHandle&& o)
-    : handle_(nullptr), id_(o.id_), uri_(std::move(o.uri_)), width_(0), height_(0) {
+    : handle_(nullptr), id_(o.id_), uri_(std::move(o.uri_)), width_(0), height_(0), lyrics_num_(0) {
   ScopeLogger();
   handle_ = o.handle_;
   o.handle_ = nullptr;
@@ -128,6 +128,7 @@ MetadataFileHandle& MetadataFileHandle::operator=(MetadataFileHandle&& o) {
   uri_ = std::move(o.uri_);
   width_ = o.width_;
   height_ = o.height_;
+  lyrics_num_ = o.lyrics_num_;
   return *this;
 }
 
@@ -363,5 +364,51 @@ PlatformResult MetadataFileHandle::GetFrame(const unsigned long timestamp, const
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
+PlatformResult MetadataFileHandle::InitSyncLyricsNum() {
+  ScopeLogger();
+  if (0 == lyrics_num_) {
+    char* value = nullptr;
+    int native_res = metadata_extractor_get_metadata(handle_, METADATA_SYNCLYRICS_NUM, &value);
+    if (METADATA_EXTRACTOR_ERROR_NONE != native_res) {
+      LoggerE("Error during getting lyrics number: %d", native_res);
+      return convertErrorCode(native_res);
+    }
+    lyrics_num_ = (unsigned long)atoi(value);
+    free(value);
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult MetadataFileHandle::GetSyncLyrics(const unsigned long index,
+                                                 unsigned long* timestamp,
+                                                 std::string* lyrics_string) {
+  ScopeLogger();
+  char* lyrics = nullptr;
+  SCOPE_EXIT {
+    free(lyrics);
+  };
+
+  auto ret = InitSyncLyricsNum();
+  if (!ret) {
+    return ret;
+  }
+
+  // validation of input index (available values are <0; lyrics_num -1>)
+  if (index >= lyrics_num_) {
+    std::string message = "Invalid lyrics index: " + std::to_string(index);
+    return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, message.c_str());
+  }
+
+  int native_res = metadata_extractor_get_synclyrics(handle_, index, timestamp, &lyrics);
+  if (METADATA_EXTRACTOR_ERROR_NONE != native_res) {
+    LoggerE("Error during getting sync lyrics: %d", native_res);
+    return convertErrorCode(native_res);
+  }
+  if (lyrics) {
+    *lyrics_string = lyrics;
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
 }  // namespace metadata
 }  // namespace extension
index 2bcd8d03497f3f3cd5efcbcc41e600d527071d05..f0136b04957183adb7dc38bf30543f90e2c69ebd 100644 (file)
@@ -42,9 +42,12 @@ class MetadataFileHandle {
   common::PlatformResult GetFrame(std::vector<std::uint8_t>* frame_array);
   common::PlatformResult GetFrame(const unsigned long timestamp, const bool is_accurate,
                                   std::vector<std::uint8_t>* frame_array);
+  common::PlatformResult GetSyncLyrics(const unsigned long index, unsigned long* timestamp,
+                                       std::string* lyrics_string);
 
  private:
   common::PlatformResult InitWidthHeight();
+  common::PlatformResult InitSyncLyricsNum();
   common::PlatformResult EncodeJPEG(unsigned char* frame, size_t frame_size,
                                     std::uint8_t** uint8_frame, size_t* buffer_size);
 
@@ -54,6 +57,7 @@ class MetadataFileHandle {
 
   unsigned int width_;
   unsigned int height_;
+  unsigned int lyrics_num_;
 };
 
 }  // namespace metadata
index 49e1cd62e822cc10555f733946eb1f1316fc1d35..eb8c02eb7a127b87b55b73063e71c14ea8233a4e 100644 (file)
@@ -37,6 +37,7 @@ MetadataInstance::MetadataInstance() : next_handle_id_(1) {
   REGISTER_METHOD(MetadataFileHandleGetArtwork);
   REGISTER_METHOD(MetadataFileHandleGetThumbnailFrame);
   REGISTER_METHOD(MetadataFileHandleGetFrameAtTime);
+  REGISTER_METHOD(MetadataFileHandleGetSyncLyrics);
   REGISTER_METHOD(MetadataFileHandleRelease);
 #undef REGISTER_METHOD
 }
@@ -242,6 +243,49 @@ void MetadataInstance::MetadataFileHandleGetFrameAtTime(const picojson::value& a
   ReportSuccess(picojson::value(result_frame), out);
 }
 
+picojson::value getSyncLyricsJSON(const unsigned long timestamp, const std::string& lyrics) {
+  ScopeLogger();
+  picojson::value result = picojson::value(picojson::object());
+  picojson::object& result_obj = result.get<picojson::object>();
+  result_obj.insert(std::make_pair("timestamp", picojson::value((double)timestamp)));
+  result_obj.insert(std::make_pair("lyrics", picojson::value(lyrics)));
+
+  return result;
+}
+
+void MetadataInstance::MetadataFileHandleGetSyncLyrics(const picojson::value& args,
+                                                       picojson::object& out) {
+  ScopeLogger();
+  const std::string& uri = args.get("uri").get<std::string>();
+  const int id = static_cast<int>(args.get("id").get<double>());
+  const unsigned long index = static_cast<unsigned long>(args.get("index").get<double>());
+
+  auto res = InitializeHandleIfNeeded(uri, id);
+  if (!res) {
+    LogAndReportError(res, &out);
+    return;
+  }
+
+  unsigned long timestamp = 0;
+  std::string lyrics;
+  try {
+    MetadataFileHandle& m = handles_map_.at(id);
+
+    auto res = m.GetSyncLyrics(index, &timestamp, &lyrics);
+    if (!res) {
+      LogAndReportError(res, &out);
+      return;
+    }
+  } catch (...) {
+    // this should never happen
+    LogAndReportError(
+        PlatformResult(ErrorCode::ABORT_ERR, "Unknown error during accessing a file."), &out);
+    return;
+  }
+
+  ReportSuccess(getSyncLyricsJSON(timestamp, lyrics), out);
+}
+
 void MetadataInstance::MetadataFileHandleRelease(const picojson::value& args,
                                                  picojson::object& out) {
   ScopeLogger();
index 26a3f4997fb7ac01b92fc28e5a18843dfed17740..61dd760b59771f3c6be766ec71b00139da69d498 100644 (file)
@@ -35,6 +35,7 @@ class MetadataInstance : public common::ParsedInstance {
   void MetadataFileHandleGetArtwork(const picojson::value& args, picojson::object& out);
   void MetadataFileHandleGetThumbnailFrame(const picojson::value& args, picojson::object& out);
   void MetadataFileHandleGetFrameAtTime(const picojson::value& args, picojson::object& out);
+  void MetadataFileHandleGetSyncLyrics(const picojson::value& args, picojson::object& out);
   void MetadataFileHandleRelease(const picojson::value& args, picojson::object& out);
 
   std::map<int, MetadataFileHandle> handles_map_;