Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yank Note 使用分享 #65

Open
purocean opened this issue Nov 6, 2021 · 17 comments
Open

Yank Note 使用分享 #65

purocean opened this issue Nov 6, 2021 · 17 comments

Comments

@purocean purocean pinned this issue Nov 6, 2021
@purocean
Copy link
Owner Author

purocean commented Nov 6, 2021

我日常使用的一些小工具

  • File to Base64
  • SVG to Markdown Image
  • SVG to PNG
  • Unix 时间戳
  • URL 编码解码
  • Hash
  • Base64
  • 进制转换
点击展开代码
# 小工具

```html
<!-- --applet-- File to Base64 -->
<script>
async function change (files) {
    const result = await ctx.utils.fileToBase64URL(files[0])
    document.getElementById('result').value = result
}
</script>

<input type="file" onchange="change(this.files)">
<textarea id="result"></textarea>
<button onclick="ctx.utils.copyText(document.getElementById('result').value)">拷贝</button>
```

```html
<!-- --applet-- SVG to Markdown Image -->

<script>
function run (type) {
    const input = document.getElementById('input')
    const output = document.getElementById('output')
    output.value = ''

    output.value = `![](data:image/svg+xml;base64,${ctx.lib.cryptojs.enc.Base64.stringify(ctx.lib.cryptojs.enc.Utf8.parse(input.value))})`
    // output.value = `data:image/svg+xml;base64,${ctx.lib.cryptojs.enc.Base64.stringify(ctx.lib.cryptojs.enc.Utf8.parse(input.value))}`

    output.focus()
    output.select()
}
</script>

<div>
    输入
    <textarea id="input" style="display: block; width: 100%"></textarea>
    <button onclick="run('encodeBase64')">Base64 编码</button>
    <textarea id="output" style="display: block; width: 100%"></textarea>
    <button onclick="document.getElementById('input').value = ''; document.getElementById('output').value = ''">清空</button>
</div>
```

```html
<!-- --applet-- SVG to PNG -->

<script>
function svgToPng(svg, callback) {
    const url = getSvgUrl(svg);
    svgUrlToPng(url, (imgData) => {
        callback(imgData);
        URL.revokeObjectURL(url);
    });
}

function getSvgUrl(svg) {
    return  URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' }));
}

function svgUrlToPng(svgUrl, callback) {
    const svgImage = document.createElement('img');
    // imgPreview.style.position = 'absolute';
    // imgPreview.style.top = '-9999px';
    document.body.appendChild(svgImage);
    svgImage.onload = function () {
        const canvas = document.createElement('canvas');
        canvas.width = svgImage.clientWidth;
        canvas.height = svgImage.clientHeight;
        const canvasCtx = canvas.getContext('2d');
        canvasCtx.drawImage(svgImage, 0, 0);
        const imgData = canvas.toDataURL('image/png');
        callback(imgData);
        setTimeout(() => {
            this.remove()
        }, 300)
    };
    svgImage.src = svgUrl;
}

function run (type) {
    const input = document.getElementById('input')
    const output = document.getElementById('output')
    output.value = ''

    svgUrlToPng(input.value, imgData => {
        output.value = imgData
        output.focus()
        output.select()
    });
}
</script>

<div>
    输入
    <input id="input" style="display: block; width: 100%" placeholder="DATA URL">
    <button onclick="run()">转换</button>
    <textarea id="output" style="display: block; width: 100%"></textarea>
</div>
```

