Add hf-clone-with-local-dir.user.js
This commit is contained in:
commit
a5c8dfd47b
1 changed files with 125 additions and 0 deletions
125
hf-clone-with-local-dir.user.js
Normal file
125
hf-clone-with-local-dir.user.js
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
// ==UserScript==
|
||||||
|
// @name HF Clone Modal - Add hf download with --local-dir
|
||||||
|
// @namespace https://kyu.sh/
|
||||||
|
// @version 1.0
|
||||||
|
// @description Hugging Face clone repository 모달에 --local-dir 포함 hf download 명령어 + 복사 버튼 추가
|
||||||
|
// @match https://huggingface.co/*
|
||||||
|
// @grant none
|
||||||
|
// @run-at document-idle
|
||||||
|
// ==/UserScript==
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const PROCESSED = 'data-hf-localdir-added';
|
||||||
|
|
||||||
|
function makeLocalDir(repoId) {
|
||||||
|
// lcw99/wikipedia-korean-20240501 -> lcw99-wikipedia-korean-20240501
|
||||||
|
return repoId.replace(/\//g, '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCopyButton(getText) {
|
||||||
|
// 기존 복사 버튼 마크업을 모방
|
||||||
|
const btn = document.createElement('button');
|
||||||
|
btn.type = 'button';
|
||||||
|
btn.className =
|
||||||
|
'z-1 ml-4 mt-4 sm:mr-6 sm:absolute sm:top-0 sm:right-0 focus:outline-hidden inline-flex cursor-pointer items-center text-sm bg-white shadow-xs rounded-md border px-2 py-1 text-gray-600';
|
||||||
|
btn.title = 'Copy snippet to clipboard';
|
||||||
|
btn.innerHTML =
|
||||||
|
'<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z"></path><rect fill="none" width="32" height="32"></rect></svg>';
|
||||||
|
|
||||||
|
btn.addEventListener('click', async () => {
|
||||||
|
const text = getText();
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(text);
|
||||||
|
} catch {
|
||||||
|
const ta = document.createElement('textarea');
|
||||||
|
ta.value = text;
|
||||||
|
ta.style.position = 'fixed';
|
||||||
|
ta.style.left = '-9999px';
|
||||||
|
document.body.appendChild(ta);
|
||||||
|
ta.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
document.body.removeChild(ta);
|
||||||
|
}
|
||||||
|
const orig = btn.style.color;
|
||||||
|
btn.style.color = '#16a34a';
|
||||||
|
setTimeout(() => (btn.style.color = orig), 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
function processModal(modal) {
|
||||||
|
const pres = modal.querySelectorAll('pre');
|
||||||
|
for (const pre of pres) {
|
||||||
|
const text = pre.textContent || '';
|
||||||
|
const m = text.match(
|
||||||
|
/hf\s+download\s+(\S+)(?:\s+--repo-type=(\S+))?/
|
||||||
|
);
|
||||||
|
if (!m) continue;
|
||||||
|
|
||||||
|
// 이미 --local-dir 이 들어있으면 skip
|
||||||
|
if (text.includes('--local-dir')) continue;
|
||||||
|
|
||||||
|
const repoId = m[1];
|
||||||
|
const repoType = m[2]; // undefined 가능
|
||||||
|
const localDir = makeLocalDir(repoId);
|
||||||
|
const repoTypeFlag = repoType ? ` --repo-type=${repoType}` : '';
|
||||||
|
const newCmd =
|
||||||
|
`hf download ${repoId}${repoTypeFlag} --local-dir="${localDir}"`;
|
||||||
|
|
||||||
|
const container = pre.closest('.relative.border-t') || pre.parentElement;
|
||||||
|
if (!container || container.hasAttribute(PROCESSED)) continue;
|
||||||
|
container.setAttribute(PROCESSED, '1');
|
||||||
|
|
||||||
|
const block = document.createElement('div');
|
||||||
|
block.className = 'relative border-t border-gray-100';
|
||||||
|
block.setAttribute(PROCESSED, '1');
|
||||||
|
|
||||||
|
const copyBtn = buildCopyButton(() => newCmd);
|
||||||
|
|
||||||
|
const inner = document.createElement('div');
|
||||||
|
inner.className = 'overflow-x-auto pl-4 pb-6 sm:pl-6';
|
||||||
|
|
||||||
|
const codeWrap = document.createElement('div');
|
||||||
|
codeWrap.setAttribute('translate', 'no');
|
||||||
|
codeWrap.className =
|
||||||
|
'inline-block text-sm text-gray-700 pt-5 mr-4 sm:mr-6';
|
||||||
|
|
||||||
|
const comment = document.createElement('pre');
|
||||||
|
comment.className = 'text-gray-400';
|
||||||
|
comment.textContent = '# Download into a named local directory';
|
||||||
|
|
||||||
|
const cmdPre = document.createElement('pre');
|
||||||
|
cmdPre.textContent = newCmd;
|
||||||
|
|
||||||
|
codeWrap.appendChild(comment);
|
||||||
|
codeWrap.appendChild(cmdPre);
|
||||||
|
inner.appendChild(codeWrap);
|
||||||
|
block.appendChild(copyBtn);
|
||||||
|
block.appendChild(inner);
|
||||||
|
|
||||||
|
container.parentNode.insertBefore(block, container.nextSibling);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scan() {
|
||||||
|
document.querySelectorAll('dialog[open]').forEach((dialog) => {
|
||||||
|
const h3 = dialog.querySelector('h3');
|
||||||
|
if (h3 && /clone this/i.test(h3.textContent)) {
|
||||||
|
processModal(dialog);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 모달은 동적으로 열리므로 MutationObserver 로 감시
|
||||||
|
const observer = new MutationObserver(() => {
|
||||||
|
// 약간의 디바운스
|
||||||
|
clearTimeout(observer._t);
|
||||||
|
observer._t = setTimeout(scan, 50);
|
||||||
|
});
|
||||||
|
observer.observe(document.body, { childList: true, subtree: true });
|
||||||
|
|
||||||
|
scan();
|
||||||
|
})();
|
||||||
Loading…
Add table
Add a link
Reference in a new issue