Omnisearch와 구글 연동을 위한 개선된 Userscript

Mon, 04 Aug 2025 03:07:58 GMT

Omnisearch와 구글 검색창 연동하는 기능을 사용하시다보면 레이아웃이 깨지는 경우가 있습니다. 아래 스크립트는 해당 내용과 디자인 요소를 조금 개선한 커맨드스페이스 버전입니다. ![Image](https://upload.cafenono.com/image/slashpagePost/20250804/121000_tvMOjgGMqIIVTkdoWh?q=80&s=1280x180&t=outside&f=webp) Tampermonkey에 가셔서 새로운 스크립트로 추가하시고 사용하시면 됩니다. ![Image](https://upload.cafenono.com/image/slashpagePost/20250804/120936_1Ck2s6CU2HHeY34cMC?q=80&s=1280x180&t=outside&f=webp) 혹 아직 설치가 안되어있으신 분들은 패스트캠퍼스 강의의 Part 2_Chapter 6-1을 확인하시거나 아래 링크를 참고해주세요. [Inject Omnisearch results into your search engine - Omnisearch - Obsidian Publish](https://publish.obsidian.md/omnisearch/Inject+Omnisearch+results+into+your+search+engine) 준비가 되었다면 아래의 Userscript를 복사해서 사용하세요. 두 가지 버전이 있습니다. ![Image](https://upload.cafenono.com/image/slashpagePost/20250804/120952_BSSNsHRRy7orvZKvrm?q=80&s=1280x180&t=outside&f=webp) v1 ![Image](https://upload.cafenono.com/image/slashpagePost/20250804/214310_rGB49C11WgeXUstmtH?q=80&s=1280x180&t=outside&f=webp) v2 ## 초기 버전(v1) 스크립트 **스크립트 복사하기** ``` "use strict"; // ==UserScript== // @name Obsidian Omnisearch in Google CMDS v0.1 // @namespace https://github.com/scambier/userscripts // @downloadURL https://github.com/scambier/userscripts/raw/master/dist/obsidian-omnisearch-google.user.js // @updateURL https://github.com/scambier/userscripts/raw/master/dist/obsidian-omnisearch-google.user.js // @version 0.4.2 // @description Injects Obsidian notes in Google search results with modern design // @author Simon Cambier, Modified by CMDSPACE // @match https://google.com/* // @match https://www.google.com/* // @icon https://obsidian.md/favicon.ico // @require https://code.jquery.com/jquery-3.7.1.min.js // @require https://raw.githubusercontent.com/sizzlemctwizzle/GM_config/master/gm_config.js // @require https://gist.githubusercontent.com/scambier/109932d45b7592d3decf24194008be4d/raw/9c97aa67ff9c5d56be34a55ad6c18a314e5eb548/waitForKeyElements.js // @grant GM.xmlHttpRequest // @grant GM_getValue // @grant GM_setValue // @grant GM.getValue // @grant GM.setValue // ==/UserScript== /* globals GM_config, jQuery, $, waitForKeyElements */ (function () { "use strict"; // Google's right "sidebar" that will contain the results div const sidebarSelector = "#rhs"; // The results div const resultsDivId = "OmnisearchObsidianResults"; // The "loading"/"no results" label const loadingSpanId = "OmnisearchObsidianLoading"; // Modern styles for the sidebar panel const injectStyles = () => { const style = document.createElement('style'); style.textContent = ` /* Main container styles */ #${resultsDivId} { margin-top: 20px; margin-bottom: 20px; padding: 0; width: 100%; min-width: 360px; box-sizing: border-box; } /* Header section */ #${resultsDivId} .obsidian-header { background: #7C3AED; color: white; padding: 16px 20px; border-radius: 12px 12px 0 0; display: flex; align-items: center; justify-content: space-between; border: 1px solid #7C3AED; border-bottom: none; } #${resultsDivId} .obsidian-header-title { display: flex; align-items: center; gap: 10px; font-size: 16px; font-weight: 600; color: white; } #${resultsDivId} .obsidian-header svg { width: 24px; height: 24px; filter: brightness(0) invert(1); } #${resultsDivId} .obsidian-settings-link { color: white; opacity: 0.9; font-size: 13px; text-decoration: none; transition: opacity 0.2s; } #${resultsDivId} .obsidian-settings-link:hover { opacity: 1; text-decoration: underline; } /* Content container */ #${resultsDivId} .obsidian-content { background: #ffffff; border: 1px solid #e0e0e0; border-top: none; border-radius: 0 0 12px 12px; padding: 16px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); } /* Result items */ #${resultsDivId} [data-omnisearch-result] { background: #f8f9fa; border-radius: 8px; padding: 14px; margin-bottom: 12px; transition: all 0.2s ease; border: 1px solid transparent; cursor: pointer; } #${resultsDivId} [data-omnisearch-result]:last-child { margin-bottom: 0; } #${resultsDivId} [data-omnisearch-result]:hover { background: #ffffff; border-color: #dadce0; transform: translateX(-2px); box-shadow: 0 2px 8px rgba(0,0,0,0.08); } /* Result title */ #${resultsDivId} .LC20lb { color: #1a73e8; font-size: 15px; font-weight: 500; line-height: 1.4; margin-bottom: 6px; display: block; text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } #${resultsDivId} a:hover .LC20lb { text-decoration: underline; } /* Meta information */ #${resultsDivId} .result-meta { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; } #${resultsDivId} .result-meta svg { width: 14px; height: 14px; } #${resultsDivId} .VuuXrf { color: #7C3AED; font-size: 12px; font-weight: 500; } #${resultsDivId} .dyjrff { color: #80868b; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; display: block; } /* Excerpt text */ #${resultsDivId} .VwiC3b { color: #4d5156; font-size: 13px; line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } /* Loading state */ #${resultsDivId} #${loadingSpanId} { display: block; text-align: center; color: #5f6368; padding: 20px; font-size: 14px; } /* Error state */ #${resultsDivId} .error-message { color: #d93025; padding: 16px; text-align: center; font-size: 14px; } #${resultsDivId} .error-message a { color: #1a73e8; text-decoration: none; } #${resultsDivId} .error-message a:hover { text-decoration: underline; } /* Dark mode support */ @media (prefers-color-scheme: dark) { #${resultsDivId} .obsidian-header { background: #6B2EC5; color: white; border-color: #6B2EC5; } #${resultsDivId} .obsidian-settings-link { color: white; opacity: 0.9; } #${resultsDivId} .obsidian-settings-link:hover { opacity: 1; } #${resultsDivId} .obsidian-content { background: #202124; border-color: #3c4043; } #${resultsDivId} [data-omnisearch-result] { background: #303134; } #${resultsDivId} [data-omnisearch-result]:hover { background: #3c4043; border-color: #5f6368; } #${resultsDivId} .LC20lb { color: #8ab4f8; } #${resultsDivId} .VuuXrf { color: #9974F8; } #${resultsDivId} .dyjrff { color: #9aa0a6; } #${resultsDivId} .VwiC3b { color: #bdc1c6; } #${resultsDivId} #${loadingSpanId} { color: #9aa0a6; } } /* Responsive adjustments */ @media (max-width: 1200px) { #${resultsDivId} .obsidian-header { padding: 14px 16px; } #${resultsDivId} .obsidian-header-title { font-size: 15px; } #${resultsDivId} .obsidian-content { padding: 12px; } } `; document.head.appendChild(style); }; // The `new GM_config()` syntax is not recognized by the TS compiler // @ts-ignore const gmc = new GM_config({ id: "ObsidianOmnisearchGoogle", title: "Omnisearch in Google - Configuration", fields: { port: { label: "HTTP Port", type: "text", default: "51361", }, nbResults: { label: "Number of results to display", type: "int", default: 3, }, }, events: { save: () => { location.reload(); }, init: () => { }, }, }); // Promise resolves when initialization completes const onInit = (config) => new Promise((resolve) => { let isInit = () => setTimeout(() => (config.isInit ? resolve() : isInit()), 0); isInit(); }); // Obsidian logo const logo = ` `; function omnisearch() { const port = gmc.get("port"); const nbResults = gmc.get("nbResults"); // Extract the ?q= part of the URL with URLSearchParams const params = new URLSearchParams(window.location.search); const query = params.get("q"); if (!query) return; injectLoadingLabel(); GM.xmlHttpRequest({ method: "GET", url: `http://localhost:${port}/search?q=${query}`, headers: { "Content-Type": "application/json", }, onload: function (res) { const data = JSON.parse(res.response); removeLoadingLabel(data.length > 0); // Keep the x first results data.splice(nbResults); const resultsContainer = $(`#${resultsDivId} .obsidian-content`); // Delete all existing data-omnisearch-result $("[data-omnisearch-result]").remove(); // Inject results for (const item of data) { const url = `obsidian://open?vault=${encodeURIComponent(item.vault)}&file=${encodeURIComponent(item.path)}`; const element = $(`

${item.basename}

${logo} Obsidian

${item.path}

${item.excerpt.replaceAll("
", " ").replaceAll("
", " ")}

`); resultsContainer.append(element); } }, onerror: function (res) { console.log("Omnisearch error", res); const span = $("#" + loadingSpanId)[0]; if (span) { span.parentElement.innerHTML = `
Error: Obsidian is not running or the Omnisearch server is not enabled.
Open Obsidian
`; } }, }); } function injectTitle() { const id = "OmnisearchObsidianConfig"; if (!$("#" + id)[0]) { const header = $(`

${logo} Omnisearch Results
Settings
`); $(`#${resultsDivId}`).prepend(header); $(document).on("click", "#" + id, function (e) { e.preventDefault(); gmc.open(); }); } } function injectResultsContainer() { const resultsDiv = $(`

`); $(sidebarSelector).append(resultsDiv); // append instead of prepend to put at bottom } function injectLoadingLabel() { if (!$("#" + loadingSpanId)[0]) { const label = $(`Loading Obsidian results...`); $(`#${resultsDivId} .obsidian-content`).append(label); } } function removeLoadingLabel(foundResults = true) { if (foundResults) { $("#" + loadingSpanId).remove(); } else { $("#" + loadingSpanId).text("No results found in Obsidian"); } } console.log("Loading Omnisearch injector CMDS v0.1"); let init = onInit(gmc); init.then(() => { // Inject styles injectStyles(); // Make sure the results container is there if (!$(sidebarSelector)[0]) { // Create sidebar with proper width if it doesn't exist $("#rcnt").append('

'); } injectResultsContainer(); injectTitle(); omnisearch(); // Make an initial call console.log("Loaded Omnisearch injector CMDS v0.1"); // Keep the results at the bottom of sidebar waitForKeyElements(sidebarSelector, () => { // Move to bottom if other elements are added const omnisearchDiv = $(`#${resultsDivId}`); if (omnisearchDiv.next().length > 0) { omnisearchDiv.appendTo(sidebarSelector); } }); }); })(); ``` 이제는 여러 가지 레이아웃 상황에서도 깨지지 않고 잘 보입니다. ![Image](https://upload.cafenono.com/image/slashpagePost/20250804/121221_NBXfSbcVywBrMrmlzG?q=80&s=1280x180&t=outside&f=webp) ## 임영록님 수정 버전(v2) 스크립트 **스크립트 복사하기** ``` "use strict"; // ==UserScript== // @name Obsidian Omnisearch in Google CMDS v0.1 - Custom // @namespace https://github.com/scambier/userscripts // @downloadURL https://github.com/scambier/userscripts/raw/master/dist/obsidian-omnisearch-google.user.js // @updateURL https://github.com/scambier/userscripts/raw/master/dist/obsidian-omnisearch-google.user.js // @version 0.4.2-custom // @description Injects Obsidian notes in Google search results with modern design - Custom version with dark header and no logos // @author Simon Cambier, Modified by CMDSPACE, Customized for user // @match https://google.com/* // @match https://www.google.com/* // @icon https://obsidian.md/favicon.ico // @require https://code.jquery.com/jquery-3.7.1.min.js // @require https://raw.githubusercontent.com/sizzlemctwizzle/GM_config/master/gm_config.js // @require https://gist.githubusercontent.com/scambier/109932d45b7592d3decf24194008be4d/raw/9c97aa67ff9c5d56be34a55ad6c18a314e5eb548/waitForKeyElements.js // @grant GM.xmlHttpRequest // @grant GM_getValue // @grant GM_setValue // @grant GM.getValue // @grant GM.setValue // ==/UserScript== /* globals GM_config, jQuery, $, waitForKeyElements */ (function () { "use strict"; // Google's right "sidebar" that will contain the results div const sidebarSelector = "#rhs"; // The results div const resultsDivId = "OmnisearchObsidianResults"; // The "loading"/"no results" label const loadingSpanId = "OmnisearchObsidianLoading"; // Modern styles for the sidebar panel - CUSTOMIZED VERSION const injectStyles = () => { const style = document.createElement('style'); style.textContent = ` /* Main container styles */ #${resultsDivId} { margin-top: 20px; margin-bottom: 20px; padding: 0; width: 100%; min-width: 360px; box-sizing: border-box; } /* Header section - CUSTOMIZED: Light blue background without border */ #${resultsDivId} .obsidian-header { background: #F2F6FF; color: #1B0CAB; padding: 16px 20px; border-radius: 20px 20px 0 0; display: flex; align-items: center; justify-content: space-between; border: none; } #${resultsDivId} .obsidian-header-title { display: flex; align-items: center; gap: 10px; font-size: 16px; font-weight: normal; color: #1B0CAB; } /* Logo in header */ #${resultsDivId} .obsidian-header svg { width: 20px; height: 20px; } #${resultsDivId} .obsidian-settings-link { color: #1B0CAB; opacity: 0.7; font-size: 13px; text-decoration: none; transition: opacity 0.2s; } #${resultsDivId} .obsidian-settings-link:hover { opacity: 1; color: #1B0CAB; text-decoration: underline; } /* Content container */ #${resultsDivId} .obsidian-content { background: #F2F6FF; border: none; border-top: none; border-radius: 0 0 20px 20px; padding: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); } /* Result items */ #${resultsDivId} [data-omnisearch-result] { background: #ffffff; border-radius: 8px; padding: 14px; margin-bottom: 12px; transition: all 0.2s ease; border: none; cursor: pointer; } #${resultsDivId} [data-omnisearch-result]:last-child { margin-bottom: 0; } #${resultsDivId} [data-omnisearch-result]:hover { background: #ffffff; transform: translateX(-2px); box-shadow: 0 2px 8px rgba(0,0,0,0.08); } /* Result title - CUSTOMIZED: Smaller font size and reduced margin */ #${resultsDivId} .LC20lb { color: #1B0CAB; font-size: 12px; font-weight: 500; line-height: 1.4; margin-bottom: 3px; display: block; text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } #${resultsDivId} a:hover .LC20lb { text-decoration: underline; } /* Meta information - CUSTOMIZED: Hide logos */ #${resultsDivId} .result-meta { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; } /* CUSTOMIZED: Hide all logos in result items */ #${resultsDivId} .result-meta svg { display: none !important; } #${resultsDivId} .VuuXrf { color: #374151; font-size: 12px; font-weight: 500; } #${resultsDivId} .dyjrff { color: #80868b; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; display: block; } /* Excerpt text - CUSTOMIZED: Highlight search terms, 4 lines */ #${resultsDivId} .VwiC3b { color: #4d5156; font-size: 13px; line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; margin-bottom: 8px; font-weight: 500; } /* Search term highlighting */ #${resultsDivId} .search-highlight { font-weight: bold; background: rgba(255, 255, 0, 0.2); padding: 1px 2px; border-radius: 2px; } /* Loading state */ #${resultsDivId} #${loadingSpanId} { display: block; text-align: center; color: #5f6368; padding: 20px; font-size: 14px; } /* Error state */ #${resultsDivId} .error-message { color: #d93025; padding: 16px; text-align: center; font-size: 14px; } #${resultsDivId} .error-message a { color: #1a73e8; text-decoration: none; } #${resultsDivId} .error-message a:hover { text-decoration: underline; } /* Dark mode support - CUSTOMIZED: Unified color scheme */ @media (prefers-color-scheme: dark) { /* Main container - no border */ #${resultsDivId} { border: none; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); } /* Header - Unified color */ #${resultsDivId} .obsidian-header { background: #2C303D; color: #e2e8f0; border: none; } #${resultsDivId} .obsidian-header-title { color: #e2e8f0; } #${resultsDivId} .obsidian-settings-link { color: #e2e8f0; opacity: 0.7; } #${resultsDivId} .obsidian-settings-link:hover { color: #e2e8f0; opacity: 1; } /* Content container - Unified color */ #${resultsDivId} .obsidian-content { background: #2C303D; border: none; } /* Individual result items - Unified color with subtle distinction */ #${resultsDivId} [data-omnisearch-result] { background: #2C303D; border-bottom: 1px solid rgba(255, 255, 255, 0.03); } #${resultsDivId} [data-omnisearch-result]:last-child { border-bottom: none; } #${resultsDivId} [data-omnisearch-result]:hover { background: #363A47; transform: translateX(-2px); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); } /* Text colors */ #${resultsDivId} .LC20lb { color: #9974F8; } #${resultsDivId} .VuuXrf { color: #a0aec0; } #${resultsDivId} .dyjrff { color: #9aa0a6; } #${resultsDivId} .VwiC3b { color: #bdc1c6; } #${resultsDivId} #${loadingSpanId} { color: #9aa0a6; } /* Search highlighting in dark mode */ #${resultsDivId} .search-highlight { background: rgba(153, 116, 248, 0.3); color: #e2e8f0; } } /* Responsive adjustments */ @media (max-width: 1200px) { #${resultsDivId} .obsidian-header { padding: 14px 16px; } #${resultsDivId} .obsidian-header-title { font-size: 15px; } #${resultsDivId} .obsidian-content { padding: 12px; } } `; document.head.appendChild(style); }; // The `new GM_config()` syntax is not recognized by the TS compiler // @ts-ignore const gmc = new GM_config({ id: "ObsidianOmnisearchGoogle", title: "Omnisearch in Google - Configuration", fields: { port: { label: "HTTP Port", type: "text", default: "51361", }, nbResults: { label: "Number of results to display", type: "int", default: 3, }, }, events: { save: () => { location.reload(); }, init: () => { }, }, }); // Promise resolves when initialization completes const onInit = (config) => new Promise((resolve) => { let isInit = () => setTimeout(() => (config.isInit ? resolve() : isInit()), 0); isInit(); }); // Obsidian logo SVG const logo = ` `; function omnisearch() { const port = gmc.get("port"); const nbResults = gmc.get("nbResults"); // Extract the ?q= part of the URL with URLSearchParams const params = new URLSearchParams(window.location.search); const query = params.get("q"); if (!query) return; injectLoadingLabel(); GM.xmlHttpRequest({ method: "GET", url: `http://localhost:${port}/search?q=${query}`, headers: { "Content-Type": "application/json", }, onload: function (res) { const data = JSON.parse(res.response); removeLoadingLabel(data.length > 0); // Keep the x first results data.splice(nbResults); const resultsContainer = $(`#${resultsDivId} .obsidian-content`); // Delete all existing data-omnisearch-result $("[data-omnisearch-result]").remove(); // Inject results - CUSTOMIZED: New order and search highlighting for (const item of data) { const url = `obsidian://open?vault=${encodeURIComponent(item.vault)}&file=${encodeURIComponent(item.path)}`; // Highlight search terms in excerpt let highlightedExcerpt = item.excerpt.replaceAll("
", " ").replaceAll("
", " "); if (query) { const queryTerms = query.split(' ').filter(term => term.length > 1); queryTerms.forEach(term => { const regex = new RegExp(`(${term})`, 'gi'); highlightedExcerpt = highlightedExcerpt.replace(regex, '$1'); }); } const element = $(`

${highlightedExcerpt}

${item.basename}

${item.path}

`); resultsContainer.append(element); } }, onerror: function (res) { console.log("Omnisearch error", res); const span = $("#" + loadingSpanId)[0]; if (span) { span.parentElement.innerHTML = `
Error: Obsidian is not running or the Omnisearch server is not enabled.
Open Obsidian
`; } }, }); } function injectTitle() { const id = "OmnisearchObsidianConfig"; if (!$("#" + id)[0]) { // CUSTOMIZED: Header with logo const header = $(`

${logo} Omnisearch Results
Settings
`); $(`#${resultsDivId}`).prepend(header); $(document).on("click", "#" + id, function (e) { e.preventDefault(); gmc.open(); }); } } function injectResultsContainer() { const resultsDiv = $(`

`); $(sidebarSelector).append(resultsDiv); // append instead of prepend to put at bottom } function injectLoadingLabel() { if (!$("#" + loadingSpanId)[0]) { const label = $(`Loading Obsidian results...`); $(`#${resultsDivId} .obsidian-content`).append(label); } } function removeLoadingLabel(foundResults = true) { if (foundResults) { $("#" + loadingSpanId).remove(); } else { $("#" + loadingSpanId).text("No results found in Obsidian"); } } console.log("Loading Omnisearch injector CMDS v0.1 - Custom version"); let init = onInit(gmc); init.then(() => { // Inject styles injectStyles(); // Make sure the results container is there if (!$(sidebarSelector)[0]) { // Create sidebar with proper width if it doesn't exist $("#rcnt").append('

'); } injectResultsContainer(); injectTitle(); omnisearch(); // Make an initial call console.log("Loaded Omnisearch injector CMDS v0.1 - Custom version"); // Keep the results at the bottom of sidebar waitForKeyElements(sidebarSelector, () => { // Move to bottom if other elements are added const omnisearchDiv = $(`#${resultsDivId}`); if (omnisearchDiv.next().length > 0) { omnisearchDiv.appendTo(sidebarSelector); } }); }); })(); ```