```html
<!-- --applet-- Unix 时间戳 -->
  
<script>
function run (type) {
    const input = document.getElementById('input')
    const output = document.getElementById('output')
    const now = ctx.lib.dayjs()
    output.value = ''

    switch (type) {
        case 'current':
            input.value = now.format('YYYY-MM-DD HH:mm:ss')
            output.value = parseInt(now.valueOf() / 1000)
            break
        case 'current-ms':
            input.value = now.format('YYYY-MM-DD HH:mm:ss SSS')
            output.value = now.valueOf()
            break
        case 'a2b':
            output.value = parseInt(ctx.lib.dayjs(input.value).valueOf() / 1000)
            break
        case 'a2b-ms':
            output.value = ctx.lib.dayjs(input.value).valueOf()
            break
        case 'b2a':
            output.value = ctx.lib.dayjs(input.value * 1000).format('YYYY-MM-DD HH:mm:ss')
            break
        case 'b2a-ms':
            output.value = ctx.lib.dayjs(input.value * 1).format('YYYY-MM-DD HH:mm:ss SSS')
            break
    }
    output.focus()
    output.select()
}
</script>

<div>
    输入
    <input id="input" style="display: block; width: 100%">
    <button onclick="run('a2b')">时间->戳值</button>
    <button onclick="run('b2a')">戳值->时间</button>
    <button onclick="run('current')">当前时间</button>
    <button onclick="run('a2b-ms')">时间->戳值ms</button>
    <button onclick="run('b2a-ms')">戳值ms->时间</button>
    <button onclick="run('current-ms')">当前时间ms</button>
    <button style="float: right" onclick="document.getElementById('input').value = ''; document.getElementById('output').value = ''">清空</button>
    <input id="output" style="display: block; width: 100%">
</div>
```

```html
<!-- --applet-- URL 编码解码 -->

<script>
function init () {
    // console.log('初始化', appletId, appletFrame, resize, Vue)
}

function run (type) {
    const input = document.getElementById('input')
    const output = document.getElementById('output')
    output.value = ''

    switch (type) {
        case 'encodeURI':
            output.value = encodeURI(input.value)
            break
        case 'encodeURIComponent':
            output.value = encodeURIComponent(input.value)
            break
        case 'decodeURI':
            output.value = decodeURI(input.value)
            break
        case 'decodeURIComponent':
            output.value = decodeURIComponent(input.value)
            break
        case 'encodeURIfull':
            output.value = '%' + [...input.value].map(x => x.charCodeAt().toString(16)).join('%')
            break
    }
    output.focus()
    output.select()
}
</script>

<div>
    输入2021-11-06 23:58:28    <textarea id="input" style="display: block; width: 100%"></textarea>
    <button onclick="run('encodeURIfull')">URL 完全编码</button>
    <button onclick="run('encodeURI')">encodeURI</button>
    <button onclick="run('encodeURIComponent')">encodeURIComponent</button>
    <button onclick="run('decodeURI')">decodeURI</button>
    <button onclick="run('decodeURIComponent')">decodeURIComponent</button>
    <textarea id="output" style="display: block; width: 100%"></textarea>
    <button onclick="document.getElementById('input').value = ''; document.getElementById('output').value = ''">清空</button>
    <button onclick="var x = document.getElementById('output'); x.value = x.value.toUpperCase()">结果大写</button>
</div>
```

```html
<!-- --applet-- Hash -->

<script>
function run (type) {
    const input = document.getElementById('input')
    const output = document.getElementById('output')
    output.value = ''

    switch (type) {
        case 'md5':
            output.value = ctx.lib.cryptojs.MD5(input.value).toString().toLowerCase()
            break
        case 'sha1':
            output.value = ctx.lib.cryptojs.SHA1(input.value).toString().toLowerCase()
            break
        case 'sha256':
            output.value = ctx.lib.cryptojs.SHA256(input.value).toString().toLowerCase()
            break
    }
    output.focus()
    output.select()
}
</script>

<div>
    输入
    <textarea id="input" style="display: block; width: 100%"></textarea>
    <button onclick="run('md5')">MD5</button>
    <button onclick="run('sha1')">SHA1</button>
    <button onclick="run('sha256')">SHA256</button>
    <textarea id="output" style="display: block; width: 100%"></textarea>
    <button onclick="document.getElementById('input').value = ''; document.getElementById('output').value = ''">清空</button>
    <button onclick="var x = document.getElementById('output'); x.value = x.value.toUpperCase()">结果大写</button>
</div>
```

