Error extracting video metadata for file "E:\$$ Tuts\This is the end\9. Yeah Right.mp4": The filename, directory name, or volume label syntax is incorrect. (os error 123) #21800
-
I have the following deno script that calculates total watch time of videos in a folder in hours, minutes, & seconds: // Import required Deno modules
import { walk } from 'https://deno.land/std/fs/mod.ts'
import { exec } from 'https://deno.land/x/exec/mod.ts'
import * as path from 'https://deno.land/std/path/mod.ts'
// Function to calculate total watch time
async function calculateTotalWatchTime(folderPath: string): Promise<number[]> {
let totalDurationInSeconds = 0
// Iterate through files in the folder and its subfolders
for await (const entry of walk(folderPath, { includeDirs: false })) {
try {
// Check if the entry is a regular file and a video file
if (entry.isFile && isVideoFile(entry.name)) {
// Resolve the full path using Deno's path module
const realPath = path.resolve(folderPath, entry.name)
// Extract video duration using ffprobe with sexagesimal option
const videoMetadata = await extractVideoMetadata(realPath)
console.log({ videoMetadata })
// Accumulate the duration in seconds
totalDurationInSeconds += parseDurationToSeconds(videoMetadata.duration)
}
} catch (err) {
console.error(`Error processing file "${entry.name}": ${err.message}`)
}
}
// Convert total duration to hours, minutes, and seconds
const hours = Math.floor(totalDurationInSeconds / 3600)
const minutes = Math.floor((totalDurationInSeconds % 3600) / 60)
const seconds = totalDurationInSeconds % 60
return [hours, minutes, seconds]
}
// Function to check if the file is a video file
function isVideoFile(fileName: string): boolean {
return /\.(mp4|mkv|ts|webm)$/i.test(fileName)
}
// Function to extract video metadata using ffprobe with sexagesimal option
async function extractVideoMetadata(
filePath: string,
): Promise<{ duration: number }> {
// Run FFmpeg command to get video duration
const cmd = [
'ffprobe',
'-v',
'error',
'-show_entries',
'format=duration',
'-sexagesimal',
'-of',
'default=noprint_wrappers=1:nokey=1',
filePath,
]
const result = await exec(cmd)
// Parse the duration from the result
const duration = parseFloat(result.trim())
return { duration }
}
// Function to parse the duration in sexagesimal format to seconds
function parseDurationToSeconds(duration: string): number {
const [hours, minutes, seconds] = duration.split(':').map(parseFloat)
return hours * 3600 + minutes * 60 + seconds
}
// Get folder path from Deno.args
const [folderPath] = Deno.args
// Check if folderPath is provided
if (!folderPath) {
console.error('Please provide the folder path as an argument.')
Deno.exit(1)
}
// Calculate and log the total watch time
const totalWatchTime = await calculateTotalWatchTime(folderPath)
console.log(
`Total watch time: ${totalWatchTime[0]} hours, ${totalWatchTime[1]} minutes, ${totalWatchTime[2]} seconds.`,
) For some reason, it stopped working. And I have been trying to figure out for many hours but can't find a solution. This is mostly due to Windows file paths not handling spaces well it seems. The error is around the
How do I handle filepaths in Windows that include spaces? I have asked ChatGPT & Perplexity but both aren't able to solve it. I run it as: deno run --allow-run --allow-read .\video-time-calculator.ts '.\This is the end' |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Alright, found the solution. // Import required Deno modules
import { walk } from 'https://deno.land/std/fs/mod.ts'
import { exec } from 'https://deno.land/x/exec/mod.ts'
import * as path from 'https://deno.land/std/path/mod.ts'
// Function to calculate total watch time
async function calculateTotalWatchTime(folderPath: string): Promise<number[]> {
let totalDurationInSeconds = 0
const root = folderPath.replace(/"/g, '') // terminal bug that adds " if it foldername contains / at the end
// Iterate through files in the folder and its subfolders
for await (const entry of walk(root, { includeDirs: false })) {
try {
// Check if the entry is a regular file and a video file
if (entry.isFile && isVideoFile(entry.name)) {
// Resolve the full path using Deno's path module
const realPath = path.resolve(root, entry.name)
// Extract video duration using ffprobe with sexagesimal option
const { duration } = await extractVideoMetadata(entry.path)
// Accumulate the duration in seconds
totalDurationInSeconds += parseDurationToSeconds(duration)
}
} catch (err) {
console.error(`Error processing file "${entry.name}": ${err.message}`)
}
}
// Convert total duration to hours, minutes, and seconds
const hours = Math.floor(totalDurationInSeconds / 3600)
const minutes = Math.floor((totalDurationInSeconds % 3600) / 60)
const seconds = totalDurationInSeconds % 60
return [hours, minutes, seconds]
}
// Function to check if the file is a video file
function isVideoFile(fileName: string): boolean {
return /\.(mp4|mkv|ts|webm)$/i.test(fileName)
}
// Function to extract video metadata using ffprobe with sexagesimal option
async function extractVideoMetadata(filePath: string): Promise<{
duration: string
}> {
// Run FFmpeg command to get video duration
const cmd = [
'ffprobe',
'-v',
'error',
'-show_entries',
'format=duration',
'-sexagesimal',
'-of',
'default=noprint_wrappers=1:nokey=1',
filePath,
]
const process = await Deno.run({ cmd, stdout: 'piped' })
const decoder = new TextDecoder()
const output = await process.output()
const duration = decoder.decode(output)
return { duration }
}
// Function to parse the duration in sexagesimal format to seconds
function parseDurationToSeconds(duration: string): number {
const [hours, minutes, seconds] = duration.split(':').map(parseFloat)
return hours * 3600 + minutes * 60 + seconds
}
// Get folder path from Deno.args
const [folderPath] = Deno.args
// Check if folderPath is provided
if (!folderPath) {
console.error('Please provide the folder path as an argument.')
Deno.exit(1)
}
// Calculate and log the total watch time
const [hours, minutes, seconds] = await calculateTotalWatchTime(folderPath)
console.log(
`Total watch time: ${hours} hours, ${minutes} minutes, ${seconds.toFixed(
2,
)} seconds.`,
) |
Beta Was this translation helpful? Give feedback.
Alright, found the solution.