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
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ Run `onedrive help` (or `-h`/`--help`) for this list at any time, and
- `mcp` - run a read-only [MCP](https://modelcontextprotocol.io) server over stdio
- `mkdir` - create a remote folder
- `mv` - move a local file to OneDrive or vice-versa
- `realpath` - print the View Online URL of a remote or locally synced file
- `rm` - delete a file or folder from OneDrive
- `sendmail` - send an invitation email for editing to recipients
- `stat` - dump all information for particular file(s)
Expand Down Expand Up @@ -90,6 +91,20 @@ Run `onedrive help` (or `-h`/`--help`) for this list at any time, and

`onedrive find 'Pictures/Camera Roll' -regex 2015 -type f -print0 | xargs -0 onedrive mv -t :/Pictures/2015/`

##### Get the web address of a file

`realpath` prints the item's own _View Online_ URL, which exists whether or not
the file has ever been shared. It accepts a remote path, or a local path inside
the folder the OneDrive sync client mirrors:

```sh
onedrive realpath Documents/report.docx
onedrive realpath ~/OneDrive/Documents/report.docx
```

To hand someone else access instead, use `ln`: that creates a new sharing
permission and prints _its_ link, which `chmod` can later downgrade or revoke.

##### Create an album and add photos to it

```sh
Expand Down Expand Up @@ -185,6 +200,7 @@ so this stays a pointer rather than a second source of truth:

## DONE

- Print the View Online URL of a file (`onedrive realpath`)
- Read-only [MCP](https://modelcontextprotocol.io) server (`onedrive mcp`)
- Photo albums via bundles (`onedrive album`)
- Full-text search across the drive (`onedrive grep`)
Expand Down
75 changes: 74 additions & 1 deletion bin/onedrive
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,76 @@ async function stat(args) {
}
}

// OneDrive's sync clients mirror the drive into one of a handful of well-known
// directories. The `OneDrive*` variables are set by the Windows client; the
// rest are the defaults elsewhere.
async function syncRoots() {
const home = require('os').homedir()
const roots = [
process.env.OneDrive,
process.env.OneDriveConsumer,
process.env.OneDriveCommercial,
Path.join(home, 'OneDrive'),
].filter(Boolean)
// macOS mounts the drive under ~/Library/CloudStorage as OneDrive-Personal,
// or OneDrive-<Tenant> for work accounts, so the leaf name is not fixed.
const cloud = Path.join(home, 'Library', 'CloudStorage')
try {
const names = await FS.readdir(cloud)
roots.push(
...names
.filter(name => name.startsWith('OneDrive'))
.map(name => Path.join(cloud, name))
)
} catch {
// No ~/Library/CloudStorage: not a Mac, or nothing is mounted there.
}
return roots
}

// Compared case-insensitively: every platform running the sync client has a
// case-insensitive filesystem by default.
function stripPrefix(path, root) {
const prefix = root.endsWith(Path.sep) ? root : root + Path.sep
return path.toLowerCase().startsWith(prefix.toLowerCase())
? path.slice(prefix.length)
: undefined
}

// Only an explicitly local-looking path can name a file in the sync folder, so
// a bare `Documents/report.docx` stays remote the way it is for every other
// command. An absolute path that is not inside a sync folder stays remote too.
async function localToRemote(file) {
if (!/^([~.]|\/|\\|[A-Za-z]:)/.test(file)) {
return undefined
}
const home = require('os').homedir()
const abs = Path.resolve(file.replace(/^~(?=[/\\]|$)/, home))
for (const root of await syncRoots()) {
const rel = stripPrefix(abs, Path.resolve(root))
if (rel !== undefined) {
return rel.split(Path.sep).join('/')
}
}
return undefined
}

async function realpath1(file) {
// `webUrl` is the item's own address and exists whether or not it has ever
// been shared -- unlike the sharing link `ln` mints (#12).
const result = await getItem((await localToRemote(file)) ?? file)
console.log(Colors.underline(result.webUrl))
}

async function realpath(args) {
if (args.length === 0) {
args = ['']
}
for (const cur of args) {
await realpath1(cur)
}
}

async function find_paged(cont, expression) {
if (cont === undefined) {
return
Expand Down Expand Up @@ -1711,7 +1781,7 @@ async function main(argv) {
console.log(
'\nusage: ' +
commandName() +
' COMMAND [arguments]\n\ncommands: album albums cat chmod cp df find grep help ln login ls mcp mkdir mv rm sendmail stat wget'
' COMMAND [arguments]\n\ncommands: album albums cat chmod cp df find grep help ln login ls mcp mkdir mv realpath rm sendmail stat wget'
)
return

Expand Down Expand Up @@ -1762,6 +1832,9 @@ async function main(argv) {
case 'mv':
return mv(argv.slice(3))

case 'realpath':
return realpath(argv.slice(3))

case 'rm':
return rm(argv.slice(3))

Expand Down
14 changes: 14 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,7 @@ <h2>Usage</h2>
<li> <code>mcp</code> - run a read-only <a href="https://modelcontextprotocol.io">MCP</a> server over stdio</li>
<li> <code>mkdir</code> - create a remote folder</li>
<li> <code>mv</code> - move a local file to OneDrive or vice-versa</li>
<li> <code>realpath</code> - print the View Online URL of a remote or locally synced file</li>
<li> <code>rm</code> - delete a file or folder from OneDrive</li>
<li> <code>sendmail</code> - send an invitation email for editing to recipients</li>
<li> <code>stat</code> - dump all information for particular file(s)</li>
Expand Down Expand Up @@ -521,6 +522,19 @@ <h5>Move remote files to a new folder</h5>

<p><code>onedrive find &#39;Pictures/Camera Roll&#39; -regex 2015 -type f -print0 | xargs -0 onedrive mv -t :/Pictures/2015/</code></p>

<h5>Get the web address of a file</h5>

<p><code>realpath</code> prints the item&#39;s own <em>View Online</em> URL, which exists whether or not
the file has ever been shared. It accepts a remote path, or a local path inside
the folder the OneDrive sync client mirrors:</p>

<pre><code class="sh">onedrive realpath Documents/report.docx
onedrive realpath ~/OneDrive/Documents/report.docx
</code></pre>

<p>To hand someone else access instead, use <code>ln</code>: that creates a new sharing
permission and prints <em>its</em> link, which <code>chmod</code> can later downgrade or revoke.</p>

<h5>Create an album and add photos to it</h5>

<pre><code class="sh">onedrive album create &#39;Summer 2026&#39;
Expand Down