```html
<!-- --applet-- Base64 -->

<script>
function run (type) {
    const input = document.getElementById('input')
    const output = document.getElementById('output')
    output.value = ''

    switch (type) {
        case 'encodeBase64':
            output.value = ctx.lib.cryptojs.enc.Base64.stringify(
                ctx.lib.cryptojs.enc.Utf8.parse(input.value)
            );
            break
        case 'decodeBase64':
            output.value = ctx.lib.cryptojs.enc.Base64.parse(input.value)
                .toString(ctx.lib.cryptojs.enc.Utf8);
            break
    }
    output.focus()
    output.select()
}
</script>

<div>
    输入
    <textarea id="input" style="display: block; width: 100%"></textarea>
    <button onclick="run('encodeBase64')">Base64 编码</button>
    <button onclick="run('decodeBase64')">Base64 解码</button>
    <textarea id="output" style="display: block; width: 100%"></textarea>
    <button onclick="document.getElementById('input').value = ''; document.getElementById('output').value = ''">清空</button>
</div>
```

```html
<!-- --applet-- 进制 -->

<script>
function run (type) {
    const input = document.getElementById('input')
    const prefix = document.getElementById('prefix')
    const output = document.getElementById('output')
    output.value = ''

    switch (type) {
        case 'encodeHex':
            output.value = prefix.value + [...input.value].map(x => x.charCodeAt().toString(16)).join(prefix.value)
            break
        // case 'decodeHex':
        //     output.value = prefix.value + [...input.value].map(x => x.charCodeAt().toString(16)).join(prefix.value)
        //     break
    }
    output.focus()
    output.select()
}
</script>

<div>
    前导
    <input id="prefix" value="\x" style="display: block; width: 100%">
    输入
    <textarea id="input" style="display: block; width: 100%"></textarea>
    <button onclick="run('encodeHex')">HEX编码</button>
    <textarea id="output" style="display: block; width: 100%"></textarea>
    <button onclick="document.getElementById('input').value = ''; document.getElementById('output').value = ''">清空</button>
    <button onclick="var x = document.getElementById('output'); x.value = x.value.toUpperCase()">结果大写</button>
</div>
```

@purocean
Copy link
Owner Author

purocean commented Nov 6, 2021

Tello 遥控器

视频:https://www.bilibili.com/video/BV1W34y1Z7jf

image

点击展开代码
# Tello 遥控器{style="color:#00ffe9"}

使用 Markdown 控制 Tello

```html
<!-- --applet-- Tello 遥控器 -->
<script>
function exec (cmd) {
    ctx.ui.useToast().show('info', cmd);
    ctx.api.runCode('bash', `echo '${cmd}' | nc -cuw 1 192.168.10.1 8889`)
}
</script>


<div style="display: flex;justify-content: space-between">
    <div>
    <button onclick="exec('takeoff')">起飞</button>
    <button onclick="exec('land')">降落</button>
    </div>
    <button onclick="exec('command')">连接</button>
</div>
<br>
<br>
<div style="display: flex;justify-content: space-between">
    <div>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button onclick="exec('up 20')">上</button>
        <br>
        <br>
        <button onclick="exec('cw 20')">逆</button> &nbsp;&nbsp;&nbsp;&nbsp;
        <button onclick="exec('ccw 20')">顺</button>
        <br>
        <br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button onclick="exec('down 20')">下</button>
    </div>
    <div>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button onclick="exec('forward 20')">前</button>
        <br>
        <br>
        <button onclick="exec('left 20')">左</button> &nbsp;&nbsp;&nbsp;&nbsp;
        <button onclick="exec('right 20')">右</button>
        <br>
        <br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button onclick="exec('back 20')">后</button>
    </div>
</div>
```

@purocean
Copy link
Owner Author

purocean commented Nov 6, 2021

⚠️ 下面两个功能,都可以在拓展中心安装扩展来实现

Git 推送按钮

推送到 Git 仓库这个功能,现在可以编写插件实现。

window.registerPlugin({
  name: 'git-push',
  register: ctx => {
    ctx.statusBar.tapMenus(menus => {
      menus['git-push'] = {
        id: 'git-push',
        position: 'left',
        title: 'Git 提交',
        onClick: () => {
          const currentRepo = ctx.store.state.currentRepo;
          const path = currentRepo && currentRepo.path
          if (path) {
            ctx.action.getActionHandler('xterm.run')(`cd '${path}' && git add . && git ci -m 'update' && git push && exit`)
          }
        }
      }
    })
  }
});

将上述代码编写 git-push.js 文件放入<主目录>/plugins/ 中即可。(可在托盘菜单中打开主目录)

右键 Sublime Merge 菜单

window.registerPlugin({
  name: 'file-tree-context-menu-sublime-merge',
  register: ctx => {
    ctx.tree.tapContextMenus((items, node) => {
      const openInSublimeMerge = () => {
        const currentRepo = ctx.store.state.currentRepo;
        const path = currentRepo ? currentRepo.path + node.path : ''
        if (path) {
          if (node.type === 'dir') {
            ctx.api.runCode('bash', `smg '${path}'`);
          } else {
            ctx.api.runCode('bash', `cd '${currentRepo.path}' && smg blame '${path}'`);
          }
        }
      }

      if (node.type === 'file' || (node.type === 'dir' && node.path === '/')) {
        items.push(
          { type: 'separator' },
          { id: 'openInSublimeMerge', label: '在 Sublime Merge 中打开', onClick: openInSublimeMerge }
        );
      }

      return items;
    })
  }
});

注:苹果应用商店的版本因为审核原因不支持终端功能,上面的插件无效

@purocean purocean changed the title Yank Note 使用案例 Yank Note 使用分享 Nov 6, 2021
@purocean
Copy link
Owner Author

purocean commented Nov 17, 2021

在文档中嵌入天气预报

image

---
enableMacro: true
---

```{onclick="ctx.view.refresh()"}
Updated at: [= $ctx.lib.dayjs().format('YYYY-MM-DD HH:mm') =]

[= fetch('https://wttr.in?0AT').then(r => r.text()) =]
```

@purocean
Copy link
Owner Author

purocean commented Dec 6, 2021

流畅的编辑体验

Untitled

转换链接和图片

Untitled

Emoji
Untitled

路径补全

Untitled

@dislazy
Copy link

dislazy commented Feb 12, 2022

authelia 这个和yn配合 既能兼顾安全,也能兼顾内容

@purocean
Copy link
Owner Author

因为沙盒和审核机制的限制,Mac App Store 的 Yank Note 有如下缺陷:

  1. 没有内置终端
  2. 不能使用“在浏览器中打开”功能
  3. 不能使用“分享”功能
  4. 代码运行功能受限
  5. 一些插件能力受限,如上面的 “Git 提交” 插件
  6. 沙盒可能会产生一些问题 [BUG]: macOS 运行 Python 代码产生 spawn EPERM 错误 #102 app store下载安装后启动闪退 #83

如果你更注重内容安全,可以使用 Mac App Store 的版本,否则还是使用 GitHub 的版本吧。

@zhwei820
Copy link

GitJournal
https://github.com/GitJournal/GitJournal
yn 现在只支持桌面版, 有时候我们想在手机上做点记录(记录),然后传到笔记上。
找了好久,找到这个移动端配合的比较好软件,分享给大家。
支持 Android/ios

Screenshot_20221027_090434_io gitjournal gitjournal

@JACKDELAY
Copy link

Git 推送按钮

推送到 Git 仓库这个功能,现在可以编写插件实现。

window.registerPlugin({
  name: 'git-push',
  register: ctx => {
    ctx.statusBar.tapMenus(menus => {
      menus['git-push'] = {
        id: 'git-push',
        position: 'left',
        title: 'Git 提交',
        onClick: () => {
          const currentRepo = ctx.store.state.currentRepo;
          const path = currentRepo && currentRepo.path
          if (path) {
            ctx.action.getActionHandler('xterm.run')(`cd '${path}' && git add . && git ci -m 'update' && git push && exit`)
          }
        }
      }
    })
  }
});

