Skip to content

Commit 69c5c02

Browse files
committed
Initial commit
0 parents  commit 69c5c02

File tree

9 files changed

+242
-0
lines changed

9 files changed

+242
-0
lines changed

.editorconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
root = true
2+
3+
[*]
4+
end_of_line = lf
5+
trim_trailing_whitespace = true
6+
insert_final_newline = true
7+
charset = utf-8
8+
indent_style = space
9+
indent_size = 2

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto eol=lf

.github/workflows/main.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
on: push
2+
3+
jobs:
4+
build:
5+
runs-on: windows-2022
6+
steps:
7+
- uses: actions/checkout@v4
8+
- run: ./build.ps1
9+
- uses: softprops/action-gh-release@v2
10+
if: startsWith(github.ref, 'refs/tags/')
11+
with:
12+
draft: true
13+
files: build/*.js
14+
- uses: actions/upload-artifact@v4
15+
with:
16+
name: Build artifacts
17+
path: build/*.js

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/build/
2+
/.idea/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 PolarGoose
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# DirectoryOpus-FileMimeTypeAndEncodingColumns-plugin
2+
This plugin adds two columns, "MIME type" and "Encoding" using [UNIX file](https://man7.org/linux/man-pages/man1/file.1.html) utility.<br>
3+
The plugin uses the content of a file and not its extension.<br>
4+
The screenshot below shows how the encoding and MIME type are correctly determined, even for files with incorrect extensions.
5+
![Example](doc/screenshot.png)
6+
7+
# Prerequisites
8+
You need to have `file.exe` utility installed on your system. The easiest way to get it is to install [Git for Windows](https://git-scm.com/downloads/win)
9+
10+
# Limitations
11+
* The script has to call `file.exe` for each file in the folder. Thus, it might be very slow for big folders.
12+
* UNC paths (paths that start with `\\`) and FTP paths are not supported - the MIME type column will be empty
13+
14+
# How to use
15+
* Make sure `file.exe` is installed on your system
16+
* Download the `js` file from the [latest release](https://github.com/PolarGoose/DirectoryOpus-FileMimeTypeColumn-plugin/releases)
17+
* Copy the `js` file to the `%AppData%\GPSoftware\Directory Opus\Script AddIns` folder
18+
* The extra columns will become available in the `Settings`->`File Display Columns`->`Appearance`->`Columns:`.
19+
* By default, the script uses the `%ProgramFiles%/Git/usr/bin/file.exe` path. If it is installed in a different folder, you need to change the script configuration in the `Script management` menu.

build.ps1

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
Function Info($msg) {
2+
Write-Host -ForegroundColor DarkGreen "`nINFO: $msg`n"
3+
}
4+
5+
Function Error($msg) {
6+
Write-Host `n`n
7+
Write-Error $msg
8+
exit 1
9+
}
10+
11+
Function CheckReturnCodeOfPreviousCommand($msg) {
12+
if(-Not $?) {
13+
Error "${msg}. Error code: $LastExitCode"
14+
}
15+
}
16+
17+
Function GetVersion() {
18+
$gitCommand = Get-Command -ErrorAction Stop -Name git
19+
20+
try { $tag = & $gitCommand describe --exact-match --tags HEAD 2>$null } catch { }
21+
if(-Not $?) {
22+
$tag = "v0.0-dev"
23+
Info "The commit is not tagged. Use '$tag' as a version instead"
24+
}
25+
26+
$commitHash = & $gitCommand rev-parse --short HEAD
27+
CheckReturnCodeOfPreviousCommand "Failed to get git commit hash"
28+
29+
return "$($tag.Substring(1))~$commitHash"
30+
}
31+
32+
Set-StrictMode -Version Latest
33+
$ErrorActionPreference = "Stop"
34+
$ProgressPreference = "SilentlyContinue"
35+
$root = Resolve-Path "$PSScriptRoot"
36+
$buildDir = "$root/build"
37+
$version = GetVersion
38+
39+
Info "Copy the script to the build directory"
40+
New-Item -Force -ItemType "directory" $buildDir > $null
41+
Copy-Item -Force -Path $root/src/file-mime-type-and-encoding-columns.js -Destination $buildDir > $null
42+
43+
Info "Insert the version=$version in the script"
44+
(Get-Content $buildDir/file-mime-type-and-encoding-columns.js).Replace(
45+
" data.version = `"0.0-dev`"",
46+
" data.version = `"$version`"") | Set-Content $buildDir/file-mime-type-and-encoding-columns.js

doc/screenshot.png

57.7 KB
Loading
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
var shell = new ActiveXObject("WScript.shell")
2+
var fso = new ActiveXObject("Scripting.FileSystemObject")
3+
var fsu = DOpus.FSUtil()
4+
var stt = DOpus.Create().StringTools()
5+
6+
function OnInit(/* ScriptInitData */ data) {
7+
data.name = "File MIME type column using file.exe"
8+
data.desc = "Shows the MIME type using the file.exe utility"
9+
data.default_enable = true
10+
data.config_desc = DOpus.NewMap()
11+
data.config_desc("debug") = "Print debug messages to the script log"
12+
data.config.debug = false
13+
data.config_desc("fileExeFullName") = "Path to the 'file.exe' utility. You can get this utility by installing 'Git for Windows': https://git-scm.com/download/win"
14+
data.config.fileExeFullName = "%ProgramFiles%/Git/usr/bin/file.exe"
15+
data.version = "0.0-dev";
16+
data.url = "https://github.com/PolarGoose/DirectoryOpus-TabLabelizer-plugin";
17+
18+
var cmd = data.AddColumn()
19+
cmd.name = "File MIME type column using file.exe"
20+
cmd.method = "OnMimeTypeColumnDataRequested"
21+
cmd.label = "MIME type"
22+
cmd.autorefresh = true
23+
cmd.justify = "right"
24+
25+
var cmd = data.AddColumn()
26+
cmd.name = "File encoding column using file.exe"
27+
cmd.method = "OnEncodingColumnDataRequested"
28+
cmd.label = "Enconding"
29+
cmd.autorefresh = true
30+
cmd.justify = "right"
31+
}
32+
33+
function OnMimeTypeColumnDataRequested(/* ScriptColumnData */ data) {
34+
var fileFullName = data.item.realpath
35+
debug("OnFileType: fileFullName=" + fileFullName)
36+
37+
try {
38+
var fileType = getFileType(fileFullName)
39+
debug("fileType=" + fileType)
40+
data.value = fileType
41+
} catch (e) {
42+
debug("Exception:" + e)
43+
data.value = "<error>"
44+
}
45+
}
46+
47+
function OnEncodingColumnDataRequested(/* ScriptColumnData */ data) {
48+
var fileFullName = data.item.realpath
49+
debug("OnFileType: fileFullName=" + fileFullName)
50+
51+
try {
52+
var fileType = getEncoding(fileFullName)
53+
debug("fileType=" + fileType)
54+
data.value = fileType
55+
} catch (e) {
56+
debug("Exception:" + e)
57+
data.value = "<error>"
58+
}
59+
}
60+
61+
function getFileType(/* Path */ fileFullName) {
62+
var fileCommandLineArguments = "--mime-type --brief "
63+
return runFileExeAndReturnOutput(fileFullName, fileCommandLineArguments)
64+
}
65+
66+
function getEncoding(/* Path */ fileFullName) {
67+
var fileCommandLineArguments = "--mime --brief "
68+
var output = runFileExeAndReturnOutput(fileFullName, fileCommandLineArguments)
69+
if(output === "") {
70+
return ""
71+
}
72+
73+
// The output look like: "text/plain; charset=us-ascii". We need to get "us-ascii"
74+
var match = /charset=([^;\r\n]+)/.exec(output)
75+
if (match && match.length > 1) {
76+
return match[1]
77+
}
78+
79+
throw "Failed to get the text encoding. Output of file.exe: " + output
80+
}
81+
82+
function runFileExeAndReturnOutput(/* Path */ fileFullName, /* string */ fileCommandLineArguments) {
83+
// file.exe tool doesn't work for ftp and UNC paths
84+
if (fileFullName.pathpart.substr(0, 2) === "\\\\" || fileFullName.pathpart.substr(0, 3) === "ftp") {
85+
debug("Skip UNC or FTP path")
86+
return "";
87+
}
88+
89+
var command = '"' + Script.config.fileExeFullName + '" ' + fileCommandLineArguments + '"' + fileFullName + '"'
90+
return runCommandAndReturnOutput(command)
91+
}
92+
93+
function runCommandAndReturnOutput(/* string */ command) {
94+
var tempFileFullName = fsu.GetTempFilePath()
95+
var cmdLine = 'cmd.exe /c "' + command + ' > "' + tempFileFullName + '""'
96+
debug("shell.run " + cmdLine)
97+
98+
try {
99+
var exitCode = shell.run(cmdLine, 0, true)
100+
if (exitCode !== 0) {
101+
throw "Failed to execute the command. ExitCode=" + exitCode
102+
}
103+
104+
var content = readAllText(tempFileFullName)
105+
if (content.indexOf("cannot open") === 0) {
106+
throw "File.exe failed. Output of File.exe: " + content
107+
}
108+
109+
return content
110+
}
111+
finally {
112+
fso.DeleteFile(tempFileFullName)
113+
}
114+
}
115+
116+
function readAllText(/* string */ fileFullName) {
117+
var handle = fsu.OpenFile(fileFullName)
118+
var content = stt.Decode(handle.Read(), "utf8")
119+
handle.Close()
120+
return content
121+
}
122+
123+
function debug(text) {
124+
if (Script.config.debug) {
125+
DOpus.Output(text)
126+
}
127+
}

0 commit comments

Comments
 (0)