PowerShell - 更改 MP4 元数据(右键单击属性)

问题描述 投票:0回答:1

我一直在尝试找到一种方法来编辑“标签”部分,将其与 MP4 的“标题”部分交换。

问题是我无法使用 ExiftTool、MP3Tag、MediaMonkey 执行此操作,尝试手动右键单击并更改每个文件的标签简直就是一场噩梦。

我最接近的是一个名为 MP4 Video & Auto Tag Editor 的应用程序,因为它可以让您编辑 Microsoft Xtra Atoms,但可惜...它没有办法对整个目录执行此操作

我找到了这个 PowerShell 脚本,它显示了所有元数据。

但是,我不知道如何准确编辑“标签”部分以实际自定义和交易值。我知道 ExiftTool 只能“读”而不能“写”,所以我最大的担心是我面临同样的问题。

SRCDIRECTORY代表我正在使用的目录...

Function Get-MP3MetaData 
{ 
    [CmdletBinding()] 
    [Alias()] 
    [OutputType([Psobject])] 
    Param 
    ( 
        [String] [Parameter(Mandatory=$true, ValueFromPipeline=$true)] $Directory 
    ) 
 
    Begin 
    { 
        $shell = New-Object -ComObject "Shell.Application" 
    } 
    Process 
    { 
 
        Foreach($Dir in $Directory) 
        { 
            $ObjDir = $shell.NameSpace($Dir) 
            $Files = gci $Dir| ?{$_.Extension -in '.mp3','.mp4'} 
 
            Foreach($File in $Files) 
            { 
                $ObjFile = $ObjDir.parsename($File.Name) 
                $MetaData = @{} 
                $MP3 = ($ObjDir.Items()|?{$_.path -like "*.mp3" -or $_.path -like "*.mp4"}) 
                $PropertArray = 0,1,2,12,13,14,15,16,17,18,19,20,21,22,27,28,36,220,223 
             
                Foreach($item in $PropertArray) 
                {  
                    If($ObjDir.GetDetailsOf($ObjFile, $item)) #To avoid empty values 
                    { 
                        $MetaData[$($ObjDir.GetDetailsOf($MP3,$item))] = $ObjDir.GetDetailsOf($ObjFile, $item) 
                    } 
                  
                } 
             
                New-Object psobject -Property $MetaData |select *, @{n="Directory";e={$Dir}}, @{n="Fullname";e={Join-Path $Dir $File.Name -Resolve}}, @{n="Extension";e={$File.Extension}} 
            } 
        } 
    } 
    End 
    { 
    } 
} 


ForEach($item in ("SRCDIRECTORY" |Get-MP3MetaData)){ 
    $itemTitle = $item.Title 
    $itemTags = $item.Tags
}
windows powershell mp4 exiftool microsoft-file-explorer
1个回答
0
投票

虽然我无法找到“纯”PowerShell 方法来执行此操作,但这里有一篇与如何在 C# 中执行此操作相关的类似帖子:https://stackoverflow.com/a/24053204/433069此人回答的要点是使用(历史上 Microsoft 支持的)Windows® API Code Pack for Microsoft® .NET Framework,然后使用此代码段(这是此代码的 C# 版本):

var shellFile = ShellFile.FromParsingName(filePath);
ShellPropertyWriter w = shellFile.Properties.GetPropertyWriter();
w.WriteProperty(SystemProperties.System.Title, "New Title");
w.Close();

问题是微软不再提供这个API代码包(至少在我的搜索中)。然而,一些开发人员复制了源代码并将其发布到 GitHub here

这为微软如何做到这一点提供了有趣的见解。

如果您查看 C# 代码,您会发现最终它们会调用以下 Shell 类 IShellItem2::GetPropertyStore,然后调用 IPropertyStore::SetValue,但是这些是 C++ API,它们不会似乎是通过 COM 公开的,这意味着(据我所知)PowerShell 中没有直接的方法来实现此目的。

这里有一个有趣的讨论是否有可能获取不在 shell 命名空间中的项目的 shell 属性?其中该开发人员尝试以各种方式访问此接口,但运气不佳。我相信那里提供的解决方案只会得到您读取了对属性的访问权限(我很愿意纠正)。

理论上,如果您想运送“含电池”,您可以重写 Windows API 代码包的相关部分,然后根据需要

Add-Type
将它们放入。然而对我来说,我只是想让一些东西发挥作用。

因此,我提取了该项目生成的两个 NuGet 包(

windowsapicodepack-core.1.1.2
windowsapicodepack-shell.1.1.1
),将 DLL(
Microsoft.WindowsAPICodePack.dll
Microsoft.WindowsAPICodePack.Shell.dll
)提取到与我的脚本相同的路径中,然后编写了以下内容:

$targetFile = "C:\temp\Sample.mp4"

Add-Type -Path $PSScriptRoot\Microsoft.WindowsAPICodePack.Shell.dll

$shellFile = [Microsoft.WindowsAPICodePack.Shell.ShellFile]::FromFilePath($targetFile)
$propertyWriter = $shellFile.Properties.GetPropertyWriter()
$titlePropertyKey = [Microsoft.WindowsAPICodePack.Shell.PropertySystem.PropertyKey]::new([Guid]::new("{F29F85E0-4FF9-1068-AB91-08002B27B3D9}"), 2)
$propertyWriter.WriteProperty($titlePropertyKey, "New Title")
$propertyWriter.Close()

它是 C# 代码的粗略音译。最大的问题是我无法加载静态属性类型(

Microsoft.WindowsAPICodePack.Shell.PropertySystem.SystemProperties.System.Title
),所以我最终像静态类一样重新创建了
PropertyKey

我可以确认这适用于我拥有的几个示例文件。

© www.soinside.com 2019 - 2024. All rights reserved.