mirror of
https://github.com/bnchiang96/xiaohongshu-importer.git
synced 2026-07-22 05:42:21 +00:00
Merge pull request #1 from bnchiang96/master
Release v1.0.1: Add '其他' category, fix download label clickability, a…
This commit is contained in:
commit
d92f7e1299
5 changed files with 59 additions and 31 deletions
|
|
@ -14,10 +14,10 @@ Import notes from Xiaohongshu (小红书) into your Obsidian vault with ease. Th
|
|||
|
||||
### Option 1: Download from GitHub Release
|
||||
1. Visit the [latest release](https://github.com/bnchiang96/Xiaohongshu-Importer-for-Obsidian/releases/latest) on GitHub.
|
||||
2. Download the `xhs-importer.zip` file, which contains `main.js` and `manifest.json`.
|
||||
2. Download the `Xiaohongshu-Importer-for-Obsidian-v1.0.1.zip` file, which contains `main.js` and `manifest.json`.
|
||||
3. Extract the ZIP file to your Obsidian plugins folder:
|
||||
```
|
||||
unzip Xiaohongshu-Importer-for-Obsidian-v1.0.0.zip -d /path/to/your-vault/.obsidian/plugins/Xiaohongshu-Importer-for-Obsidian/
|
||||
unzip Xiaohongshu-Importer-for-Obsidian-v1.0.1.zip -d /path/to/your-vault/.obsidian/plugins/Xiaohongshu-Importer-for-Obsidian/
|
||||
```
|
||||
- Ensure the folder name matches the plugin ID: `Xiaohongshu-Importer-for-Obsidian`.
|
||||
4. Enable the plugin in Obsidian:
|
||||
|
|
|
|||
76
main.ts
76
main.ts
|
|
@ -1,15 +1,15 @@
|
|||
import { Plugin, Notice, Modal, requestUrl, PluginSettingTab, App, Setting, WorkspaceLeaf } from "obsidian";
|
||||
import { Plugin, Notice, Modal, requestUrl, PluginSettingTab, App, Setting, WorkspaceLeaf, TFile } from "obsidian";
|
||||
|
||||
interface XHSImporterSettings {
|
||||
defaultFolder: string;
|
||||
categories: string[];
|
||||
categories: string[]; // User-defined categories, excluding "其他"
|
||||
lastCategory: string;
|
||||
downloadMedia: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_SETTINGS: XHSImporterSettings = {
|
||||
defaultFolder: "XHS Notes",
|
||||
categories: ["美食", "旅行", "娱乐", "知识", "工作", "情感", "个人成长", "优惠", "搞笑", "育儿", "Others"],
|
||||
categories: ["美食", "旅行", "娱乐", "知识", "工作", "情感", "个人成长", "优惠", "搞笑", "育儿"], // Removed "Others"
|
||||
lastCategory: "",
|
||||
downloadMedia: false,
|
||||
};
|
||||
|
|
@ -167,7 +167,7 @@ category: ${category}
|
|||
} else if (images.length > 0) {
|
||||
let finalImageUrl = images[0];
|
||||
if (downloadMedia) {
|
||||
const imageFilename = `${mediaSafeTitle}-cover-${Date.now()}.jpg`;
|
||||
const imageFilename = `${mediaSafeTitle}-0-${Date.now()}.jpg`; // Use index 0 to match later logic
|
||||
const downloadedFilename = await this.downloadMediaFile(images[0], mediaFolder, imageFilename);
|
||||
finalImageUrl = downloadedFilename.startsWith("http") ? downloadedFilename : `../media/${downloadedFilename}`;
|
||||
}
|
||||
|
|
@ -186,15 +186,24 @@ category: ${category}
|
|||
}
|
||||
// Handle non-video notes
|
||||
else {
|
||||
let downloadedImages: string[] = [];
|
||||
if (images.length > 0) {
|
||||
let finalImageUrl = images[0];
|
||||
if (downloadMedia) {
|
||||
const imageFilename = `${mediaSafeTitle}-cover-${Date.now()}.jpg`;
|
||||
const downloadedFilename = await this.downloadMediaFile(images[0], mediaFolder, imageFilename);
|
||||
finalImageUrl = downloadedFilename.startsWith("http") ? downloadedFilename : `../media/${downloadedFilename}`;
|
||||
// Download all images, including the first one (which will be used as the cover)
|
||||
for (let i = 0; i < images.length; i++) {
|
||||
const imageFilename = `${mediaSafeTitle}-${i}-${Date.now()}.jpg`;
|
||||
const downloadedFilename = await this.downloadMediaFile(images[i], mediaFolder, imageFilename);
|
||||
const finalImageUrl = downloadedFilename.startsWith("http") ? downloadedFilename : `../media/${downloadedFilename}`;
|
||||
downloadedImages.push(finalImageUrl);
|
||||
}
|
||||
} else {
|
||||
downloadedImages = images;
|
||||
}
|
||||
markdown += `\n\n`;
|
||||
|
||||
// Use the first downloaded image as the cover image (no separate download for cover)
|
||||
markdown += `\n\n`;
|
||||
}
|
||||
|
||||
const cleanContent = content.replace(/#[^#\s]*(?:\s+#[^#\s]*)*\s*/g, "").trim();
|
||||
markdown += `${cleanContent.split("\n").join("\n")}\n\n`;
|
||||
|
||||
|
|
@ -204,18 +213,11 @@ category: ${category}
|
|||
markdown += tags.map((tag) => `#${tag}`).join(" ") + "\n";
|
||||
markdown += "```\n\n";
|
||||
}
|
||||
|
||||
if (images.length > 0) {
|
||||
const downloadedImages = [];
|
||||
for (let i = 0; i < images.length; i++) {
|
||||
let finalImageUrl = images[i];
|
||||
if (downloadMedia) {
|
||||
const imageFilename = `${mediaSafeTitle}-${i}-${Date.now()}.jpg`;
|
||||
const downloadedFilename = await this.downloadMediaFile(images[i], mediaFolder, imageFilename);
|
||||
finalImageUrl = downloadedFilename.startsWith("http") ? downloadedFilename : `../media/${downloadedFilename}`;
|
||||
}
|
||||
downloadedImages.push(``);
|
||||
}
|
||||
markdown += downloadedImages.join("\n") + "\n";
|
||||
// Add all images (including the first one, which is already used as the cover)
|
||||
const imageMarkdown = downloadedImages.map((url) => ``).join("\n");
|
||||
markdown += `${imageMarkdown}\n`;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -344,7 +346,6 @@ category: ${category}
|
|||
|
||||
// Plugin lifecycle: Cleanup on unload (currently empty)
|
||||
onunload() {}
|
||||
|
||||
}
|
||||
|
||||
class XHSImporterSettingTab extends PluginSettingTab {
|
||||
|
|
@ -472,7 +473,7 @@ class XHSInputModal extends Modal {
|
|||
this.onSubmit = onSubmit;
|
||||
this.selectedCategory = this.settings.lastCategory && this.settings.categories.includes(this.settings.lastCategory)
|
||||
? this.settings.lastCategory
|
||||
: this.settings.categories[0];
|
||||
: this.settings.categories[0] || "其他";
|
||||
this.downloadMedia = this.settings.downloadMedia;
|
||||
}
|
||||
|
||||
|
|
@ -507,6 +508,7 @@ class XHSInputModal extends Modal {
|
|||
chipContainer.style.flexWrap = "wrap";
|
||||
chipContainer.style.gap = "8px";
|
||||
|
||||
// Add user-defined categories
|
||||
this.settings.categories.forEach((category) => {
|
||||
const chip = chipContainer.createEl("button", { text: category });
|
||||
chip.style.padding = "4px 8px";
|
||||
|
|
@ -526,23 +528,49 @@ class XHSInputModal extends Modal {
|
|||
});
|
||||
});
|
||||
|
||||
// Add hardcoded "其他" category
|
||||
const otherChip = chipContainer.createEl("button", { text: "其他" });
|
||||
otherChip.style.padding = "4px 8px";
|
||||
otherChip.style.borderRadius = "12px";
|
||||
otherChip.style.border = "1px solid #ccc";
|
||||
otherChip.style.backgroundColor = "其他" === this.selectedCategory ? "#FF2442" : "#f0f0f0";
|
||||
otherChip.style.color = "其他" === this.selectedCategory ? "#fff" : "#000";
|
||||
otherChip.style.cursor = "pointer";
|
||||
otherChip.style.transition = "background-color 0.2s";
|
||||
|
||||
otherChip.addEventListener("click", () => {
|
||||
this.selectedCategory = "其他";
|
||||
chipContainer.querySelectorAll("button").forEach((btn) => {
|
||||
btn.style.backgroundColor = btn.textContent === this.selectedCategory ? "#FF2442" : "#f0f0f0";
|
||||
btn.style.color = btn.textContent === this.selectedCategory ? "#fff" : "#000";
|
||||
});
|
||||
});
|
||||
|
||||
// Download media option
|
||||
const downloadRow = contentEl.createEl("div", { cls: "modal-row" });
|
||||
downloadRow.style.display = "flex";
|
||||
downloadRow.style.alignItems = "center";
|
||||
downloadRow.style.gap = "8px";
|
||||
const checkbox = downloadRow.createEl("input", { attr: { type: "checkbox" } });
|
||||
downloadRow.style.marginTop = "20px"; // Existing margin-top
|
||||
downloadRow.style.marginBottom = "20px"; // Added margin-bottom to match margin-top
|
||||
const checkboxId = "download-media-checkbox";
|
||||
const checkbox = downloadRow.createEl("input", { attr: { type: "checkbox", id: checkboxId } });
|
||||
checkbox.checked = this.downloadMedia;
|
||||
checkbox.addEventListener("change", () => {
|
||||
this.downloadMedia = checkbox.checked;
|
||||
});
|
||||
downloadRow.createEl("label", { text: "Download media locally for this import" });
|
||||
const label = downloadRow.createEl("label", {
|
||||
text: "Download media locally for this import",
|
||||
attr: { for: checkboxId } // Associate label with checkbox
|
||||
});
|
||||
label.style.cursor = "pointer"; // Ensure the label looks clickable
|
||||
|
||||
// Submit button
|
||||
const buttonRow = contentEl.createEl("div", { cls: "modal-row" });
|
||||
buttonRow.style.display = "flex";
|
||||
buttonRow.style.justifyContent = "flex-end";
|
||||
const submitButton = buttonRow.createEl("button", { text: "Import" });
|
||||
submitButton.style.width = "100%"; // Make the button full width
|
||||
submitButton.style.margin = "0";
|
||||
|
||||
submitButton.addEventListener("click", () => {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"id": "Xiaohongshu-Importer-for-Obsidian",
|
||||
"name": "Xiaohongshu Importer",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "Import Xiaohongshu notes into Obsidian with media and categorization.",
|
||||
"author": "Rocher Lee",
|
||||
"author": "bnchiang96",
|
||||
"authorUrl": "https://github.com/bnchiang96",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "Xiaohongshu-Importer-for-Obsidian",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "An Obsidian plugin to import Xiaohongshu (小红书) notes into your vault.",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production"
|
||||
},
|
||||
"keywords": ["obsidian", "plugin", "xiaohongshu"],
|
||||
"author": "Your Name",
|
||||
"author": "bnchiang96",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.6",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"1.0.0": "0.15.0"
|
||||
"1.0.1": "0.15.0"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue