Save last playback position for long videos.

This commit is contained in:
John Preston 2019-12-25 18:19:52 +03:00
parent b584204522
commit e9620af6fb
3 changed files with 71 additions and 1 deletions

View File

@ -21,6 +21,7 @@ constexpr auto kAutoLockTimeoutLateMs = crl::time(3000);
constexpr auto kLegacyCallsPeerToPeerNobody = 4;
constexpr auto kVersionTag = -1;
constexpr auto kVersion = 1;
constexpr auto kMaxSavedPlaybackPositions = 16;
} // namespace
@ -93,6 +94,10 @@ QByteArray Settings::serialize() const {
stream << qint32(_variables.suggestEmoji ? 1 : 0);
stream << qint32(_variables.suggestStickersByEmoji ? 1 : 0);
stream << qint32(_variables.spellcheckerEnabled.current() ? 1 : 0);
stream << qint32(_variables.mediaLastPlaybackPosition.size());
for (const auto &[id, time] : _variables.mediaLastPlaybackPosition) {
stream << quint64(id) << qint64(time);
}
}
return result;
}
@ -142,6 +147,7 @@ void Settings::constructFromSerialized(const QByteArray &serialized) {
qint32 suggestEmoji = _variables.suggestEmoji ? 1 : 0;
qint32 suggestStickersByEmoji = _variables.suggestStickersByEmoji ? 1 : 0;
qint32 spellcheckerEnabled = _variables.spellcheckerEnabled.current() ? 1 : 0;
std::vector<std::pair<DocumentId, crl::time>> mediaLastPlaybackPosition;
stream >> versionTag;
if (versionTag == kVersionTag) {
@ -250,6 +256,18 @@ void Settings::constructFromSerialized(const QByteArray &serialized) {
if (!stream.atEnd()) {
stream >> spellcheckerEnabled;
}
if (!stream.atEnd()) {
auto count = qint32(0);
stream >> count;
if (stream.status() == QDataStream::Ok) {
for (auto i = 0; i != count; ++i) {
quint64 documentId;
qint64 time;
stream >> documentId >> time;
mediaLastPlaybackPosition.emplace_back(documentId, time);
}
}
}
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for Main::Settings::constructFromSerialized()"));
@ -336,6 +354,7 @@ void Settings::constructFromSerialized(const QByteArray &serialized) {
_variables.suggestEmoji = (suggestEmoji == 1);
_variables.suggestStickersByEmoji = (suggestStickersByEmoji == 1);
_variables.spellcheckerEnabled = (spellcheckerEnabled == 1);
_variables.mediaLastPlaybackPosition = std::move(mediaLastPlaybackPosition);
}
void Settings::setSupportChatsTimeSlice(int slice) {
@ -430,6 +449,34 @@ rpl::producer<int> Settings::thirdColumnWidthChanges() const {
return _variables.thirdColumnWidth.changes();
}
void Settings::setMediaLastPlaybackPosition(DocumentId id, crl::time time) {
auto &map = _variables.mediaLastPlaybackPosition;
const auto i = ranges::find(
map,
id,
&std::pair<DocumentId, crl::time>::first);
if (i != map.end()) {
if (time > 0) {
i->second = time;
} else {
map.erase(i);
}
} else if (time > 0) {
if (map.size() >= kMaxSavedPlaybackPositions) {
map.erase(map.begin());
}
map.emplace_back(id, time);
}
}
crl::time Settings::mediaLastPlaybackPosition(DocumentId id) const {
const auto i = ranges::find(
_variables.mediaLastPlaybackPosition,
id,
&std::pair<DocumentId, crl::time>::first);
return (i != _variables.mediaLastPlaybackPosition.end()) ? i->second : 0;
}
void Settings::setArchiveCollapsed(bool collapsed) {
_variables.archiveCollapsed = collapsed;
}

View File

@ -153,6 +153,9 @@ public:
_variables.groupStickersSectionHidden.remove(peerId);
}
void setMediaLastPlaybackPosition(DocumentId id, crl::time time);
[[nodiscard]] crl::time mediaLastPlaybackPosition(DocumentId id) const;
[[nodiscard]] Data::AutoDownload::Full &autoDownload() {
return _variables.autoDownload;
}
@ -277,6 +280,7 @@ private:
bool suggestEmoji = true;
bool suggestStickersByEmoji = true;
rpl::variable<bool> spellcheckerEnabled = true;
std::vector<std::pair<DocumentId, crl::time>> mediaLastPlaybackPosition;
static constexpr auto kDefaultSupportChatsLimitSlice
= 7 * 24 * 60 * 60;

View File

@ -80,6 +80,8 @@ constexpr auto kIdsLimit = 48;
// Preload next messages if we went further from current than that.
constexpr auto kIdsPreloadAfter = 28;
constexpr auto kMinLengthForSavePosition = 20 * TimeId(60); // 20 minutes.
Images::Options VideoThumbOptions(not_null<DocumentData*> document) {
const auto result = Images::Option::Smooth | Images::Option::Blurred;
return (document && document->isVideoMessage())
@ -435,6 +437,20 @@ bool OverlayWidget::documentBubbleShown() const {
}
void OverlayWidget::clearStreaming() {
if (_streamed && _doc) {
const auto state = _streamed->instance.player().prepareLegacyState();
const auto time = (state.position == kTimeUnknown
|| state.length == kTimeUnknown)
? TimeId(0)
: (state.length >= kMinLengthForSavePosition * state.frequency)
? (state.position / state.frequency) * crl::time(1000)
: TimeId(0);
auto &session = _doc->session();
if (session.settings().mediaLastPlaybackPosition(_doc->id) != time) {
session.settings().setMediaLastPlaybackPosition(_doc->id, time);
session.saveSettingsDelayed();
}
}
_fullScreenVideo = false;
_streamed = nullptr;
}
@ -2018,7 +2034,10 @@ void OverlayWidget::startStreamingPlayer() {
if (!_streamed->withSound && _streamed->instance.player().playing()) {
return;
}
restartAtSeekPosition(0);
const auto position = _doc
? _doc->session().settings().mediaLastPlaybackPosition(_doc->id)
: 0;
restartAtSeekPosition(position);
}
void OverlayWidget::initStreamingThumbnail() {