@@ -84,6 +84,7 @@ import {
8484 showToast ,
8585 writeFileWithPicker ,
8686} from ' ../helpers/utils'
87+ import { processToBeAddedPlaylistVideo } from ' ../helpers/playlists'
8788
8889const IMPORT_DIRECTORY_ID = ' data-settings-import'
8990const START_IN_DIRECTORY = ' downloads'
@@ -1019,6 +1020,8 @@ async function importPlaylists() {
10191020 ' videoCount' ,
10201021 ]
10211022
1023+ const knownKeys = [... requiredKeys, ... optionalKeys, ... ignoredKeys]
1024+
10221025 const requiredVideoKeys = [
10231026 ' videoId' ,
10241027 ' title' ,
@@ -1033,16 +1036,19 @@ async function importPlaylists() {
10331036 // 'playlistItemId',
10341037 ]
10351038
1039+ const newPlaylists = []
1040+
10361041 playlists .forEach ((playlistData ) => {
10371042 // We would technically already be done by the time the data is parsed,
10381043 // however we want to limit the possibility of malicious data being sent
10391044 // to the app, so we'll only grab the data we need here.
10401045
10411046 const playlistObject = {}
10421047 const videoIdToBeAddedSet = new Set ()
1048+ let countRequiredKeysPresent = 0
10431049
10441050 Object .keys (playlistData).forEach ((key ) => {
1045- if ([requiredKeys, optionalKeys, ignoredKeys]. every (( ks ) => ! ks .includes (key) )) {
1051+ if (! knownKeys .includes (key)) {
10461052 const message = ` ${ t (' Settings.Data Settings.Unknown data key' )} : ${ key} `
10471053 showToast (message)
10481054 } else if (key === ' videos' ) {
@@ -1057,17 +1063,22 @@ async function importPlaylists() {
10571063 }
10581064 })
10591065
1060- playlistObject[key] = videoArray
1066+ playlistObject .videos = videoArray
1067+
1068+ if (requiredKeys .includes (key)) {
1069+ countRequiredKeysPresent++
1070+ }
10611071 } else if (! ignoredKeys .includes (key)) {
10621072 // Do nothing for keys to be ignored
10631073 playlistObject[key] = playlistData[key]
1074+
1075+ if (requiredKeys .includes (key)) {
1076+ countRequiredKeysPresent++
1077+ }
10641078 }
10651079 })
10661080
1067- const playlistObjectKeys = Object .keys (playlistObject)
1068- const playlistObjectHasAllRequiredKeys = requiredKeys .every ((k ) => playlistObjectKeys .includes (k))
1069-
1070- if (! playlistObjectHasAllRequiredKeys) {
1081+ if (countRequiredKeysPresent !== requiredKeys .length ) {
10711082 const message = t (' Settings.Data Settings.Playlist insufficient data' , { playlist: playlistData .playlistName })
10721083 showToast (message)
10731084 return
@@ -1082,47 +1093,58 @@ async function importPlaylists() {
10821093 })
10831094
10841095 if (existingPlaylist === undefined ) {
1085- store . dispatch ( ' addPlaylist ' , playlistObject)
1096+ newPlaylists . push ( playlistObject)
10861097 return
10871098 }
10881099
1089- const duplicateVideoPresentInToBeAdded = playlistObject .videos .length > videoIdToBeAddedSet .size
1090- const existingVideoIdSet = existingPlaylist .videos .reduce ((video ) => videoIdToBeAddedSet .add (video .videoId ), new Set ())
1091- const duplicateVideoPresentInExistingPlaylist = existingPlaylist .videos .length > existingVideoIdSet .size
1092- const shouldAddDuplicateVideos = duplicateVideoPresentInToBeAdded || duplicateVideoPresentInExistingPlaylist
1100+ /** @type {Set<string> | undefined} */
1101+ let existingVideoIdSet
1102+
1103+ let shouldAddDuplicateVideos = playlistObject .videos .length > videoIdToBeAddedSet .size
1104+
1105+ if (! shouldAddDuplicateVideos) {
1106+ existingVideoIdSet = existingPlaylist .videos .reduce ((set , video ) => set .add (video .videoId ), new Set ())
1107+ shouldAddDuplicateVideos = existingPlaylist .videos .length > existingVideoIdSet .size
1108+ }
1109+
1110+ const playlistVideos = [... existingPlaylist .videos ]
10931111
10941112 playlistObject .videos .forEach ((video ) => {
10951113 let videoExists = false
10961114 if (shouldAddDuplicateVideos) {
10971115 if (video .playlistItemId != null ) {
10981116 // Find by `playlistItemId` if present
1099- videoExists = existingPlaylist . videos .some ((x ) => {
1117+ videoExists = playlistVideos .some ((x ) => {
11001118 // Allow duplicate (by videoId) videos to be added
11011119 return x .videoId === video .videoId && x .playlistItemId === video .playlistItemId
11021120 })
11031121 } else {
11041122 // Older playlist exports have no `playlistItemId` but have `timeAdded`
11051123 // Which might be duplicate for copied playlists with duplicate `videoId`
1106- videoExists = existingPlaylist . videos .some ((x ) => {
1124+ videoExists = playlistVideos .some ((x ) => {
11071125 // Allow duplicate (by videoId) videos to be added
11081126 return x .videoId === video .videoId && x .timeAdded === video .timeAdded
11091127 })
11101128 }
1129+ } else if (existingVideoIdSet !== undefined ) {
1130+ // Disallow duplicate (by videoId) videos to be added
1131+
1132+ if (existingVideoIdSet .has (video .videoId )) {
1133+ videoExists = true
1134+ } else {
1135+ existingVideoIdSet .add (video .videoId )
1136+ }
11111137 } else {
1112- videoExists = existingPlaylist . videos .some ((x ) => {
1138+ videoExists = playlistVideos .some ((x ) => {
11131139 // Disallow duplicate (by videoId) videos to be added
11141140 return x .videoId === video .videoId
11151141 })
11161142 }
11171143
11181144 if (! videoExists) {
11191145 // Keep original `timeAdded` value
1120- const payload = {
1121- _id: existingPlaylist ._id ,
1122- videoData: video,
1123- }
1124-
1125- store .dispatch (' addVideo' , payload)
1146+ processToBeAddedPlaylistVideo (video)
1147+ playlistVideos .push (video)
11261148 }
11271149 })
11281150 // Update playlist's `lastUpdatedAt` & other attributes
@@ -1131,9 +1153,14 @@ async function importPlaylists() {
11311153 // Only these attributes would be updated (besides videos)
11321154 playlistName: playlistObject .playlistName ,
11331155 description: playlistObject .description ,
1156+ videos: playlistVideos
11341157 })
11351158 })
11361159
1160+ if (newPlaylists .length > 0 ) {
1161+ store .dispatch (' addPlaylists' , newPlaylists)
1162+ }
1163+
11371164 showToast (t (' Settings.Data Settings.All playlists has been successfully imported' ))
11381165}
11391166
0 commit comments