我们能否在派生自 Cloud Firestore 的 Dart [Flutter] 中检索添加了 Duration 的相同更新媒体项?

Can we retrieve the same updated media item with added Duration in Dart [Flutter] which is derived from Cloud Firestore?

我对 Flutter 中 Dart 包的 [audio_service][1] 有疑问。它无法读取当前 MediaItem 的持续时间。正如其官方文档 [此处][2] 中所写,我们被要求创建一个新的 MediaItem 来存储复制的持续时间。如果我们不这样做,那么我们将无法在 [audio_service][1] 播放歌曲时保持进度条。我的意思是,如果它没有歌曲的持续时间值,如果用户点击暂停按钮或停止按钮,它将打破进度条。

现在,我想到了另一种选择来保留持续时间数据。 我使用 [flutter_ffmpeg][3] 及其包之一来读取字符串中的持续时间。然后使用这些代码将 String 转换为 Duration:

Future<MediaItem> addDuration(File myAudio) async {
    late final MediaItem songInfo;
    String duration = "";
    await readAudio(myAudio).then((value) => duration = value);
    durSong = parseDuration(duration);
    songInfo.copyWith(duration: durSong);
    log("Duration is $durSong");
    log("The current duration for ${songInfo.title} is ${songInfo.duration}");
    return songInfo;
  }

Future<String> readAudio(File audio) async {
    final FlutterFFprobe durReader = FlutterFFprobe();
    String duration = "";
    await durReader.getMediaInformation(audio.path).then((value) => duration = value.getMediaProperties()!["duration"]);
    return duration;
  }

Duration parseDuration(String s) {
    int hours = 0;
    int minutes = 0;
    int micros;
    List<String> parts = s.split(':');
    if (parts.length > 2) {
      hours = int.parse(parts[parts.length - 3]);
    }
    if (parts.length > 1) {
      minutes = int.parse(parts[parts.length - 2]);
    }
    micros = (double.parse(parts[parts.length - 1]) * 1000000).round();
    return Duration(hours: hours, minutes: minutes, microseconds: micros);
  }

我的用例是我创建了服务器应用程序和客户端应用程序。服务器应用程序用于处理,使用插件 flutter_ffmpeg 检索持续时间值并将其存储在 MediaItem 中,然后将其上传到 Cloud Firestore 和 Storage。客户端应用程序用于从 Cloud Firestore 和 Storage 检索数据。

我根据 [官方文档][2] 更新了媒体项目。我打算使用更新的歌曲,所以我不需要再次为当前媒体项目添加持续时间。

我的问题是:
从 Cloud Firestore 下载后,媒体项中包含的数据是否具有相同的持续时间值?我的意思是,我们需要在同一首歌中再次添加持续时间值吗???或者持续时间值已经存储在歌曲中?

[1]: https://pub.dev/packages/audio_service
[2]: https://github.com/ryanheise/audio_service/wiki/FAQ#how-do-i-update-an-existing-mediaitem
[3]: https://pub.dev/packages/flutter_ffmpeg

好的,我想我知道答案了。 Dart 中 Duration 类型的数据不能上传到 Firestore 中,必须转换成 Timestamp 格式。所以,我存储 Duration 数据的唯一方法是在这个函数 readAudio(File audio).

中保留 return 值的字符串值

Future<String> readAudio(File audio) async {
    final FlutterFFprobe durReader = FlutterFFprobe();
    String duration = "";
    await durReader.getMediaInformation(audio.path).then((value) => duration = value.getMediaProperties()!["duration"]);
    return duration; //this data
}

当我从 Cloud Firestore 和 Storage 下载所有歌曲数据时,我应该使用函数 parseDuration(String s).

设置并将字符串类型的 Duration 值转换为 Duration 类型

