Skip to content
Merged
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
2 changes: 2 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ const IpcChannels = {
SET_INVIDIOUS_AUTHORIZATION: 'set-invidious-authorization',

GENERATE_PO_TOKEN: 'generate-po-token',

WRITE_SCREENSHOT: 'write-screenshot',
}

const DBActions = {
Expand Down
4 changes: 4 additions & 0 deletions src/datastores/handlers/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ class Settings {
}
}

static _findScreenshotFolderPath() {
return db.settings.findOneAsync({ _id: 'screenshotFolderPath' })
}

static _updateBounds(value) {
return db.settings.updateAsync({ _id: 'bounds' }, { _id: 'bounds', value }, { upsert: true })
}
Expand Down
34 changes: 34 additions & 0 deletions src/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,40 @@ function runApp() {
})
}

ipcMain.handle(IpcChannels.WRITE_SCREENSHOT, async (event, filename, arrayBuffer) => {
if (!isFreeTubeUrl(event.senderFrame.url) || typeof filename !== 'string' || !(arrayBuffer instanceof ArrayBuffer)) {
return
}

const screenshotFolderPath = await baseHandlers.settings._findScreenshotFolderPath()

let directory
if (screenshotFolderPath && screenshotFolderPath.value.length > 0) {
directory = screenshotFolderPath.value
} else {
directory = path.join(app.getPath('pictures'), 'FreeTube')
}

directory = path.normalize(directory)

const filePath = path.resolve(directory, filename)

// Ensure that we are only writing inside of the expected directory
if (path.dirname(filePath) !== directory) {
throw new Error('Invalid save location')
}

try {
await asyncFs.mkdir(directory, { recursive: true })

await asyncFs.writeFile(filePath, new DataView(arrayBuffer))
} catch (error) {
console.error('WRITE_SCREENSHOT failed', error)
// throw a new error so that we don't expose the real error to the renderer
throw new Error('Failed to save')
}
})

ipcMain.on(IpcChannels.STOP_POWER_SAVE_BLOCKER, (_, id) => {
powerSaveBlocker.stop(id)
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import fs from 'fs/promises'
import path from 'path'

import { computed, defineComponent, onBeforeUnmount, onMounted, reactive, ref, shallowRef, watch } from 'vue'
import shaka from 'shaka-player'
import { useI18n } from '../../composables/use-i18n-polyfill'
Expand All @@ -24,11 +21,9 @@ import {
} from '../../helpers/player/utils'
import {
addKeyboardShortcutToActionTitle,
getPicturesPath,
showToast,
writeFileWithPicker
} from '../../helpers/utils'
import { pathExists } from '../../helpers/filesystem'

/** @typedef {import('../../helpers/sponsorblock').SponsorBlockCategory} SponsorBlockCategory */

Expand Down Expand Up @@ -344,11 +339,6 @@ export default defineComponent({
return store.getters.getScreenshotAskPath
})

/** @type {import('vue').ComputedRef<string>} */
const screenshotFolder = computed(() => {
return store.getters.getScreenshotFolderPath
})

/** @type {import('vue').ComputedRef<boolean>} */
const videoVolumeMouseScroll = computed(() => {
return store.getters.getVideoVolumeMouseScroll
Expand Down Expand Up @@ -1602,16 +1592,16 @@ export default defineComponent({

const filenameWithExtension = `${filename}.${format}`

if (!process.env.IS_ELECTRON || screenshotAskPath.value) {
const wasPlaying = !video_.paused
if (wasPlaying) {
video_.pause()
}
const wasPlaying = !video_.paused
if (wasPlaying) {
video_.pause()
}

try {
/** @type {Blob} */
const blob = await new Promise((resolve) => canvas.toBlob(resolve, mimeType, imageQuality))
try {
/** @type {Blob} */
const blob = await new Promise((resolve) => canvas.toBlob(resolve, mimeType, imageQuality))

if (!process.env.IS_ELECTRON || screenshotAskPath.value) {
const saved = await writeFileWithPicker(
filenameWithExtension,
blob,
Expand All @@ -1625,53 +1615,24 @@ export default defineComponent({
if (saved) {
showToast(t('Screenshot Success'))
}
} catch (error) {
console.error(error)
showToast(t('Screenshot Error', { error }))
}
} else {
const arrayBuffer = await blob.arrayBuffer()

canvas.remove()
const { ipcRenderer } = require('electron')

if (wasPlaying) {
video_.play()
}
} else {
let dirPath
await ipcRenderer.invoke(IpcChannels.WRITE_SCREENSHOT, filenameWithExtension, arrayBuffer)

if (screenshotFolder.value === '') {
dirPath = path.join(await getPicturesPath(), 'Freetube')
} else {
dirPath = screenshotFolder.value
showToast(t('Screenshot Success'))
}
} catch (error) {
console.error(error)
showToast(t('Screenshot Error', { error }))
} finally {
canvas.remove()

if (!(await pathExists(dirPath))) {
try {
await fs.mkdir(dirPath, { recursive: true })
} catch (err) {
console.error(err)
showToast(t('Screenshot Error', { error: err }))
canvas.remove()
return
}
if (wasPlaying) {
video_.play()
}

const filePath = path.join(dirPath, filenameWithExtension)

canvas.toBlob((result) => {
result.arrayBuffer().then(ab => {
const arr = new Uint8Array(ab)

fs.writeFile(filePath, arr)
.then(() => {
showToast(t('Screenshot Success'))
})
.catch((err) => {
console.error(err)
showToast(t('Screenshot Error', { error: err }))
})
})
}, mimeType, imageQuality)
canvas.remove()
}
}

Expand Down
Loading