vault backup: 2025-08-31 11:54:56
This commit is contained in:
3
.obsidian/community-plugins.json
vendored
3
.obsidian/community-plugins.json
vendored
@@ -62,5 +62,6 @@
|
||||
"onlyoffice",
|
||||
"obsidian42-brat",
|
||||
"soundscapes",
|
||||
"execute-code"
|
||||
"execute-code",
|
||||
"obsidian-custom-frames"
|
||||
]
|
||||
2
.obsidian/plugins/cubox-sync/data.json
vendored
2
.obsidian/plugins/cubox-sync/data.json
vendored
@@ -34,7 +34,7 @@
|
||||
"contentTemplate": "# {{{title}}}\n\n{{{description}}}\n\n{{{article_title}}} //文章内容标题\n{{{content}}} //文章正文\n\n\n[Read in Cubox]({{{cubox_url}}}) \n[Read Original]({{{url}}}) \n\n---\n\n{{#highlights.length}}\n## Annotations \n\n{{#highlights}}\n> {{{text}}} \n\n{{#note}}\n{{{note}}}\n{{/note}}\n[Link️]({{{cubox_url}}}) \n\n{{/highlights}}\n{{/highlights.length}}",
|
||||
"highlightInContent": true,
|
||||
"dateFormat": "yyyy-MM-dd",
|
||||
"lastSyncTime": 1756608449359,
|
||||
"lastSyncTime": 1756612049514,
|
||||
"lastSyncCardId": "7358083230366436785",
|
||||
"lastCardUpdateTime": "2025-08-21T13:52:28.950+0800",
|
||||
"syncing": false
|
||||
|
||||
17
.obsidian/plugins/obsidian-custom-frames/data.json
vendored
Normal file
17
.obsidian/plugins/obsidian-custom-frames/data.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"frames": [
|
||||
{
|
||||
"url": "",
|
||||
"displayName": "New Frame",
|
||||
"icon": "",
|
||||
"hideOnMobile": true,
|
||||
"addRibbonIcon": false,
|
||||
"openInCenter": false,
|
||||
"zoomLevel": 1,
|
||||
"forceIframe": false,
|
||||
"customCss": "",
|
||||
"customJs": ""
|
||||
}
|
||||
],
|
||||
"padding": 5
|
||||
}
|
||||
657
.obsidian/plugins/obsidian-custom-frames/main.js
vendored
Normal file
657
.obsidian/plugins/obsidian-custom-frames/main.js
vendored
Normal file
@@ -0,0 +1,657 @@
|
||||
/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||
if you want to view the source, please visit the github repository of this plugin
|
||||
*/
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
|
||||
var __export = (target, all) => {
|
||||
__markAsModule(target);
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __reExport = (target, module2, desc) => {
|
||||
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
|
||||
for (let key of __getOwnPropNames(module2))
|
||||
if (!__hasOwnProp.call(target, key) && key !== "default")
|
||||
__defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
|
||||
}
|
||||
return target;
|
||||
};
|
||||
var __toModule = (module2) => {
|
||||
return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
|
||||
};
|
||||
var __async = (__this, __arguments, generator) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
var fulfilled = (value) => {
|
||||
try {
|
||||
step(generator.next(value));
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
};
|
||||
var rejected = (value) => {
|
||||
try {
|
||||
step(generator.throw(value));
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
};
|
||||
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
||||
step((generator = generator.apply(__this, __arguments)).next());
|
||||
});
|
||||
};
|
||||
|
||||
// src/main.ts
|
||||
__export(exports, {
|
||||
default: () => CustomFramesPlugin
|
||||
});
|
||||
var import_obsidian4 = __toModule(require("obsidian"));
|
||||
|
||||
// src/frame.ts
|
||||
var import_obsidian = __toModule(require("obsidian"));
|
||||
|
||||
// src/settings.ts
|
||||
var defaultSettings = {
|
||||
frames: [],
|
||||
padding: 5
|
||||
};
|
||||
var presets = {
|
||||
"obsidian": {
|
||||
url: "https://forum.obsidian.md/",
|
||||
displayName: "Obsidian Forum",
|
||||
icon: "edit",
|
||||
hideOnMobile: true,
|
||||
addRibbonIcon: true,
|
||||
openInCenter: true,
|
||||
zoomLevel: 1,
|
||||
forceIframe: false,
|
||||
customCss: "",
|
||||
customJs: ""
|
||||
},
|
||||
"detexify": {
|
||||
url: "https://detexify.kirelabs.org/classify.html",
|
||||
displayName: "Detexify",
|
||||
icon: "type",
|
||||
hideOnMobile: true,
|
||||
addRibbonIcon: true,
|
||||
openInCenter: false,
|
||||
zoomLevel: 0.95,
|
||||
forceIframe: false,
|
||||
customCss: `/* hide info clutter and ad banner */
|
||||
#classify--info-area,
|
||||
.adsbygoogle {
|
||||
display: none !important
|
||||
}`,
|
||||
customJs: ""
|
||||
},
|
||||
"calendar": {
|
||||
url: "https://calendar.google.com/calendar",
|
||||
displayName: "Google Calendar",
|
||||
icon: "calendar",
|
||||
hideOnMobile: true,
|
||||
addRibbonIcon: true,
|
||||
openInCenter: true,
|
||||
zoomLevel: 1,
|
||||
forceIframe: false,
|
||||
customCss: `/* hide the menu bar "Calendar" text and remove minimum width */
|
||||
div[style*="min-width: 238px"] {
|
||||
min-width: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
div[style*="min-width: 238px"] span[role*="heading"] {
|
||||
display: none !important;
|
||||
}`,
|
||||
customJs: ""
|
||||
},
|
||||
"keep": {
|
||||
url: "https://keep.google.com",
|
||||
displayName: "Google Keep",
|
||||
icon: "files",
|
||||
hideOnMobile: true,
|
||||
addRibbonIcon: false,
|
||||
openInCenter: false,
|
||||
zoomLevel: 1,
|
||||
forceIframe: false,
|
||||
customCss: `/* hide the menu bar, the "Keep" text and the Google Apps button */
|
||||
html > body > div:nth-child(2) > div:nth-child(2) > div:first-child,
|
||||
html > body > div:first-child > header:first-child > div > div:first-child > div > div:first-child > a:first-child > span,
|
||||
html > body > div:first-child > header:first-child > div:nth-child(2) > div:first-child > div:first-child,
|
||||
html > body > div:first-child > header:first-child > div:nth-child(2) > div:nth-child(3) > div:first-child > div:first-child > div:first-child {
|
||||
display: none !important;
|
||||
}
|
||||
html > body > div:first-child > header:first-child > div > div:first-child > div > div:first-child > a:first-child {
|
||||
cursor: default;
|
||||
}`,
|
||||
customJs: ""
|
||||
},
|
||||
"todoist": {
|
||||
url: "https://todoist.com",
|
||||
displayName: "Todoist",
|
||||
icon: "list-checks",
|
||||
hideOnMobile: true,
|
||||
addRibbonIcon: false,
|
||||
openInCenter: false,
|
||||
zoomLevel: 1,
|
||||
forceIframe: false,
|
||||
customCss: `/* hide the help, home, search, and productivity overview buttons, create extra space, and prevent toast pop-up from acting weird */
|
||||
[aria-label="Go to Home view"], #quick_find, [aria-label="Productivity"], [aria-label="Help & Feedback"] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.view_content {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.view_header {
|
||||
padding-left: 15px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.undo_toast {
|
||||
width: 95%;
|
||||
}`,
|
||||
customJs: ""
|
||||
},
|
||||
"notion": {
|
||||
url: "https://www.notion.so/",
|
||||
displayName: "Notion",
|
||||
icon: "box",
|
||||
hideOnMobile: true,
|
||||
addRibbonIcon: true,
|
||||
openInCenter: true,
|
||||
zoomLevel: 1,
|
||||
forceIframe: false,
|
||||
customCss: "",
|
||||
customJs: ""
|
||||
},
|
||||
"twitter": {
|
||||
url: "https://twitter.com",
|
||||
displayName: "Twitter",
|
||||
icon: "twitter",
|
||||
hideOnMobile: true,
|
||||
addRibbonIcon: false,
|
||||
openInCenter: false,
|
||||
zoomLevel: 1,
|
||||
forceIframe: false,
|
||||
customCss: "",
|
||||
customJs: ""
|
||||
},
|
||||
"tasks": {
|
||||
url: "https://tasks.google.com/embed/?origin=https://calendar.google.com&fullWidth=1",
|
||||
displayName: "Google Tasks",
|
||||
icon: "list-checks",
|
||||
hideOnMobile: true,
|
||||
addRibbonIcon: false,
|
||||
openInCenter: false,
|
||||
zoomLevel: 1,
|
||||
forceIframe: false,
|
||||
customCss: "",
|
||||
customJs: ""
|
||||
},
|
||||
"readwise-daily-review": {
|
||||
"url": "https://readwise.io/dailyreview",
|
||||
"displayName": "Readwise Daily Review",
|
||||
"icon": "highlighter",
|
||||
"hideOnMobile": true,
|
||||
"addRibbonIcon": false,
|
||||
"openInCenter": false,
|
||||
"zoomLevel": 1,
|
||||
"forceIframe": false,
|
||||
"customCss": ".fixed-nav {\n display: none !important;\n}",
|
||||
"customJs": ""
|
||||
}
|
||||
};
|
||||
function getIcon(settings) {
|
||||
return settings.icon ? `lucide-${settings.icon}` : "documents";
|
||||
}
|
||||
function getId(settings) {
|
||||
return settings.displayName.toLowerCase().replace(/\s/g, "-");
|
||||
}
|
||||
|
||||
// src/frame.ts
|
||||
var CustomFrame = class {
|
||||
constructor(settings, data) {
|
||||
this.settings = settings;
|
||||
this.data = data;
|
||||
}
|
||||
create(parent, additionalStyle = void 0, urlSuffix = void 0) {
|
||||
let style = `padding: ${this.settings.padding}px;`;
|
||||
if (additionalStyle)
|
||||
style += additionalStyle;
|
||||
if (import_obsidian.Platform.isDesktopApp && !this.data.forceIframe) {
|
||||
let frameDoc = parent.doc;
|
||||
this.frame = frameDoc.createElement("webview");
|
||||
this.frame.partition = "persist:vault-" + app.appId;
|
||||
parent.appendChild(this.frame);
|
||||
this.frame.setAttribute("allowpopups", "");
|
||||
this.frame.addEventListener("dom-ready", () => {
|
||||
this.frame.setZoomFactor(this.data.zoomLevel);
|
||||
this.frame.insertCSS(this.data.customCss);
|
||||
this.frame.executeJavaScript(this.data.customJs);
|
||||
});
|
||||
this.frame.addEventListener("destroyed", () => {
|
||||
if (frameDoc != parent.doc) {
|
||||
this.frame.detach();
|
||||
this.create(parent, additionalStyle, urlSuffix);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.frame = parent.doc.createElement("iframe");
|
||||
parent.appendChild(this.frame);
|
||||
this.frame.setAttribute("sandbox", "allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts allow-top-navigation-by-user-activation allow-downloads");
|
||||
this.frame.setAttribute("allow", "encrypted-media; fullscreen; oversized-images; picture-in-picture; sync-xhr; geolocation;");
|
||||
style += `transform: scale(${this.data.zoomLevel}); transform-origin: 0 0;`;
|
||||
}
|
||||
this.frame.addClass("custom-frames-frame");
|
||||
this.frame.addClass(`custom-frames-${getId(this.data)}`);
|
||||
this.frame.setAttribute("style", style);
|
||||
let src = new URL(this.data.url);
|
||||
if (urlSuffix) {
|
||||
let suffix = new URL(urlSuffix, src.origin);
|
||||
suffix.searchParams.forEach((value, key) => {
|
||||
src.searchParams.set(key, value);
|
||||
});
|
||||
if (suffix.pathname !== "/") {
|
||||
src.pathname += suffix.pathname;
|
||||
}
|
||||
src.hash = suffix.hash || src.hash;
|
||||
}
|
||||
this.frame.setAttribute("src", src.toString());
|
||||
}
|
||||
refresh() {
|
||||
if (this.frame instanceof HTMLIFrameElement) {
|
||||
this.frame.contentWindow.location.reload();
|
||||
} else {
|
||||
this.frame.reload();
|
||||
}
|
||||
}
|
||||
return() {
|
||||
if (this.frame instanceof HTMLIFrameElement) {
|
||||
this.frame.contentWindow.open(this.data.url);
|
||||
} else {
|
||||
this.frame.loadURL(this.data.url);
|
||||
}
|
||||
}
|
||||
goBack() {
|
||||
if (this.frame instanceof HTMLIFrameElement) {
|
||||
this.frame.contentWindow.history.back();
|
||||
} else {
|
||||
this.frame.goBack();
|
||||
}
|
||||
}
|
||||
goForward() {
|
||||
if (this.frame instanceof HTMLIFrameElement) {
|
||||
this.frame.contentWindow.history.forward();
|
||||
} else {
|
||||
this.frame.goForward();
|
||||
}
|
||||
}
|
||||
toggleDevTools() {
|
||||
if (!(this.frame instanceof HTMLIFrameElement)) {
|
||||
if (!this.frame.isDevToolsOpened()) {
|
||||
this.frame.openDevTools();
|
||||
} else {
|
||||
this.frame.closeDevTools();
|
||||
}
|
||||
}
|
||||
}
|
||||
getCurrentUrl() {
|
||||
return this.frame instanceof HTMLIFrameElement ? this.frame.contentWindow.location.href : this.frame.getURL();
|
||||
}
|
||||
focus() {
|
||||
if (this.frame instanceof HTMLIFrameElement) {
|
||||
this.frame.contentWindow.focus();
|
||||
} else {
|
||||
this.frame.focus();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// src/settings-tab.ts
|
||||
var import_obsidian2 = __toModule(require("obsidian"));
|
||||
var CustomFramesSettingTab = class extends import_obsidian2.PluginSettingTab {
|
||||
constructor(app2, plugin) {
|
||||
super(app2, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
display() {
|
||||
this.containerEl.empty();
|
||||
this.containerEl.createEl("h2", { text: "Custom Frames Settings" });
|
||||
this.containerEl.createEl("p", {
|
||||
text: "Please note that Obsidian has to be restarted or reloaded for most of these settings to take effect.",
|
||||
cls: "mod-warning"
|
||||
});
|
||||
new import_obsidian2.Setting(this.containerEl).setName("Frame Padding").setDesc("The padding that should be left around the inside of custom frame panes, in pixels.").addText((t) => {
|
||||
t.inputEl.type = "number";
|
||||
t.setValue(String(this.plugin.settings.padding));
|
||||
t.onChange((v) => __async(this, null, function* () {
|
||||
this.plugin.settings.padding = v.length ? Number(v) : defaultSettings.padding;
|
||||
yield this.plugin.saveSettings();
|
||||
}));
|
||||
});
|
||||
for (let frame of this.plugin.settings.frames) {
|
||||
let heading = this.containerEl.createEl("h3", { text: frame.displayName || "Unnamed Frame" });
|
||||
let toggle = new import_obsidian2.ButtonComponent(this.containerEl).setButtonText("Show Settings").setClass("custom-frames-show").onClick(() => __async(this, null, function* () {
|
||||
content.hidden = !content.hidden;
|
||||
toggle.setButtonText(content.hidden ? "Show Settings" : "Hide Settings");
|
||||
}));
|
||||
let content = this.containerEl.createDiv();
|
||||
content.hidden = true;
|
||||
new import_obsidian2.Setting(content).setName("Display Name").setDesc("The display name that this frame should have.").addText((t) => {
|
||||
t.setValue(frame.displayName);
|
||||
t.onChange((v) => __async(this, null, function* () {
|
||||
frame.displayName = v;
|
||||
heading.setText(frame.displayName || "Unnamed Frame");
|
||||
yield this.plugin.saveSettings();
|
||||
}));
|
||||
});
|
||||
new import_obsidian2.Setting(content).setName("Icon").setDesc(createFragment((f) => {
|
||||
f.createSpan({ text: "The icon that this frame's pane should have. The names of any " });
|
||||
f.createEl("a", { text: "Lucide icons", href: "https://lucide.dev/" });
|
||||
f.createSpan({ text: " can be used." });
|
||||
})).addText((t) => {
|
||||
t.setValue(frame.icon);
|
||||
t.onChange((v) => __async(this, null, function* () {
|
||||
frame.icon = v;
|
||||
yield this.plugin.saveSettings();
|
||||
}));
|
||||
});
|
||||
new import_obsidian2.Setting(content).setName("URL").setDesc("The URL that should be opened in this frame.").addText((t) => {
|
||||
t.setValue(frame.url);
|
||||
t.onChange((v) => __async(this, null, function* () {
|
||||
frame.url = v;
|
||||
yield this.plugin.saveSettings();
|
||||
}));
|
||||
});
|
||||
new import_obsidian2.Setting(content).setName("Disable on Mobile").setDesc("Custom Frames is a lot more restricted on mobile devices and doesn't allow for the same types of content to be displayed. If a frame doesn't work as expected on mobile, it can be disabled.").addToggle((t) => {
|
||||
t.setValue(frame.hideOnMobile);
|
||||
t.onChange((v) => __async(this, null, function* () {
|
||||
frame.hideOnMobile = v;
|
||||
yield this.plugin.saveSettings();
|
||||
}));
|
||||
});
|
||||
new import_obsidian2.Setting(content).setName("Add Ribbon Icon").setDesc("Whether a button to open this frame should be added to the ribbon.").addToggle((t) => {
|
||||
t.setValue(frame.addRibbonIcon);
|
||||
t.onChange((v) => __async(this, null, function* () {
|
||||
frame.addRibbonIcon = v;
|
||||
yield this.plugin.saveSettings();
|
||||
}));
|
||||
});
|
||||
new import_obsidian2.Setting(content).setName("Open in Center").setDesc("Whether this frame should be opened in the unpinned center editor rather than one of the panes on the side. This is useful for sites that don't work well in a narrow view, or sites that don't require a note to be open when viewed.").addToggle((t) => {
|
||||
t.setValue(frame.openInCenter);
|
||||
t.onChange((v) => __async(this, null, function* () {
|
||||
frame.openInCenter = v;
|
||||
yield this.plugin.saveSettings();
|
||||
}));
|
||||
});
|
||||
new import_obsidian2.Setting(content).setName("Force iframe").setDesc(createFragment((f) => {
|
||||
f.createSpan({ text: "Whether this frame should use iframes on desktop as opposed to Electron webviews." });
|
||||
f.createEl("br");
|
||||
f.createEl("em", { text: "Only enable this setting if the frame is causing issues or frequent crashes. This setting causes all Desktop-only settings to be ignored." });
|
||||
})).addToggle((t) => {
|
||||
t.setValue(frame.forceIframe);
|
||||
t.onChange((v) => __async(this, null, function* () {
|
||||
frame.forceIframe = v;
|
||||
yield this.plugin.saveSettings();
|
||||
}));
|
||||
});
|
||||
new import_obsidian2.Setting(content).setName("Page Zoom").setDesc("The zoom that this frame's page should be displayed with, as a percentage.").addText((t) => {
|
||||
t.inputEl.type = "number";
|
||||
t.setValue(String(frame.zoomLevel * 100));
|
||||
t.onChange((v) => __async(this, null, function* () {
|
||||
frame.zoomLevel = v.length ? Number(v) / 100 : 1;
|
||||
yield this.plugin.saveSettings();
|
||||
}));
|
||||
});
|
||||
new import_obsidian2.Setting(content).setName("Additional CSS").setDesc(createFragment((f) => {
|
||||
f.createSpan({ text: "A snippet of additional CSS that should be applied to this frame." });
|
||||
f.createEl("br");
|
||||
f.createEl("em", { text: "Note that this is only applied on Desktop." });
|
||||
})).addTextArea((t) => {
|
||||
t.inputEl.rows = 5;
|
||||
t.inputEl.cols = 50;
|
||||
t.setValue(frame.customCss);
|
||||
t.onChange((v) => __async(this, null, function* () {
|
||||
frame.customCss = v;
|
||||
yield this.plugin.saveSettings();
|
||||
}));
|
||||
});
|
||||
new import_obsidian2.Setting(content).setName("Additional JavaScript").setDesc(createFragment((f) => {
|
||||
f.createSpan({ text: "A snippet of additional JavaScript that should be applied to this frame." });
|
||||
f.createEl("br");
|
||||
f.createEl("em", { text: "Note that this is only applied on Desktop." });
|
||||
})).addTextArea((t) => {
|
||||
t.inputEl.rows = 5;
|
||||
t.inputEl.cols = 50;
|
||||
t.setValue(frame.customJs);
|
||||
t.onChange((v) => __async(this, null, function* () {
|
||||
frame.customJs = v;
|
||||
yield this.plugin.saveSettings();
|
||||
}));
|
||||
});
|
||||
new import_obsidian2.ButtonComponent(content).setButtonText("Remove Frame").onClick(() => __async(this, null, function* () {
|
||||
this.plugin.settings.frames.remove(frame);
|
||||
yield this.plugin.saveSettings();
|
||||
this.display();
|
||||
}));
|
||||
}
|
||||
this.containerEl.createEl("hr");
|
||||
this.containerEl.createEl("p", { text: `Create a new frame, either from a preset shipped with the plugin, or a custom one that you can edit yourself. Each frame's pane can be opened using the "Custom Frames: Open" command.` });
|
||||
let addDiv = this.containerEl.createDiv();
|
||||
let dropdown = new import_obsidian2.DropdownComponent(addDiv);
|
||||
dropdown.addOption("new", "Custom");
|
||||
for (let [key, value] of Object.entries(presets).sort((a, b) => a[1].displayName.localeCompare(b[1].displayName)))
|
||||
dropdown.addOption(key, value.displayName);
|
||||
new import_obsidian2.ButtonComponent(addDiv).setButtonText("Add Frame").setClass("custom-frames-add").onClick(() => __async(this, null, function* () {
|
||||
let option = dropdown.getValue();
|
||||
if (option == "new") {
|
||||
this.plugin.settings.frames.push({
|
||||
url: "",
|
||||
displayName: "New Frame",
|
||||
icon: "",
|
||||
hideOnMobile: true,
|
||||
addRibbonIcon: false,
|
||||
openInCenter: false,
|
||||
zoomLevel: 1,
|
||||
forceIframe: false,
|
||||
customCss: "",
|
||||
customJs: ""
|
||||
});
|
||||
} else {
|
||||
this.plugin.settings.frames.push(presets[option]);
|
||||
}
|
||||
yield this.plugin.saveSettings();
|
||||
this.display();
|
||||
}));
|
||||
let disclaimer = this.containerEl.createEl("p", { cls: "mod-warning" });
|
||||
disclaimer.createSpan({ text: "Please be advised that, when adding a site as a custom frame, you potentially expose personal information you enter to other plugins you have installed. For more information, see " });
|
||||
disclaimer.createEl("a", {
|
||||
text: "this discussion",
|
||||
href: "https://github.com/Ellpeck/ObsidianCustomFrames/issues/54#issuecomment-1210879685",
|
||||
cls: "mod-warning"
|
||||
});
|
||||
disclaimer.createSpan({ text: "." });
|
||||
this.containerEl.createEl("hr");
|
||||
this.containerEl.createEl("p", { text: "Need help using the plugin? Feel free to join the Discord server!" });
|
||||
this.containerEl.createEl("a", { href: "https://link.ellpeck.de/discordweb" }).createEl("img", {
|
||||
attr: { src: "https://ellpeck.de/res/discord-wide.png" },
|
||||
cls: "custom-frames-support"
|
||||
});
|
||||
this.containerEl.createEl("p", { text: "If you like this plugin and want to support its development, you can do so through my website by clicking this fancy image!" });
|
||||
this.containerEl.createEl("a", { href: "https://ellpeck.de/support" }).createEl("img", {
|
||||
attr: { src: "https://ellpeck.de/res/generalsupport-wide.png" },
|
||||
cls: "custom-frames-support"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// src/view.ts
|
||||
var import_obsidian3 = __toModule(require("obsidian"));
|
||||
var _CustomFrameView = class extends import_obsidian3.ItemView {
|
||||
constructor(leaf, settings, data, name) {
|
||||
super(leaf);
|
||||
this.data = data;
|
||||
this.name = name;
|
||||
this.frame = new CustomFrame(settings, data);
|
||||
this.navigation = data.openInCenter;
|
||||
for (let action of _CustomFrameView.actions)
|
||||
this.addAction(action.icon, action.name, () => action.action(this));
|
||||
}
|
||||
onload() {
|
||||
this.contentEl.empty();
|
||||
this.contentEl.addClass("custom-frames-view");
|
||||
this.frame.create(this.contentEl);
|
||||
}
|
||||
onPaneMenu(menu, source) {
|
||||
super.onPaneMenu(menu, source);
|
||||
for (let action of _CustomFrameView.actions) {
|
||||
menu.addItem((i) => {
|
||||
i.setTitle(action.name);
|
||||
i.setIcon(action.icon);
|
||||
i.onClick(() => action.action(this));
|
||||
});
|
||||
}
|
||||
}
|
||||
getViewType() {
|
||||
return this.name;
|
||||
}
|
||||
getDisplayText() {
|
||||
return this.data.displayName;
|
||||
}
|
||||
getIcon() {
|
||||
return getIcon(this.data);
|
||||
}
|
||||
focus() {
|
||||
this.frame.focus();
|
||||
}
|
||||
};
|
||||
var CustomFrameView = _CustomFrameView;
|
||||
CustomFrameView.actions = [
|
||||
{
|
||||
name: "Return to original page",
|
||||
icon: "home",
|
||||
action: (v) => v.frame.return()
|
||||
},
|
||||
{
|
||||
name: "Open dev tools",
|
||||
icon: "binary",
|
||||
action: (v) => v.frame.toggleDevTools()
|
||||
},
|
||||
{
|
||||
name: "Copy link",
|
||||
icon: "link",
|
||||
action: (v) => navigator.clipboard.writeText(v.frame.getCurrentUrl())
|
||||
},
|
||||
{
|
||||
name: "Open in browser",
|
||||
icon: "globe",
|
||||
action: (v) => open(v.frame.getCurrentUrl())
|
||||
},
|
||||
{
|
||||
name: "Refresh",
|
||||
icon: "refresh-cw",
|
||||
action: (v) => v.frame.refresh()
|
||||
},
|
||||
{
|
||||
name: "Go forward",
|
||||
icon: "arrow-right",
|
||||
action: (v) => v.frame.goForward()
|
||||
},
|
||||
{
|
||||
name: "Go back",
|
||||
icon: "arrow-left",
|
||||
action: (v) => v.frame.goBack()
|
||||
}
|
||||
];
|
||||
|
||||
// src/main.ts
|
||||
var CustomFramesPlugin = class extends import_obsidian4.Plugin {
|
||||
onload() {
|
||||
return __async(this, null, function* () {
|
||||
yield this.loadSettings();
|
||||
for (let frame of this.settings.frames) {
|
||||
if (!frame.url || !frame.displayName)
|
||||
continue;
|
||||
let name = `custom-frames-${getId(frame)}`;
|
||||
if (import_obsidian4.Platform.isMobileApp && frame.hideOnMobile) {
|
||||
console.log(`Skipping frame ${name} which is hidden on mobile`);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
console.log(`Registering frame ${name} for URL ${frame.url}`);
|
||||
this.registerView(name, (l) => new CustomFrameView(l, this.settings, frame, name));
|
||||
this.addCommand({
|
||||
id: `open-${name}`,
|
||||
name: `Open ${frame.displayName}`,
|
||||
callback: () => this.openLeaf(name, frame.openInCenter, false)
|
||||
});
|
||||
if (frame.addRibbonIcon)
|
||||
this.addRibbonIcon(getIcon(frame), `Open ${frame.displayName}`, (e) => this.openLeaf(name, frame.openInCenter, import_obsidian4.Platform.isMacOS ? e.metaKey : e.ctrlKey));
|
||||
} catch (e) {
|
||||
console.error(`Couldn't register frame ${name}, is there already one with the same name?`);
|
||||
}
|
||||
}
|
||||
this.addSettingTab(new CustomFramesSettingTab(this.app, this));
|
||||
this.registerMarkdownCodeBlockProcessor("custom-frames", (s, e) => {
|
||||
e.empty();
|
||||
e.addClass("custom-frames-view-file");
|
||||
let frameMatch = /frame:([^\n]+)/gi.exec(s);
|
||||
let frameName = frameMatch && frameMatch[1].trim();
|
||||
if (!frameName) {
|
||||
e.createSpan({ text: "Couldn't parse frame name" });
|
||||
return;
|
||||
}
|
||||
let data = this.settings.frames.find((f) => f.displayName == frameName);
|
||||
if (!data) {
|
||||
e.createSpan({ text: `Couldn't find a frame with name ${frameName}` });
|
||||
return;
|
||||
}
|
||||
if (import_obsidian4.Platform.isMobileApp && data.hideOnMobile) {
|
||||
e.createSpan({ text: `${frameName} is hidden on mobile` });
|
||||
return;
|
||||
}
|
||||
let styleMatch = /style:([^\n]+)/gi.exec(s);
|
||||
let style = styleMatch && styleMatch[1].trim();
|
||||
style || (style = "height: 600px;");
|
||||
let urlSuffixMatch = /urlsuffix:([^\n]+)/gi.exec(s);
|
||||
let urlSuffix = urlSuffixMatch && urlSuffixMatch[1].trim();
|
||||
urlSuffix || (urlSuffix = "");
|
||||
let frame = new CustomFrame(this.settings, data);
|
||||
frame.create(e, style, urlSuffix);
|
||||
});
|
||||
});
|
||||
}
|
||||
loadSettings() {
|
||||
return __async(this, null, function* () {
|
||||
this.settings = Object.assign({}, defaultSettings, yield this.loadData());
|
||||
});
|
||||
}
|
||||
saveSettings() {
|
||||
return __async(this, null, function* () {
|
||||
yield this.saveData(this.settings);
|
||||
});
|
||||
}
|
||||
openLeaf(name, center, split) {
|
||||
return __async(this, null, function* () {
|
||||
let leaf;
|
||||
if (center) {
|
||||
leaf = this.app.workspace.getLeaf(split);
|
||||
yield leaf.setViewState({ type: name, active: true });
|
||||
} else {
|
||||
if (!this.app.workspace.getLeavesOfType(name).length)
|
||||
yield this.app.workspace.getRightLeaf(false).setViewState({ type: name, active: true });
|
||||
leaf = this.app.workspace.getLeavesOfType(name)[0];
|
||||
this.app.workspace.revealLeaf(leaf);
|
||||
}
|
||||
if (leaf.view instanceof CustomFrameView)
|
||||
leaf.view.focus();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/* nosourcemap */
|
||||
11
.obsidian/plugins/obsidian-custom-frames/manifest.json
vendored
Normal file
11
.obsidian/plugins/obsidian-custom-frames/manifest.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"id": "obsidian-custom-frames",
|
||||
"name": "Custom Frames",
|
||||
"version": "2.5.0",
|
||||
"minAppVersion": "1.2.0",
|
||||
"description": "A plugin that turns web apps into panes using iframes with custom styling. Also comes with presets for Google Keep, Todoist and more.",
|
||||
"author": "Ellpeck",
|
||||
"authorUrl": "https://ellpeck.de",
|
||||
"fundingUrl": "https://ellpeck.de/support",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
30
.obsidian/plugins/obsidian-custom-frames/styles.css
vendored
Normal file
30
.obsidian/plugins/obsidian-custom-frames/styles.css
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
.custom-frames-view {
|
||||
padding: 0 !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
.custom-frames-view-file {
|
||||
padding: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.custom-frames-frame {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
background-color: white;
|
||||
background-clip: content-box;
|
||||
}
|
||||
|
||||
.custom-frames-add {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.custom-frames-show {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.custom-frames-support {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
@@ -942,6 +942,21 @@
|
||||
"id": "3bdb9f84-6002-45a0-ab24-683a9c5ea5a8",
|
||||
"createdAt": 1756554053733,
|
||||
"updatedAt": 1756554053733
|
||||
},
|
||||
{
|
||||
"isEncrypted": 1,
|
||||
"EncryptedData": "4186d7afa89e4b81583c357436ded730:32fe2fba0c78a7e777c8cebc22b3a6ddeb5a1cc32378bf22a5b3abbc5812b789df87e6c3d91573bb29c7b9015e89ac7bbefad00a2545875ded65b85f17f34267607837cd85e14fd312a0753e9e5a73ef60320b62e5bb9fd5ee8896606a817f912267802396d0c822b32c51415339b4657bc1bdfe2bd79610b48a09d3da6fcd96dfe4157ada08da9efd0b11efeb4ab75e9acad5ba98239f4422e92bdff94c84397fa9a59fa0db0cfcbff22aff1f0be847ddd59b05bf09050e5849f2f11cdfd866b4ca8acd364ab1f689f4bd168337eefba6db839788d5382f2e09374623ee4fdcd4450c5ab6da8cd70233a711ee4e4319a3ae717b08e3aebc9bed076508843812dc918d9348856bb16ad28c1598f6626728b55f2f04c9954835c2176540a8a38c0cd90221a18c0cf199f507a63e49b9cd8af3a1e803f02ef33c0532a68ef2dff9a082fd2b60035ce29b3ba30c488e1aab52108c2f0bb9ab03a658b4682de3f539ae5945041e03851e5c49f58840c72f8941d4358126366101c50cc0db5df59be863d50ab98738065e5c2c2458159a8ac1c5a430c6030fc0c7b43ed89b1e320941e55508514859caaaa7eae68f30310e1de6af4064253ba2bc797bcd57eb393d6c0ed69ac0bdfdd417c9773148083627d889761463d68f0bdd1c019735729b935df03ce5dd97576a6a409f633ba14d91995e8749adadf082c5877ec35155052e1432e2e6cc4ff57b2883affbd4583bfade2ba795a45588ac4fbc541f03176f7cabfdbb0fcb9de75ea5c3290f80d63f0ac82cffc8515afae0037f571d34de0d800456a9b5aae381543e4442ba1d779296feedbcadf5baadf90f97ca6ae656ccdbc50757a8074c3550a036f1e9226bad806ca04645c76d687fd08162b11724d6844ad5c9cbae08ad8ba9a66efe8ab1373fe3",
|
||||
"fileName": "image.png",
|
||||
"width": 447,
|
||||
"height": 312,
|
||||
"extname": ".png",
|
||||
"imgUrl": "https://joyimg.cpolar.top/i/2025/08/31/68b3bf0beaf6a.png",
|
||||
"hash": "ntO0XS",
|
||||
"type": "lskyplist",
|
||||
"shortUrl": "https://joyimg.cpolar.top/i/2025/08/31/68b3bf0beaf6a.png",
|
||||
"id": "53d64f4b-7718-4455-a9da-be097376722d",
|
||||
"createdAt": 1756610316955,
|
||||
"updatedAt": 1756610316955
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -5,16 +5,28 @@
|
||||
"path": "01-工作日记/2025-08-31.md"
|
||||
},
|
||||
{
|
||||
"basename": "成都旅游亮点@20250831_104638",
|
||||
"path": "60-Imports/64-AI/成都旅游亮点@20250831_104638.md"
|
||||
"basename": "AI使用评测",
|
||||
"path": "02-技术评测/AI专题/AI使用评测.md"
|
||||
},
|
||||
{
|
||||
"basename": "Changsha_Summer_Attractions_Guide@20250831_095229",
|
||||
"path": "60-Imports/64-AI/Changsha_Summer_Attractions_Guide@20250831_095229.md"
|
||||
},
|
||||
{
|
||||
"basename": "长沙夏季旅游推荐@20250831_095229",
|
||||
"path": "60-Imports/64-AI/长沙夏季旅游推荐@20250831_095229.md"
|
||||
},
|
||||
{
|
||||
"basename": "Changsha_Summer_Attractions_Guide@20250831_095229",
|
||||
"path": "60-Imports/64-AI/Changsha_Summer_Attractions_Guide@20250831_095229.md"
|
||||
"basename": "成都旅游亮点@20250831_104638",
|
||||
"path": "60-Imports/64-AI/成都旅游亮点@20250831_104638.md"
|
||||
},
|
||||
{
|
||||
"basename": "感谢DeepSeek,1天就赚了3100",
|
||||
"path": "10-WebClipper/感谢DeepSeek,1天就赚了3100.md"
|
||||
},
|
||||
{
|
||||
"basename": "Linux查看某个程序占用的端口号_linux查询某个程序的端口号-CSDN博客",
|
||||
"path": "10-WebClipper/Linux查看某个程序占用的端口号_linux查询某个程序的端口号-CSDN博客.md"
|
||||
},
|
||||
{
|
||||
"basename": "OnlyOffice安装教程",
|
||||
@@ -124,10 +136,6 @@
|
||||
"basename": "扩展无限可能:Obsidian Web Viewer插件解析",
|
||||
"path": "10-WebClipper/扩展无限可能:Obsidian Web Viewer插件解析.md"
|
||||
},
|
||||
{
|
||||
"basename": "Linux查看某个程序占用的端口号_linux查询某个程序的端口号-CSDN博客",
|
||||
"path": "10-WebClipper/Linux查看某个程序占用的端口号_linux查询某个程序的端口号-CSDN博客.md"
|
||||
},
|
||||
{
|
||||
"basename": "Obsidian笔记多端同步解决办法 | DiyBeta's Blog",
|
||||
"path": "10-WebClipper/Obsidian笔记多端同步解决办法 | DiyBeta's Blog.md"
|
||||
@@ -191,10 +199,6 @@
|
||||
{
|
||||
"basename": "党员组织看山河为证2个多小时 晚上在最大的杨裕兴面馆吃面 (2025-08-25 19-25)",
|
||||
"path": "50-Memos/2025/08/党员组织看山河为证2个多小时 晚上在最大的杨裕兴面馆吃面 (2025-08-25 19-25).md"
|
||||
},
|
||||
{
|
||||
"basename": "督导任职期限已到(7月),收入要下降很多,今后要靠自己努力挣钱了! 花钱也要谨慎行事! 也许是个好事... (2025-08-21 18-21)",
|
||||
"path": "50-Memos/2025/08/督导任职期限已到(7月),收入要下降很多,今后要靠自己努力挣钱了! 花钱也要谨慎行事! 也许是个好事... (2025-08-21 18-21).md"
|
||||
}
|
||||
],
|
||||
"omittedPaths": [],
|
||||
|
||||
254
.obsidian/plugins/rss-reader/data.json
vendored
254
.obsidian/plugins/rss-reader/data.json
vendored
File diff suppressed because one or more lines are too long
@@ -27,11 +27,12 @@
|
||||
"01-工作日记/2025-08-30.md": "9dc24b4973b63d59ed0f259b4ab6b6f38525f707f668ea82a68935a534a18a42",
|
||||
"06-数字仓库/端口映射对照表.md": "02c569c8b8c525d576f22d7d8d83275d8b60cfe9f51d4065d843372da6b86e2d",
|
||||
"08-Inbox/Excel 2025-08-01 17.49.04.univer.md": "7a8a85a3c7c5f4ad80a1c399ca77e9671584234a3a82f65544049ec9c1f5a154",
|
||||
"01-工作日记/2025-08-31.md": "14bcbfa7f323c9c4d6f18eae0e1b8299811957fb38b569cefd171c1548cda82f",
|
||||
"01-工作日记/2025-08-31.md": "db101e330ffd14b56751b050ccbf00c76540ea3f605756ffba3ece634ad29560",
|
||||
"10-WebClipper/Linux查看某个程序占用的端口号_linux查询某个程序的端口号-CSDN博客.md": "e251845cda470738f6f7beb847b630c12853bfa1e49a57bcdb87a8767b7c989c",
|
||||
"60-Imports/64-AI/Changsha_Summer_Attractions_Guide@20250831_095229.md": "f91c93a7bde7ba81df09cfd690ae97b7aecebcf3a368615b14aa3819e6bcabaa",
|
||||
"03-学习笔记/OnlyOffice安装教程.md": "3b235b9f560f3725342320f73512fd394c85fb4981fcdf4f32e8ff30d0c053b8",
|
||||
"60-Imports/64-AI/长沙夏季旅游推荐@20250831_095229.md": "8db5a8c3ab8a290432df75f45086447eef8ea55822e7661684346b5fde55f4bb",
|
||||
"03-学习笔记/s3 docker搭建教程.md": "5ff03c85c062d2f13e67e99d25ae4776c80bc4eaddb3465d08dbd010c9049ce2"
|
||||
"03-学习笔记/s3 docker搭建教程.md": "5ff03c85c062d2f13e67e99d25ae4776c80bc4eaddb3465d08dbd010c9049ce2",
|
||||
"02-技术评测/AI专题/AI使用评测.md": "94522676e07cf438c98b5925fb7dcdbfbde84ccfefdb47c2e8ad6eaf5c72af3c"
|
||||
}
|
||||
}
|
||||
48
.obsidian/workspace.json
vendored
48
.obsidian/workspace.json
vendored
@@ -21,6 +21,20 @@
|
||||
"title": "2025-08-31"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "fc230081095b63d4",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "webviewer",
|
||||
"state": {
|
||||
"url": "https://zhuanlan.zhihu.com/p/22025416547",
|
||||
"title": "(80 封私信 / 80 条消息) 在obsidian中使用deepseek,构建智能知识助手从未如此简单 - 知乎",
|
||||
"mode": "webview"
|
||||
},
|
||||
"icon": "globe-2",
|
||||
"title": "(80 封私信 / 80 条消息) 在obsidian中使用deepseek,构建智能知识助手从未如此简单 - 知乎"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "b98b48d9165a0618",
|
||||
"type": "leaf",
|
||||
@@ -62,22 +76,9 @@
|
||||
"icon": "globe-2",
|
||||
"title": "DeepSeek based extension when? : r/ObsidianMD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "f0dbe0513bf59b3f",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "60-Imports/64-AI/成都旅游亮点@20250831_104638.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
},
|
||||
"icon": "lucide-file",
|
||||
"title": "成都旅游亮点@20250831_104638"
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
"currentTab": 1
|
||||
}
|
||||
],
|
||||
"direction": "vertical"
|
||||
@@ -234,13 +235,12 @@
|
||||
"state": {
|
||||
"type": "outline",
|
||||
"state": {
|
||||
"file": "01-工作日记/2025-08-31.md",
|
||||
"followCursor": false,
|
||||
"showSearch": false,
|
||||
"searchQuery": ""
|
||||
},
|
||||
"icon": "lucide-list",
|
||||
"title": "2025-08-31 的大纲"
|
||||
"title": "大纲"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -364,18 +364,21 @@
|
||||
"periodic-notes:Open today": false
|
||||
}
|
||||
},
|
||||
"active": "079e831c90d4cd73",
|
||||
"active": "fc230081095b63d4",
|
||||
"lastOpenFiles": [
|
||||
"60-Imports/64-AI/成都旅游亮点@20250831_104638.md",
|
||||
"60-Imports/64-AI/长沙夏季旅游推荐@20250831_095229.md",
|
||||
"01-工作日记/2025-08-31.md",
|
||||
"02-技术评测/AI专题/AI使用评测.md",
|
||||
"60-Imports/64-AI/Changsha_Summer_Attractions_Guide@20250831_095229.md",
|
||||
"60-Imports/64-AI/长沙夏季旅游推荐@20250831_095229.md",
|
||||
"60-Imports/64-AI/成都旅游亮点@20250831_104638.md",
|
||||
"10-WebClipper/感谢DeepSeek,1天就赚了3100.md",
|
||||
"10-WebClipper/Linux查看某个程序占用的端口号_linux查询某个程序的端口号-CSDN博客.md",
|
||||
"03-学习笔记/OnlyOffice安装教程.md",
|
||||
"03-学习笔记/s3 docker搭建教程.md",
|
||||
"未命名 1.md",
|
||||
"未命名.md",
|
||||
"copilot-conversations/s3 docker搭建教程.md",
|
||||
"copilot-conversations",
|
||||
"01-工作日记/2025-08-31.md",
|
||||
"60-Imports/64-AI",
|
||||
"90-学习教程/99-黑曜石玩家指南/4-obsidian附录/obsidian第三方插件列表.md",
|
||||
"70-SimpRead/Inbox/0-简悦 x FlowUs:开启知识管理极致体验@annote.md",
|
||||
@@ -391,9 +394,6 @@
|
||||
"20-我的收藏夹/21-浏览器收藏/Favorites/快速安装Homebrew教程 - Homebrew 中文网.md",
|
||||
"20-我的收藏夹/21-浏览器收藏/Favorites/ipa软件下载ios软件下载.md",
|
||||
"20-我的收藏夹/21-浏览器收藏/Favorites/发现和分享 Siri 捷径、快捷指令 捷径社区.md",
|
||||
"20-我的收藏夹/21-浏览器收藏/ClipperBox/女人会嫁给谁,其实是命中注定的,看她的父母就知道了.md",
|
||||
"20-我的收藏夹/21-浏览器收藏/ClipperBox/Podginatoromnivore Omnivore is a complete, open source read-it-later solution for people who like reading.md",
|
||||
"20-我的收藏夹/21-浏览器收藏/ClipperBox/jgchristopherobsidian-clipper Obsidian plugin that allows users to clip parts of a website into their obsidian daily note (or new note).md",
|
||||
"08-Inbox/数据备份实现流程.smm",
|
||||
"08-Inbox/数据备份流程.xmind",
|
||||
"08-Inbox/数据备份流程.png",
|
||||
|
||||
@@ -6,7 +6,7 @@ tags:
|
||||
rating: ⭐️
|
||||
excerpt:
|
||||
created: 2025-08-31T07:35
|
||||
updated: 2025-08-31T10:54
|
||||
updated: 2025-08-31T11:41
|
||||
---
|
||||
## 1TODO
|
||||
- [ ] 多喝水,避免久坐不动
|
||||
@@ -20,7 +20,7 @@ updated: 2025-08-31T10:54
|
||||
|
||||
## 2 Tracking
|
||||
- 飞牛:安装onlyoffice套件,预览各种文件很方便丝滑,开放了什么端口?
|
||||
- 学习使用copilot插件:V3和R1差不多,使用https://api.siliconflow.cn/v1
|
||||
- 学习使用copilot插件:V3和R1差不多,使用https://api.siliconflow.cn/v1,deppseek-R1/V3
|
||||
- 更新ollama:新添模型deepseek-V3,下载很慢
|
||||
- copilot:保存为笔记时,要清楚历史记录,否则会全部保存到笔记中,而且,如果之前保存过的笔记,后续又有新的聊天记录,会都添加到之前的笔记中,不会有新增笔记提示!
|
||||
|
||||
@@ -35,6 +35,8 @@ netstat -tunlp | grep 8080
|
||||
https://zhuanlan.zhihu.com/p/661410366
|
||||
|
||||
Webclipper错误指向另一个Vault,重启浏览器,webclipper恢复正常!
|
||||
- 发现一个好插件:multipost,浏览器插件,向多平台发文!
|
||||
|
||||
## 4 Questions
|
||||
- M1:Alist localhost:5244 rclone:配置了myCloudDrive-webdav,alist-desktop 映射到M1 目录文件总是为空?!
|
||||
-
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
created: 2025-08-30T10:17
|
||||
updated: 2025-08-31T11:18
|
||||
---
|
||||
|
||||
|
||||
## 1 Googl Gemini
|
||||
@@ -22,3 +26,6 @@ https://chat.lanjingai.org/
|
||||
**电脑客户端**:**[🌟Windows客户端](https://chat.lanjingai.org/file/system/LanJingAI-Windows.zip)**、 **[🌟MacOS客户端](https://chat.lanjingai.org/file/system/LanJingAI-MacOS.zip)** | **手机APP**:**[🌟Android 下载](https://chat.lanjingai.org/file/system/LanJingAI-Android.zip)**
|
||||
**客服QQ群**: **470620736**
|
||||
|
||||
## 2 ObsidianAI插件
|
||||
|
||||

|
||||
|
||||
256
10-WebClipper/感谢DeepSeek,1天就赚了3100.md
Normal file
256
10-WebClipper/感谢DeepSeek,1天就赚了3100.md
Normal file
@@ -0,0 +1,256 @@
|
||||
这是苍何的第 303 篇原创!
|
||||
|
||||
大家好,我是苍何。
|
||||
|
||||
今天在 AI 群看到有小伙伴问关于 DeepSeek 本地部署的事情:
|
||||
|
||||

|
||||
|
||||
讲真,我还真收藏了很多的教程和攻略,甚至我还去万能的宝随手一搜:
|
||||
|
||||

|
||||
|
||||
好家伙,不搜不知道,一搜吓一跳,这玩意居然这么赚钱?24 小时内 200+人已买,**按照 15.5 单价的话,1 天至少爆赚 3100 元啊**。
|
||||
|
||||
1 天 3100 元,一个月就是 93000 元,这得是多少个月的工资啊,这一波还真得感谢下 DeepSeek。(此时的我留下了不争气的泪水😭)
|
||||
|
||||
这还只是个简单的教程,而且说实话,本地部署对于很多小伙伴估计就是几分钟的事情。
|
||||
|
||||
不过有需求的地方就有市场嘛,作为一名合格的科技博主,必须也得整点科技与狠活。
|
||||
|
||||
**今天就来安排下本地部署 DeepSeek 教程**,这是我集大家之所长,亲自试验总结的教程,小白也能看懂。(不信你发给你妈咪试试🐶)
|
||||
|
||||
不信你看,就简单 3 步:
|
||||
|
||||

|
||||
|
||||
当然了,在教程前,先来个灵魂拷问:**为啥要本地部署?**
|
||||
|
||||
我觉得吧,你要想本地能和官网一样的效果,那是不现实的,说实话也没这个必要,但本地部署最终要的是能解决数据隐私的问题。
|
||||
|
||||
他是你自己的智能助手,况且折腾本身也是对 AI 更理解的一种实践,毕竟马克思曾说过:
|
||||
|
||||
**实践是检验真理的唯一标准。**
|
||||
|
||||
## 第一步 :安装 Ollama
|
||||
|
||||
Ollama 是个啥?你可以叫它「欧拉马」,可以理解成是个自己电脑上运行大语言模型的容器,开源,免费,不用联网。
|
||||
|
||||
这玩意怎么下?要么直接搜索 Ollama:
|
||||
|
||||

|
||||
|
||||
要么,就直接点击这个链接:https://ollama.com ,就可进入官网:
|
||||
|
||||

|
||||
|
||||
(ps:这个呆萌的羊驼还挺有意思😂)
|
||||
|
||||
点击 Download 进行下载,选择自己电脑对应的版本即可:
|
||||
|
||||

|
||||
|
||||
> 特别注意:这里下载需要特殊的网络环境。如果省的麻烦,也可以直接发消息给此公众号获取,我都下载好了,暗号:**Ollama**
|
||||
|
||||
下载好后,直接点击对应的 app 运行:
|
||||
|
||||

|
||||
|
||||
点击 install 下载命令行(下载后就可以在命令号使用 Ollama 命令啦):
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
如果你是 macos,就可以在菜单栏看到 Ollama 的小图标啦,这表明基础环境已经 ok。
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
## 第二步:下载 DeepSeek-R 1 模型
|
||||
|
||||
还是打开刚才的 Ollama 官网,进入「Models」页面。
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
搜索或直接找到「deepseek-r1」模型。
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
直接根据自己电脑配置选择对应参数的模型下载:
|
||||
|
||||
那你肯定会问,我电脑该选择哪个尺寸的下载呢?1.5b、7b、8b、14b 这些是啥?
|
||||
|
||||
1.5b 这些其实是大语言模型的参数规模,单位是 **billion,B**,即**十亿**。
|
||||
|
||||
比如 1.5b 就代表是 15亿参数。
|
||||
|
||||
一般来说,**参数越多,模型的能力越强,但计算资源需求也越大**。如果你看到这些数字,基本可以理解成这是某个AI模型的体型大小。
|
||||
|
||||
需要先确定自己的内存大小及存储,一般来说,模型参数越大,所需的计算资源和内存也越多。
|
||||
|
||||
> 如果您的设备内存为 8 GB,建议选择 1.5 B 或 7 B 模型,以确保模型能够流畅运行。如果您的设备内存为 16 GB 或更高,可以考虑选择 8 B 或 14 B 模型。至于 32 B 模型,可能需要更高的硬件配置才能流畅运行。
|
||||
|
||||
那怎么看自己电脑的配置呢?你可以直接搜索,但我这里建议你直接问 DeepSeek,更快获得答案🐶
|
||||
|
||||
比如我电脑配置就是这个(mac m1)。
|
||||
|
||||
我的内存大小:
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
我的硬盘存储剩余空间:
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
显卡查看:
|
||||
|
||||
> 由于 M 1 采用 **统一架构(SoC)**,GPU(显卡)是集成在芯片中的,所以你不会看到独立显卡的名称,而是看到 **Apple M 1** 及其变体。
|
||||
|
||||
和独立显卡的一个对标情况:
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
当然你如果是有独立显卡的就可以直接查看自己的显卡配置。
|
||||
|
||||
好了,经过一番综合对比,最终我觉得我的小电脑运行个 8b 参数的模型勉强够用,于是乎,继续开整。
|
||||
|
||||
直接复制这个命令:
|
||||
|
||||
```
|
||||
ollama run deepseek-r1:8b
|
||||
```
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
然后打开你电脑的终端,直接执行:
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
我家的网速一般,慢的时候只有 200 多 kb,可以说,我去看了姑妈打完 2 局麻将还没下载完🐶。
|
||||
|
||||
等啊等啊,终于下载完了:
|
||||
|
||||
出现这样,就表示已经部署完成:
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
这说明是用命令行启动了个客户端,你直接就可以在这里发消息和 DeepSeek 大模型对话啦。
|
||||
|
||||
我的第一个问题是:"猪能不能爬树?"
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
对于这个问题,回答的还可以,果然是推理型模型,思考的过程也给我们列出来了。(所以,大模型觉得野猪可能可以上树,如果来世我变成了一只猪,我希望自己是一只野猪🐷)
|
||||
|
||||
很多人会和苍何有一样的顾虑,我的天,我自己电脑跑个大模型,这不得把电脑资源吃透?
|
||||
|
||||
我抱着好奇心来看了下内存和 CPU 使用情况:
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
也还好啊,在推理任务过程中,也就占了 1.09G 的内存,对于拥有 16G 内存的大户来说,还可以接受😂
|
||||
|
||||
不想要继续在命令行对话了咋办?可以直接输入命令:
|
||||
|
||||
```
|
||||
/bye to exit
|
||||
```
|
||||
|
||||
这样,命令行这个客户端就关闭了。
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
这个时候 ollama 模型其实还是在后台运行的:
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
**不过如果退出所有的客户端或者任务闲置的时候,这个时候 ollama 其实已经不会占用过高的内存了,因为没有后台任务,你可以选择无视。**
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
当然如果你生怕 ollama 在后台影响你拔剑的速度,你也可以直接退出:
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
## 第三步:搭建 Chatbox 界面
|
||||
|
||||
这命令行对于不会编程的小伙伴来说,太难受了。
|
||||
|
||||
不过没关系,开源的 Chatbox 就可以解决这个问题,你可以理解成他是个好看的 UI 界面搭载的应用程序,让你和大模型对话就像呼吸空气一样自然🉑
|
||||
|
||||
使用方法也很简单,下面简单介绍一下:
|
||||
|
||||
1、下载并安装客户端
|
||||
|
||||
打开官网直接下载:**https://chatboxai.app/zh
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
选择对应的版本,比如我的是苹果芯片的:
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
下载安装后,第一次打开是这样的:
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
选择使用自己的 API Key 或者本地模型:
|
||||
|
||||
选择 Ollama API
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
(如果不小心点错了,或者之前已经安装过 Chatbox,也可以点击设置重新选择。)
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
选择本地跑的 DeepSeek:
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
除了对模型进行设置外,还可以对对话显示效果进行设置:
|
||||
|
||||
可以给助手设置头像和默认提示:
|
||||
|
||||
比如我用上了自己的头像,
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
其他的一些设置:
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
点击保存即可。
|
||||
|
||||
这个时候就可以在 UI 界面使用了:
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
**至此,简单三步,本地就运安装运行起来了 DeepSeek R1**。
|
||||
|
||||
但这个时候,在你本地跑的只是个小 baby,他并没有像官方一样智能,只能处理简单的任务。
|
||||
|
||||
不过如果只是单纯的做自己知识库助手,也够了,毕竟本地的数据也就这么多。
|
||||
|
||||
这里也给大家挖一个坑,我先调教调教他,再给大家汇报汇报战果。
|
||||
|
||||
简单 3 步骤的教程,你肯,是不是帮你省了 15.5 了?
|
||||
|
||||
甚至你还可以拿着教程做成视频再去卖?狠狠赚他一波。
|
||||
|
||||
## ending
|
||||
|
||||
我创建了一个读者 AI 交流群,群里都是一群前沿的 AI 极客,经常讨论最新的 AI 消息,用法,以及变现方法。
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
但是任何人在群里打任何广告,都会被我 T 掉。
|
||||
|
||||
如果你对这个特别的群,感兴趣,可以公众号后台私信我加入。
|
||||
|
||||
暗号:**AI**
|
||||
|
||||
|
||||
|
||||
'%20fill='%23FFFFFF'%3E%3Crect%20x='249'%20y='126'%20width='1'%20height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
|
||||
|
||||
最后,把苍何的座右铭送给大家:**我举手向苍穹,并非一定摘到星月,只是想保持这个永不屈服的姿势**。共勉 💪。
|
||||
|
||||
【我爱这个魔幻的世界】
|
||||
Reference in New Issue
Block a user