将上述代码编写 git-push.js 文件放入<主目录>/plugins/ 中即可。(可在托盘菜单中打开主目录)

右键 Sublime Merge 菜单

window.registerPlugin({
  name: 'file-tree-context-menu-sublime-merge',
  register: ctx => {
    ctx.tree.tapContextMenus((items, node) => {
      const openInSublimeMerge = () => {
        const currentRepo = ctx.store.state.currentRepo;
        const path = currentRepo ? currentRepo.path + node.path : ''
        if (path) {
          if (node.type === 'dir') {
            ctx.api.runCode('bash', `smg '${path}'`);
          } else {
            ctx.api.runCode('bash', `cd '${currentRepo.path}' && smg blame '${path}'`);
          }
        }
      }

      if (node.type === 'file' || (node.type === 'dir' && node.path === '/')) {
        items.push(
          { type: 'separator' },
          { id: 'openInSublimeMerge', label: '在 Sublime Merge 中打开', onClick: openInSublimeMerge }
        );
      }

      return items;
    })
  }
});

注:苹果应用商店的版本因为审核原因不支持终端功能,上面的插件无效

你好,不是非常能理解主目录是哪个程序的主目录,希望能有个更详细的教程,谢谢!

@purocean
Copy link
Owner Author

purocean commented Jan 6, 2023

@JACKDELAY 这个两个功能你都可以在扩展中心安装相应插件来实现。如果你需要自己编写插件,可以参考帮助文档
image

@JACKDELAY
Copy link

JACKDELAY commented Jan 6, 2023 via email

@JACKDELAY
Copy link

JACKDELAY commented Jan 6, 2023 via email

@dapaipai
Copy link

如果大纲可以折叠就好了,这样超长文本不会显示的太乱

@Ethanaslincy
Copy link

刚开始用yn, 觉得不错. 之前用Obsidian, 一个小需求:
写大纲的时候, 我习惯先把要连接的md文件名定义好, 后面再直接点大纲 进md文件写内容, 这个时候yn是提示文件不存在.
如果点大纲的时候, md 文件不存在能直接新建一个 就更好了,或者提示一下是否新建, 让用户选择.
BTW, Obsidian 和Typora 都是可以的. thanks.

@Ethanaslincy
Copy link

今早上更了[3.56.4] ,已经提示新建文件了, 更顺手啦. ,必须点赞啊

@Ethanaslincy
Copy link

Ethanaslincy commented Aug 9, 2023

最近用yn写的文章内容有点大, 单页的内容多的时候, 编辑器就特别卡, 编辑模式的键盘响应好慢啊...影响效率, 不知道有没有优化手段?

@purocean
Copy link
Owner Author

purocean commented May 20, 2024

暴力破解加密文档的脚本

找个文档写入下面的脚本,改一下读取文件的代码 repo 和 path,点击运行

```js
// --run--
const { content } = await ctx.api.readFile({ repo: 'test', path: '/log.c.md' })

let count = 0

async function hack (password) {
    try {
        count++

        if (count % 100000 === 0) {
            console.log('已尝试', count, '', password)
            await ctx.utils.sleep(20)
        }

        ctx.utils.crypto.decrypt(content, password)
        ctx.ui.useModal().alert({title: '破解成功', content: '密码是:' + password})
        console.log('破解成功,密码是:' + password)
        return true
    } catch (e) {
        return false
    }
}

async function hackPasswords(minLength, maxLength) {
    const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

    async function helper(prefix, length) {
        if (length === 0) {
            if ((await hack(prefix))) {
                throw new Error('破解完成')
            }
            return;
        }

        for (let i = 0; i < characters.length; i++) {
            await helper(prefix + characters[i], length - 1);
        }
    }

    for (let length = minLength; length <= maxLength; length++) {
       await helper('', length);
    }
}

console.log('破解中,请不要关闭应用……')
await ctx.utils.sleep(100)
hackPasswords(2, 4)
```

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants