$npx -y skills add LjyYano/skill-pack --skill link-to-htmlUse when the user provides a podcast/video/article URL or an existing Obsidian note (.md) and wants a self-contained HTML viewer page generated. Produces a Podwise-inspired single-file HTML with sidebar, episode header, 6 tabs (Summary, Mindmap, Transcript, Keywords, Highlights,
| 1 | # Podcast Note → HTML Viewer |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | Read an Obsidian podcast note (`.md`) and produce a single self-contained HTML file with a Podwise-inspired UI: sidebar navigation, episode header, 6 tabbed panels, dark/light theme toggle, and interactive markmap mindmap. |
| 6 | |
| 7 | **Input:** Podcast URL (will invoke `link-to-note` skill first) **OR** path to an existing `.md` podcast note. |
| 8 | |
| 9 | **Output:** Same directory as the `.md`, same filename but `.html` extension. |
| 10 | |
| 11 | **Example:** `AI/Podcasts/商业小样37 意想不到的 AI 股 康宁.md` → `AI/Podcasts/商业小样37 意想不到的 AI 股 康宁.html` |
| 12 | |
| 13 | --- |
| 14 | |
| 15 | ## Prerequisites |
| 16 | |
| 17 | - The `.md` note must follow the `link-to-note` skill's template (frontmatter + 摘要 + Takeaways + 思维导图 + 章节导读 + 金句 + 详细论点 + 完整转录) |
| 18 | - Internet access for CDN scripts (d3, markmap-lib, markmap-view) |
| 19 | |
| 20 | --- |
| 21 | |
| 22 | ## Workflow |
| 23 | |
| 24 | ``` |
| 25 | User input |
| 26 | ├─ Podcast URL → invoke link-to-note skill → get .md path → continue ↓ |
| 27 | └─ .md file path → read .md → extract data → fill HTML template → write .html |
| 28 | ``` |
| 29 | |
| 30 | ### Step 1: If input is a URL, generate the note first |
| 31 | |
| 32 | Invoke the `link-to-note` skill with the URL. Wait for it to finish and produce the `.md` file. Then continue to Step 2. |
| 33 | |
| 34 | ### Step 2: Read and parse the `.md` note |
| 35 | |
| 36 | Extract the following data from the note: |
| 37 | |
| 38 | | Data | Source in .md | How to extract | |
| 39 | |------|--------------|----------------| |
| 40 | | `TITLE` | frontmatter `title` or first `# heading` | Direct read | |
| 41 | | `PODCAST_NAME` | frontmatter `author` | Take part before `·` (e.g. `商业就是这样 · 肖文杰 / 约小亚` → `商业就是这样`) | |
| 42 | | `DATE_DISPLAY` | frontmatter `date` | Format as `DD Mon YYYY` (e.g. `2026-03-30` → `30 Mar 2026`) | |
| 43 | | `DURATION` | frontmatter `duration` | Use as-is (e.g. `"14:36"` → `14m36s` for display) | |
| 44 | | `PLATFORM` | frontmatter `platform` | Use as-is | |
| 45 | | `SOURCE_URL` | frontmatter `source` | For links | |
| 46 | | `TAGS` | frontmatter `tags` | Array of tag strings | |
| 47 | | `SUMMARY_BODY` | `## 摘要` section, first paragraph | Text between `## 摘要` and `> [!summary]` | |
| 48 | | `TAKEAWAYS[]` | `> [!summary] Takeaways` bullet list | Each `- ` item as a string | |
| 49 | | `MINDMAP_MD` | Content inside ` ```markmap ` code block | Raw markdown text between code fences | |
| 50 | | `OUTLINES[]` | `## 章节导读` table rows | Parse `| MM:SS | title | desc |` → `{ts, text}` | |
| 51 | | `HIGHLIGHTS[]` | `> [!quote] ~ MM:SS` callouts | Parse timestamp and quote text → `{ts, text}` | |
| 52 | | `DETAILS_HTML` | `## 详细论点` through `## 个人思考` | Convert each `###` subsection to HTML `<div class="detail-section">` | |
| 53 | | `THOUGHTS[]` | `## 个人思考` checkbox items | Each `- [ ] text` as a string | |
| 54 | | `TURNS[]` | `> [!note]- 完整转录` content | Parse `**[MM:SS]** Text` → `{ts, text}` (no speaker) | |
| 55 | | `SHOWNOTES_HTML` | `> [!info]- 节目 Shownotes` content | Convert key-value pairs to `<dl class="shownotes-grid">` | |
| 56 | | `COVER_ZH` | First 2 chars of `PODCAST_NAME` | For cover placeholder | |
| 57 | | `COVER_EN` | English equivalent if available, else omit | For cover placeholder | |
| 58 | |
| 59 | ### Step 3: Generate KEYWORDS array |
| 60 | |
| 61 | Combine: |
| 62 | 1. All frontmatter `tags` (excluding generic ones like `播客笔记`) |
| 63 | 2. Extract top 10-15 high-frequency nouns/terms from the summary body |
| 64 | |
| 65 | Deduplicate and limit to ~25 keywords. |
| 66 | |
| 67 | ### Step 4: Fill the HTML template |
| 68 | |
| 69 | Read `template.html` from the skill directory. Replace all `{{PLACEHOLDER}}` tokens with extracted data. Write the result to the output `.html` file. |
| 70 | |
| 71 | --- |
| 72 | |
| 73 | ## Template Placeholders |
| 74 | |
| 75 | The template file is `template.html` (same directory as this SKILL.md). All `{{TOKEN}}` strings are replaced with episode-specific data: |
| 76 | |
| 77 | | Placeholder | Source | Example value | |
| 78 | |-------------|--------|---------------| |
| 79 | | `{{TITLE}}` | frontmatter `title` | `商业小样37 \| "意想不到的 AI 股":康宁` | |
| 80 | | `{{PODCAST_NAME}}` | frontmatter `author`, before `·` | `商业就是这样` | |
| 81 | | `{{COVER_ZH}}` | First 2 chars of `PODCAST_NAME` | `商业` | |
| 82 | | `{{COVER_ZH_FIRST_CHAR}}` | First char of `PODCAST_NAME` | `商` | |
| 83 | | `{{COVER_EN}}` | English equivalent or empty string | `JUST BUSINESS` | |
| 84 | | `{{COVER_GRADIENT_START}}` | From gradient palette | `#ff7a4e` | |
| 85 | | `{{COVER_GRADIENT_END}}` | From gradient palette | `#ee4f3a` | |
| 86 | | `{{DATE_DISPLAY}}` | Formatted from frontmatter `date` | `30 Mar 2026` | |
| 87 | | `{{DURATION_DISPLAY}}` | From frontmatter `duration` | `14m36s` | |
| 88 | | `{{PLATFORM}}` | From frontmatter `platform` | `Apple Podcasts` | |
| 89 | | `{{SUMMARY_BODY}}` | `## 摘要` first paragraph | (full text) | |
| 90 | | `{{TAKEAWAYS_HTML}}` | `<li class="takeaway">...</li>` items | (HTML string) | |
| 91 | | `{{OUTLINES_JSON}}` | JSON array | `[{ts:'00:00',text:'...'}]` | |
| 92 | | `{{TURNS_JSON}}` | JSON array | `[{ts:'00:02',text:'...'}]` (no speaker) | |
| 93 | | `{{HIGHLIGHTS_JSON}}` | JSON array | `[{ts:'01:55',text:'...'}]` | |
| 94 | | `{{KEYWORDS_JSON}}` | JSON array of strings | ` |