Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions src/renderer/components/DataSettings/DataSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,24 @@
@click="showExportSearchHistoryPrompt = true"
/>
</FtFlexBox>
<h4 class="groupTitle">
{{ t('Settings.Settings') }}
<FtTooltip
class="selectTooltip"
position="top"
:tooltip="t('Settings.Data Settings.Settings Tooltip')"
/>
</h4>
<FtFlexBox class="box">
<FtButton
:label="t('Settings.Data Settings.Import Settings')"
@click="importSettings"
/>
<FtButton
:label="t('Settings.Data Settings.Export Settings')"
@click="exportSettings"
/>
</FtFlexBox>
<FtPrompt
v-if="showExportSubscriptionsPrompt"
:label="$t('Settings.Data Settings.Select Export Type')"
Expand Down Expand Up @@ -98,8 +116,10 @@ import FtButton from '../FtButton/FtButton.vue'
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
import FtPrompt from '../FtPrompt/FtPrompt.vue'
import FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'
import FtTooltip from '../FtTooltip/FtTooltip.vue'

import store from '../../store/index'
import { defaultUpdaterId } from '../../store/modules/settings'

import { MAIN_PROFILE_ID } from '../../../constants'
import { calculateColorLuminance, getRandomColor } from '../../helpers/colors'
Expand Down Expand Up @@ -1458,6 +1478,85 @@ async function exportYouTubeSearchHistory() {
}

// #endregion search history

// #region settings

/** @type {import('vue').ComputedRef<object>} */
const transferableSettings = computed(() => {
return store.getters.getTransferableSettings
})

async function importSettings() {
let response
try {
response = await readFileWithPicker(
t('Settings.Data Settings.Settings File'),
{
'application/x-freetube-db': '.db',
'application/json': '.json'
},
IMPORT_DIRECTORY_ID,
START_IN_DIRECTORY
)
} catch (err) {
const message = t('Settings.Data Settings.Unable to read file')
showToast(`${message}: ${err}`)
return
}

if (response === null) {
return
}

const { content } = response
const importedSettings = JSON.parse(content)
const currentTransferableSettings = transferableSettings.value
const currentSettings = store.state.settings

for (const [importedKey, importedValue] of Object.entries(importedSettings)) {
Comment thread
Shadorc marked this conversation as resolved.
if (!Object.hasOwn(currentSettings, importedKey)) {
const message = `${t('Settings.Data Settings.Unknown setting key')}: ${importedKey}`
showToast(message)
continue
}

if (!Object.hasOwn(currentTransferableSettings, importedKey)) {
const message = `${t('Settings.Data Settings.Non-transferable setting key')}: ${importedKey}`
showToast(message)
continue
}

const currentValue = currentTransferableSettings[importedKey]
const areValuesEqual = currentValue === importedValue ||
(typeof importedValue === 'object' && JSON.stringify(currentValue) === JSON.stringify(importedValue))
if (areValuesEqual) {
continue
}

const updaterId = defaultUpdaterId(importedKey)
await store.dispatch(updaterId, importedValue)
}

showToast(t('Settings.Data Settings.All settings have been successfully imported'))
}

async function exportSettings() {
const dateStr = getTodayDateStrLocalTimezone()
const exportFileName = `freetube-settings-${dateStr}.db`
const settingsContent = JSON.stringify(transferableSettings.value)

await promptAndWriteToFile(
exportFileName,
settingsContent,
t('Settings.Data Settings.Settings File'),
'application/x-freetube-db',
'.db',
t('Settings.Data Settings.All settings have been successfully exported')
)
}

// #endregion settings

</script>

<style scoped src="./DataSettings.css" />
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
padding-inline: 10px;
}

:deep(:not(.select, .selectLabel) > .tooltip) {
:deep(:not(.select, .selectLabel, .groupTitle) > .tooltip) {
display: inline-block;
position: absolute;
inset-inline-end: -25px;
Expand Down
54 changes: 50 additions & 4 deletions src/renderer/store/modules/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,15 @@ import { getSystemLocale, showToast } from '../../helpers/utils'
* to evaluate if it is truly necessary
* and to ensure that the implementation works as intended.
*
***
* `settingsNotTransferable`
* This set contains setting keys
* that should not be exported when a user chooses to "Export settings".
*
* When adding a new setting, it should be considered
* whether this setting can be exported or not. For example, settings
* that are OS or user specific like paths should not be exported.
*
****
* ENDING NOTES
*
Expand All @@ -141,10 +150,10 @@ import { getSystemLocale, showToast } from '../../helpers/utils'

// HELPERS
const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1)
const defaultGetterId = settingId => 'get' + capitalize(settingId)
const defaultMutationId = settingId => 'set' + capitalize(settingId)
const defaultUpdaterId = settingId => 'update' + capitalize(settingId)
const defaultSideEffectsTriggerId = settingId =>
export const defaultGetterId = settingId => 'get' + capitalize(settingId)
export const defaultMutationId = settingId => 'set' + capitalize(settingId)
export const defaultUpdaterId = settingId => 'update' + capitalize(settingId)
export const defaultSideEffectsTriggerId = settingId =>
'trigger' + capitalize(settingId) + 'SideEffects'
/*****/

Expand Down Expand Up @@ -414,10 +423,47 @@ const sideEffectHandlers = {

const settingsWithSideEffects = Object.keys(sideEffectHandlers)

const settingsNotTransferable = new Set([
/* Depends on process.env.IS_ELECTRON */
// ProxySettings
'useProxy',
'proxyProtocol',
'proxyHostname',
'proxyPort',
'proxyUsername',
'proxyPassword',
// ExternalPlayerSettings
'externalPlayer',
'externalPlayerExecutable',
'externalPlayerIgnoreWarnings',
'externalPlayerIgnoreDefaultArgs',
'externalPlayerCustomArgs',
'showAddedExternalPlayerCustomArgs',
// Others
'disableSmoothScrolling',
'hideToTrayOnMinimize',
'screenshotAskPath',
'screenshotFolderPath',

/* Depends on process.env.SUPPORTS_LOCAL_API */
'backendFallback',
'backendPreference',
'proxyVideos',
])

const customState = {
}

const customGetters = {
getTransferableSettings: (state) => {
const transferableSettings = {}
for (const [key, value] of Object.entries(state)) {
if (!settingsNotTransferable.has(key)) {
transferableSettings[key] = value
}
}
return transferableSettings
}
}

const customMutations = {}
Expand Down
10 changes: 10 additions & 0 deletions static/locales/en-US.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ Settings:
History File: History File
Playlist File: Playlist File
Search history file: Search history file
Settings File: Settings File
Export Subscriptions: Export Subscriptions
Export FreeTube: Export FreeTube
Export YouTube: Export YouTube
Expand All @@ -600,6 +601,9 @@ Settings:
Search history: Search history
Import search history: Import search history
Export search history: Export search history
Import Settings: Import Settings
Export Settings: Export Settings
Settings Tooltip: Settings that are OS/user-specific or experimental cannot be exported or imported (e.g., proxy, external player, screenshot folder...)
Profile object has insufficient data, skipping item: Profile object has insufficient
data, skipping item
All subscriptions and profiles have been successfully imported: All subscriptions
Expand All @@ -625,9 +629,15 @@ Settings:
successfully imported
All search history has been successfully exported: All search history has been
successfully exported
All settings have been successfully imported: All settings have been
successfully imported
All settings have been successfully exported: All settings have been
successfully exported
Unable to read file: Unable to read file
Unable to write file: Unable to write file
Unknown data key: Unknown data key
Unknown setting key: Unknown setting key
Non-transferable setting key: Non-transferable setting key
How do I import my subscriptions?: How do I import my subscriptions?
Manage Subscriptions: Manage Subscriptions
Proxy Settings:
Expand Down
Loading