Duration parseDuration(String s) {
    int hours = 0;
    int minutes = 0;
    int micros;
    List<String> parts = s.split(':');
    if (parts.length > 2) {
      hours = int.parse(parts[parts.length - 3]);
    }
    if (parts.length > 1) {
      minutes = int.parse(parts[parts.length - 2]);
    }
    micros = (double.parse(parts[parts.length - 1]) * 1000000).round();
    return Duration(hours: hours, minutes: minutes, microseconds: micros);
}
获得 Duration 值后,我会将其添加到 class 中,这将为我稍后准备的歌曲集合定义 MediaItem。这是我能想到的在 MediaItem 中添加 Duration 值的唯一方法。由于 audio_service 包中的示例文件如 example_playlist.dart [在 github 存储库中所示],如果歌曲没有持续时间值。

如果 Shuffle button/Repeat 按钮被用户点击,我希望任何专家都能提供另一种获取持续时间值的解决方案,并阻止它错过进度条的位置。如果有任何提示和技巧,我将不胜感激。
非常感谢你。

无论如何,在这 whosebug.com 中帮助过我的人将被视为贡献者,在我的应用程序达到 1.000.000 美元后,我将捐赠其中的 10% 给所有贡献者。这也适用于我在我的项目、任何教程网站和 YouTube 上的视频中使用的 dart 包的作者。他们的名字将列在应用程序内。像这样无偿贡献的人应该得到奖励,如果它很有用,我会很乐意奖励他们。

我的第一个应用程序将于 2022 年 5 月 1 日发布。
我不会告诉应用程序的名称,以保护 Google Play Store 和 Apple App Store 中的唯一名称。
我的原则工作就是你帮我,达到最低收入后我会奖励你5年non-stop

我发现我错在哪里了。 实际上,我们只需要在 init() 函数中添加这些代码:

    _player.durationStream.listen((duration) {
      var index = _player.currentIndex;
      if (index != null && duration != null) {
        final newQueue = queue.value;
        final oldMediaItem = newQueue[index];
        final newMediaItem = oldMediaItem.copyWith(duration: duration);
        newQueue[index] = newMediaItem;
        mediaItem.add(newMediaItem);
      }
    });
我还应该在函数 setShuffleMode()

中添加这些

@override
Future<void> setShuffleMode(AudioServiceShuffleMode shuffleMode) async {
   final enabled = shuffleMode == AudioServiceShuffleMode.all;
   if (enabled) {
     await _player.shuffle();
     await _player.setShuffleModeEnabled(true);
     _player.durationStream.listen((duration) {
       var index = _player.currentIndex;
       if (index != null && duration != null) {
         final newQueue = queue.value;
         final oldMediaItem = newQueue[index];
         final newMediaItem = oldMediaItem.copyWith(duration: duration);
         newQueue[index] = newMediaItem;
         mediaItem.add(newMediaItem);
         playbackState.add(playbackState.value.copyWith(
           shuffleMode: shuffleMode,
           updatePosition: _player.position,
           bufferedPosition: _player.bufferedPosition,
         ));
       }
     });
   } else {
     shuffleMode = AudioServiceShuffleMode.none;
     await _player.setShuffleModeEnabled(false);
     _player.durationStream.listen((duration) {
       var index = _player.currentIndex;
       if (index != null && duration != null) {
         final newQueue = queue.value;
         final oldMediaItem = newQueue[index];
         final newMediaItem = oldMediaItem.copyWith(duration: duration);
         newQueue[index] = newMediaItem;
         mediaItem.add(newMediaItem);
         playbackState.add(playbackState.value.copyWith(
           shuffleMode: shuffleMode,
           updatePosition: _player.position,
           bufferedPosition: _player.bufferedPosition,
         ));
       }
     });
   }
 }

我不需要使用库 flutter_ffmpeg 读取持续时间值,我只需要在 init() 函数中添加该代码并替换原函数setShuffleMode。我想我必须删除我下面的评论以替代比这个答案难得多的方式。嗯,还是谢谢你。