From 6bc6e0c17243fac5a1cbdc372efbd7eb66bb67db Mon Sep 17 00:00:00 2001 From: Mahmoud AlSharif <16165616+mas-iota@users.noreply.github.com> Date: Thu, 28 Aug 2025 20:27:07 +0300 Subject: [PATCH] migrate storage to file system on mobile --- .../widget.nowplaying.controller.js | 79 ++++---- widget/index.html | 1 + widget/storageUtil.js | 112 ++++++++++++ widget/viewedItems.js | 173 +++++------------- 4 files changed, 199 insertions(+), 166 deletions(-) create mode 100644 widget/storageUtil.js diff --git a/widget/controllers/widget.nowplaying.controller.js b/widget/controllers/widget.nowplaying.controller.js index f3a46f1..8354b1e 100644 --- a/widget/controllers/widget.nowplaying.controller.js +++ b/widget/controllers/widget.nowplaying.controller.js @@ -13,10 +13,10 @@ //$rootScope.blackBackground = true; $rootScope.showFeedList = false; - var NowPlaying = this; - NowPlaying.playing = false; - NowPlaying.currentTime = 0; - buildfire.appearance.navbar.hide(); + var NowPlaying = this; + NowPlaying.playing = false; + NowPlaying.currentTime = 0; + buildfire.appearance.navbar.hide(); /** * NowPlaying.item used to hold item details object * @type {object} @@ -122,19 +122,23 @@ audioPlayer.settings.set(NowPlaying.settings); }); } - NowPlaying.playing = true; - if (NowPlaying.paused) { - audioPlayer.play(); - } else { - if (NowPlaying.settings.autoJumpToLastPosition) { - lastUpdatedPosition = getItemLastSavedPosition() || 0; - if (typeof lastUpdatedPosition === 'number') { - NowPlaying.currentTrack.startAt = lastUpdatedPosition; - } - } - audioPlayer.play(NowPlaying.currentTrack); - } - }; + NowPlaying.playing = true; + if (NowPlaying.paused) { + audioPlayer.play(); + } else { + if (NowPlaying.settings.autoJumpToLastPosition) { + getItemLastSavedPosition().then(function (pos) { + lastUpdatedPosition = pos || 0; + if (typeof pos === 'number') { + NowPlaying.currentTrack.startAt = pos; + } + audioPlayer.play(NowPlaying.currentTrack); + }); + } else { + audioPlayer.play(NowPlaying.currentTrack); + } + } + }; NowPlaying.playlistPlay = function (track) { if (NowPlaying.settings) { NowPlaying.settings.isPlayingCurrentTrack = true; @@ -368,31 +372,24 @@ */ var onRefresh = Buildfire.datastore.onRefresh(function () {}); - function getItemLastSavedPosition() { - if (!NowPlaying.currentTrack || !NowPlaying.currentTrack.id) return 0; + function getItemLastSavedPosition(callback) { + if (!NowPlaying.currentTrack || !NowPlaying.currentTrack.id) { + return callback ? Promise.resolve(callback(0)) : Promise.resolve(0); + } + const key = `audio-item-${NowPlaying.currentTrack.id}`; + return storageUtil.migrateToFS(key).then(function () { + return storageUtil.read(key).then(function (item) { + if (!item || !item.lastPosition) return callback ? callback(0) : 0; + return callback ? callback(item.lastPosition) : item.lastPosition; + }); + }); + } - // get item from localstorage - let item = buildfire.localStorage.getItem(`audio-item-${NowPlaying.currentTrack.id}`); - if (!item) return 0; - try { - item = JSON.parse(item); - if (!item || !item.lastPosition) return 0; - return item.lastPosition; - } catch (err) { - console.error('Error parsing item from localStorage', err); - return 0; - } - } - - function updateAudioLastPosition(trackLastPosition) { - if (!NowPlaying.currentTrack || !NowPlaying.currentTrack.id) return; - - let item = { - lastPosition: trackLastPosition, - }; - - buildfire.localStorage.setItem(`audio-item-${NowPlaying.currentTrack.id}`, JSON.stringify(item)); - } + function updateAudioLastPosition(trackLastPosition) { + if (!NowPlaying.currentTrack || !NowPlaying.currentTrack.id) return; + lastUpdatedPosition = trackLastPosition; + storageUtil.write(`audio-item-${NowPlaying.currentTrack.id}`, { lastPosition: trackLastPosition }); + } /** * Unbind the onRefresh diff --git a/widget/index.html b/widget/index.html index a808207..9761096 100644 --- a/widget/index.html +++ b/widget/index.html @@ -72,6 +72,7 @@ + diff --git a/widget/storageUtil.js b/widget/storageUtil.js new file mode 100644 index 0000000..5a04bbf --- /dev/null +++ b/widget/storageUtil.js @@ -0,0 +1,112 @@ +let storageUtil = { + platform: buildfire.getContext().device.platform, + instanceId: buildfire.getContext().instanceId.replace("-", ""), + fsFileName: 'storage.txt', + migrateToFS: function (key, path) { + return new Promise((resolve) => { + if (this.platform === 'web') return resolve(); + + const item = buildfire.localStorage.getItem(key); + if (!item) return resolve(); + + let parsed; + try { + parsed = JSON.parse(item); + } catch (e) { + console.warn(e); + buildfire.localStorage.removeItem(key); + return resolve(); + } + + this.read(key, path).then((existing) => { + let dataToWrite; + + if (Array.isArray(parsed) && Array.isArray(existing)) { + dataToWrite = existing.concat(parsed.filter(val => !existing.includes(val))); + } else if (typeof parsed === 'object' && typeof existing === 'object') { + dataToWrite = { ...existing }; + Object.keys(parsed).forEach((k) => { + if (Array.isArray(parsed[k]) && Array.isArray(existing[k])) { + dataToWrite[k] = existing[k].concat(parsed[k].filter(val => !existing[k].includes(val))); + } else { + dataToWrite[k] = parsed[k]; + } + }); + } else { + dataToWrite = parsed; + } + + this.write(key, dataToWrite, path).then(() => { + buildfire.localStorage.removeItem(key); + resolve(); + }); + }); + }); + }, + read: function (key, path) { + return new Promise((resolve) => { + if (this.platform === 'web') { + let item = buildfire.localStorage.getItem(key); + if (!item) return resolve(null); + try { + return resolve(JSON.parse(item)); + } catch (e) { + console.warn(e); + return resolve(null); + } + } else { + const options = { + path: path || '/data/pluginMediaCenterRss/', + fileName: this.fsFileName + }; + buildfire.services.fileSystem.fileManager.readFileAsText(options, function (err, data) { + if (err || !data) return resolve(null); + try { + const parsed = JSON.parse(data); + resolve(parsed && Object.prototype.hasOwnProperty.call(parsed, key) ? parsed[key] : null); + } catch (e) { + console.warn(e); + resolve(null); + } + }); + } + }); + }, + write: function (key, data, path) { + return new Promise((resolve) => { + if (this.platform === 'web') { + const content = JSON.stringify(data); + buildfire.localStorage.setItem(key, content); + return resolve(); + } + + const options = { + path: path || '/data/pluginMediaCenterRss/', + fileName: this.fsFileName + }; + + buildfire.services.fileSystem.fileManager.readFileAsText(options, (err, fileData) => { + let stored = {}; + if (!err && fileData) { + try { + stored = JSON.parse(fileData) || {}; + } catch (e) { + console.warn(e); + } + } + + stored[key] = data; + + const writeOptions = { + path: options.path, + fileName: options.fileName, + content: JSON.stringify(stored) + }; + + buildfire.services.fileSystem.fileManager.writeFileAsText(writeOptions, function () { + resolve(); + }); + }); + }); + } +}; diff --git a/widget/viewedItems.js b/widget/viewedItems.js index 8e5d3ec..dd64e56 100644 --- a/widget/viewedItems.js +++ b/widget/viewedItems.js @@ -1,126 +1,49 @@ -'use strict'; - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { - return typeof obj; -} : function (obj) { - return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; -}; - -function _defineProperty(obj, key, value) { - if (key in obj) { - Object.defineProperty(obj, key, { - value: value, - enumerable: true, - configurable: true, - writable: true - }); - } else { - obj[key] = value; - } - return obj; -} - -var viewedItems = { - id: '', - /** - * If localStorage is not set, initialize viewed videos as an empty array - */ - init: function init() { - var _this = this; - - buildfire.auth.getCurrentUser(function (err, user) { - if (err) throw err; - - _this.id = user ? user._id : 'guest'; - - var ls_viewedItems = buildfire.localStorage.getItem('viewedItems'); - var viewedItems = ls_viewedItems ? JSON.parse(ls_viewedItems) : null; - - var storageInitialized = viewedItems && (typeof viewedItems === 'undefined' ? 'undefined' : _typeof(viewedItems)) === 'object' ? true : false; - - if (storageInitialized) { - var userStateInitialized = viewedItems.hasOwnProperty(_this.id); - if (userStateInitialized) return; - else viewedItems[_this.id] = []; - } else { - viewedItems = _defineProperty({}, _this.id, []); - } - - buildfire.localStorage.setItem('viewedItems', JSON.stringify(viewedItems)); - }); - }, - - /** - * returns the current user's parsed array of viewed videos - * @returns {Array} - */ - get: function get() { - try { - var ls_viewedItems = buildfire.localStorage.getItem('viewedItems'); - if (!ls_viewedItems) return []; - const item = JSON.parse(ls_viewedItems)[this.id]; - if (item) return item; - else return []; - } catch (e) { - console.warn(e); - return []; - } - }, - - /** - * stringify and set viewed videos to local storage - * @param {Array} videos - */ - _set: function _set(items) { - try { - var ls_viewedItems = buildfire.localStorage.getItem('viewedItems'); - if (!ls_viewedItems) return []; - var _viewedItems2 = JSON.parse(ls_viewedItems); - _viewedItems2[this.id] = items; - buildfire.localStorage.setItem('viewedItems', JSON.stringify(_viewedItems2)); - } catch (e) { - console.warn(e); - return []; - } - }, - - /** - * pushes a video id to local storage - * marks video as viewed - * @param {Object} $scope - * @param {Object} video - */ - markViewed: function markViewed($scope, id) { - var viewedItems = this.get(); - var isViewed = viewedItems.includes(id); - - if (isViewed) return; - - viewedItems.push(id); - this._set(viewedItems); - - $scope.WidgetHome.items.map(function (item) { - if (viewedItems.includes(item.guid)) { - item.viewed = true; - } - }); - - if (!$scope.$$phase) { - $scope.$apply(); - } - }, - - /** - * maps through an array of videos - * marks videos that have been viewed - * @param {Array} videos - */ - sync: function sync(items) { - var _this2 = this; - - return items.map(function (item) { - var isViewed = _this2.get().includes(item.guid); - item.viewed = isViewed ? true : false; - }); - } +let viewedItems = { + id: '', + data: {}, + init: function () { + let _this = this; + buildfire.auth.getCurrentUser(function (err, user) { + if (err) throw err; + _this.id = user ? user._id : 'guest'; + let key = `viewedItems_${storageUtil.instanceId}`; + storageUtil.migrateToFS(key, '/data/pluginMediaCenterRss/').then(function () { + storageUtil.read(key, '/data/pluginMediaCenterRss/').then(function (stored) { + if (!stored || typeof stored !== 'object') stored = {}; + if (!stored[_this.id]) stored[_this.id] = []; + _this.data = stored; + return storageUtil.write(key, _this.data, '/data/pluginMediaCenterRss/'); + }); + }); + }); + }, + get: function () { + if (this.data && this.data[this.id]) return this.data[this.id]; + return []; + }, + _set: function (items) { + this.data[this.id] = items; + storageUtil.write(`viewedItems_${storageUtil.instanceId}`, this.data, '/data/pluginMediaCenterRss/'); + }, + markViewed: function ($scope, id) { + let viewed = this.get(); + if (viewed.includes(id)) return; + viewed.push(id); + this._set(viewed); + $scope.WidgetHome.items.map(function (item) { + if (viewed.includes(item.guid)) { + item.viewed = true; + } + }); + if (!$scope.$$phase) { + $scope.$apply(); + } + }, + sync: function (items) { + let _this = this; + return items.map(function (item) { + item.viewed = _this.get().includes(item.guid); + return item; + }); + } };