首页
/ 视频播放进度同步:Kazumi 多设备间进度共享实现

视频播放进度同步:Kazumi 多设备间进度共享实现

2026-02-05 05:42:52作者:谭伦延

你是否遇到过这样的困扰:在手机上看番看到一半,切换到电脑端继续观看时,却发现播放进度需要重新查找?Kazumi 的视频播放进度同步功能彻底解决了这一问题,让你在多设备间无缝接续精彩剧情。本文将详细介绍 Kazumi 如何通过 WebDAV 协议实现播放进度的跨设备同步,以及背后的技术实现细节。

同步功能架构概述

Kazumi 的进度同步功能基于 WebDAV(Web-based Distributed Authoring and Versioning)协议实现,通过将本地播放历史数据加密存储到 WebDAV 服务器,实现多设备间的数据共享。核心实现涉及两个关键模块:

这两个模块协同工作,完成数据的备份、恢复和冲突解决,确保各设备间的播放进度保持一致。

数据同步实现原理

WebDAV 客户端核心实现

Kazumi 的 WebDAV 客户端封装在 WebDav 类中,位于 lib/utils/webdav.dart。该类实现了与 WebDAV 服务器的通信,包括初始化连接、数据上传、下载和同步等功能。

初始化连接的关键代码如下:

Future<void> init() async {
  var directory = await getApplicationSupportDirectory();
  webDavLocalTempDirectory = Directory('${directory.path}/webdavTemp');
  Box setting = GStorage.setting;
  webDavURL = setting.get(SettingBoxKey.webDavURL, defaultValue: '');
  webDavUsername = setting.get(SettingBoxKey.webDavUsername, defaultValue: '');
  webDavPassword = setting.get(SettingBoxKey.webDavPassword, defaultValue: '');
  if (webDavURL.isEmpty) {
    throw Exception('请先填写WebDAV URL');
  }
  client = webdav.newClient(
    webDavURL,
    user: webDavUsername,
    password: webDavPassword,
    debug: false,
  );
  client.setHeaders({'accept-charset': 'utf-8'});
  try {
    await client.ping();
    try {
      await client.mkdir('/kazumiSync');    
      if (!await webDavLocalTempDirectory.exists()) {
        await webDavLocalTempDirectory.create(recursive: true);
      }
      initialized = true;
      KazumiLogger().log(Level.info, 'webDav backup directory create success');
    } catch (_) {
      KazumiLogger().log(Level.error, 'webDav backup directory create failed');
      rethrow;
    }
  } catch (e) {
    KazumiLogger().log(Level.error, 'WebDAV ping failed: $e');
    rethrow;
  }
}

这段代码首先从本地存储中读取 WebDAV 服务器配置信息,然后创建 WebDAV 客户端并测试连接。成功连接后,会在服务器上创建一个名为 kazumiSync 的目录,用于存储同步数据。

播放历史数据同步流程

播放历史数据的同步主要通过 updateHistorydownloadAndPatchHistory 两个方法实现:

Future<void> updateHistory() async {
  if (isHistorySyncing) {
    KazumiLogger().log(Level.warning, 'History is currently syncing');
    throw Exception('History is currently syncing');
  }
  isHistorySyncing = true;
  try {
    await update('histories');
  } catch (e) {
    KazumiLogger().log(Level.error, 'webDav update history failed $e');
    rethrow;
  } finally {
    isHistorySyncing = false;
  }
}

Future<void> downloadAndPatchHistory() async {
  if (isHistorySyncing) {
    KazumiLogger().log(Level.warning, 'History is currently syncing');
    throw Exception('History is currently syncing');
  }
  isHistorySyncing = true;
  String fileName = 'histories.tmp';
  try {
    final existingFile = File('${webDavLocalTempDirectory.path}/$fileName');
    await download('histories');
    await GStorage.patchHistory(existingFile.path);
  } catch (e) {
    KazumiLogger()
        .log(Level.error, 'webDav download and patch history failed $e');
    rethrow;
  } finally {
    isHistorySyncing = false;
  }
}

updateHistory 方法负责将本地的播放历史数据上传到 WebDAV 服务器,而 downloadAndPatchHistory 方法则从服务器下载最新的历史数据,并与本地数据进行合并。

数据冲突解决策略

当多个设备同时修改播放进度时,可能会产生数据冲突。Kazumi 采用基于时间戳的冲突解决策略,总是保留最新的播放进度。这一逻辑在 lib/utils/storage.dartpatchHistory 方法中实现:

static Future<void> patchHistory(String backupFilePath) async {
  final backupFile = File(backupFilePath);
  final backupContent = await backupFile.readAsBytes();
  final tempBox = await Hive.openBox('tempHistoryBox', bytes: backupContent);
  final tempBoxItems = tempBox.toMap().entries;

  for (var tempBoxItem in tempBoxItems) {
    if (histories.get(tempBoxItem.key) != null) {
      if (histories
          .get(tempBoxItem.key)!
          .lastWatchTime
          .isBefore(tempBoxItem.value.lastWatchTime)) {
        await histories.delete(tempBoxItem.key);
        await histories.put(tempBoxItem.key, tempBoxItem.value);
      }
    } else {
      await histories.put(tempBoxItem.key, tempBoxItem.value);
    }
  }
  await tempBox.close();
}

这段代码会比较本地和远程历史记录的 lastWatchTime(最后观看时间),如果远程记录更新,则用远程记录覆盖本地记录,从而保证播放进度的准确性。

实际使用流程

配置 WebDAV 服务器

要使用 Kazumi 的进度同步功能,首先需要在设置中配置 WebDAV 服务器信息。这些配置项定义在 lib/utils/storage.dartSettingBoxKey 类中:

static const String webDavEnable = 'webDavEnable',
    webDavEnableHistory = 'webDavEnableHistory',
    webDavEnableCollect = 'webDavEnableCollect',
    webDavURL = 'webDavURL',
    webDavUsername = 'webDavUsername',
    webDavPassword = 'webDavPasswd',

用户需要提供 WebDAV 服务器的 URL、用户名和密码,Kazumi 会将这些信息安全存储在本地。

手动触发同步

除了自动同步外,用户还可以手动触发同步操作。同步功能的入口位于应用的设置页面,用户可以根据需要选择同步播放历史或收藏列表。

相关模块与文件

Kazumi 的进度同步功能涉及多个模块和文件,以下是核心组件的路径:

这些文件共同构成了 Kazumi 的多设备同步系统,确保用户在不同设备上都能获得一致的观看体验。

总结

Kazumi 通过 WebDAV 协议实现了播放进度的跨设备同步,解决了用户在多设备间切换时的播放进度接续问题。核心实现包括 WebDAV 客户端、数据同步逻辑和冲突解决策略,确保了数据的安全性和一致性。

通过本文的介绍,你已经了解了 Kazumi 进度同步功能的工作原理和实现细节。如果你对某个具体模块感兴趣,可以查看相应的源代码文件,深入了解其实现。

如果你在使用同步功能时遇到问题,可以参考项目的 README.md 或提交 issue 寻求帮助。Kazumi 作为一个开源项目,欢迎社区贡献代码和提出改进建议,共同完善这一功能。

登录后查看全文
热门项目推荐
相关项目推荐