一 学习流程的常规闭环

    按此常规闭环, 可对我们有学习计划并已添加至 SuperMemo 软件的学习材料进行常规闭环学习.

    流程为: 步骤 1-> 步骤 2-> 步骤 3-> 步骤 1

    SuperMemo实践闭环(1)-学习流程及时间管理 - 知乎 - 图1

    引用形式管理学习材料

    步骤 1.SuperMemo 添加索引

    在 SuperMemo 中放置学习材料, 如 PDF 目录索引 / 视频文件链接 / 网页内容及链接 / Obsidian 笔记链接, 通过 SuperMemo 来检索资料, 设置优先级, 安排学习计划.

    步骤 2. 开始学习不同的材料

    在 SuperMemo 外使用对应的软件来学习, 如 PDF 阅读器读 PDF,PotPlayer 看音视频, Edge 浏览器看网页资料, Obsidian 软件上做各种内容摘录或重点复习笔记.

    步骤 3. 划出重点及添加复习

    使用 PDF 阅读器备注 / 高亮提取重点, PotPlayer 书签提取重点视频, Edge 浏览器上的标注插件标注网页重点内容, Obsidian 作笔记. 对标出内容按需通过索引或者制卡的形式添加SuperMemo.


    二 学习流程的整体闭环

    上面的步骤 1 至步骤 3 的流程完成了在SuperMemo 中索引内容从学习至复习的整体闭环, 但未在 SuperMemo 中索引内容则默认被排除在外了, 所以在步骤 1 - 步骤 3 的基础上, 我们使用 Obsidian 来进一步闭环. 通过 Obsidian 建立已有知识节点与新知识节点的关系. 通过扩展已有节点的内容, 关联孤立的内容, 或添加新的节点内容. 即通过不停的织网来扩充新的学习材料, 并建立新学习索引.最终整体流程就成了:

    步骤 1-> 步骤 2-> 步骤 3->[挖掘 Obsidian 图谱中已有或新增节点关联 -> 重点或新索引]-> 步骤 1

    SuperMemo实践闭环(1)-学习流程及时间管理 - 知乎 - 图2

    Obsidian 挖掘新知识点并在 SM 中索引


    三 番茄钟进行时间管理

    使用小蕃茄软件及ManicTime 软件进行时间跟踪及蕃茄钟管理. 软件的使用及安装在专栏文章中可以参考, 因此这里不再详细说明.

    SuperMemo实践闭环(1)-学习流程及时间管理 - 知乎 - 图3

    ManicTime 时间跟踪管理

    SuperMemo实践闭环(1)-学习流程及时间管理 - 知乎 - 图4

    小蕃茄时间管理应用


    四 补充相关的操作脚本

    1. 生成学习索引并导入 SM 软件

    SuperMemo实践闭环(1)-学习流程及时间管理 - 知乎 - 图5
    SuperMemo实践闭环(1)-学习流程及时间管理 - 知乎 - 图6

    在 Windows 或 MacOS 系统上通过如上的工具或者其它你方便的方式来生成下面的待处理文件:

    pdf-files.txt

    1. /Users/Likey/Documents/电子书籍/公众号(码农沉思录)_1.pdf
    2. /Users/Likey/Documents/电子书籍/公众号(码农沉思录)_2.pdf
    3. /Users/Likey/Documents/电子书籍/公众号(码农沉思录)_3.pdf
    4. /Users/Likey/Documents/电子书籍/公众号(石杉的架构笔记)_1.pdf
    5. /Users/Likey/Documents/电子书籍/公众号(石杉的架构笔记)_2.pdf

    md-files.txt

    1. /Users/Likey/Documents/ObsidianDoc/000-MOC-内容地图索引/1-project.md
    2. /Users/Likey/Documents/ObsidianDoc/000-MOC-内容地图索引/2-areas.md
    3. /Users/Likey/Documents/ObsidianDoc/000-MOC-内容地图索引/3-resources.md
    4. /Users/Likey/Documents/ObsidianDoc/000-MOC-内容地图索引/4-archives.md
    5. /Users/Likey/Documents/ObsidianDoc/000-MOC-内容地图索引/5-helps.md

    mv-files.txt

    1. /Users/Likey/Documents/学习课程/亿级流量电商详情页系统实战(第二版):缓存架构+高可用服务架构+微服务架构/用所选项目新建的文件夹/181_商品详情页动态渲染系统:在CentOS 6安装和部署Docker/视频/课程视频.avi
    2. /Users/Likey/Documents/学习课程/亿级流量电商详情页系统实战(第二版):缓存架构+高可用服务架构+微服务架构/用所选项目新建的文件夹/182_商品详情页动态渲染系统:在CentOS 6安装mavengit以及推送github/视频/课程视频.avi

    git-files.txt

    1. https://www.runoob.com/python/python-files-io.html
    2. https://www.runoob.com/sitemap

    提取 PDF 章节信息 - 生成网页

    1. #!/usr/bin/python3
    2. # 提取PDF章节信息
    3. import fitz # = PyMuPDF
    4. with open("../pdf/list/pdf-files.txt") as f1:
    5. pdfShortNameArr = [] # duplicate remove
    6. for pdfLongName in f1.readlines():
    7. pdfLongName = pdfLongName.rstrip("\n") # strip()
    8. if pdfLongName.endswith("pdf"):
    9. try:
    10. pdfNameList = pdfLongName.split("/")
    11. pdfShortName = pdfNameList[len(pdfNameList) - 1]
    12. if pdfShortName in pdfShortNameArr:
    13. print(pdfShortName + " is exits, so skip !")
    14. continue
    15. if pdfShortName.find("-") > -1:
    16. print(pdfShortName + " contains '-' , so skip !")
    17. continue
    18. pdfShortNameArr.append(pdfShortName)
    19. doc = fitz.open(pdfLongName) # open PDF
    20. toc = doc.getToC() # get current table of contents
    21. if len(toc) == 0:
    22. print(pdfLongName + "\t未获取到TOC")
    23. continue
    24. else:
    25. print(pdfLongName)
    26. outHtmlName = "../pdf/" + pdfShortName.removesuffix(".pdf") + "-outline.html"
    27. with open(outHtmlName, mode="w", encoding="utf-8") as f:
    28. chapterInfoCnt = "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; " \
    29. "charset=UTF-8\"/>\r\n</head>\r\n<body>"
    30. for t in toc:
    31. t[2] = pdfShortName + "-" + str(t[2]) # show what we have so far
    32. # print(t[2])
    33. if str(t[2]).endswith("--1"):
    34. continue
    35. chapterInfo = "{}{}-{}{}".format("\r\n<p>", str(t[1]).strip("\n"), str(t[2]).strip("\n"), "</p>")
    36. chapterInfoCnt += chapterInfo
    37. chapterInfoCnt += "\r\n</body>\r\n</html>"
    38. f.write(chapterInfoCnt)
    39. except RuntimeError:
    40. print("RuntimeError...")

    提取 Obsidian URI 信息 - 生成网页

    1. #!/usr/bin/python3
    2. # 提取 Obsidian URI 信息
    3. from urllib.parse import quote, unquote
    4. with open("../md/list/md-files.txt") as f1:
    5. mdShortNameArr = [] # duplicate remove
    6. chapterInfoCnt = "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; " \
    7. "charset=UTF-8\"/>\r\n</head>\r\n<body>"
    8. for mdLongName in f1.readlines():
    9. mdLongName = mdLongName.rstrip("\n") # strip()
    10. if mdLongName.endswith("md"):
    11. try:
    12. mdNameList = mdLongName.split("/")
    13. mdShortName = mdNameList[len(mdNameList) - 1]
    14. if mdShortName in mdShortNameArr:
    15. print(mdShortName + " is exits, so skip !")
    16. continue
    17. # if mdShortName.find("-") > -1:
    18. # print(mdShortName + " contains '-' , so skip !")
    19. # continue
    20. mdShortNameArr.append(mdShortName)
    21. mdLongName = mdLongName.replace("/Users/Likey/Documents/ObsidianDoc/", "")
    22. prefixStr = "obsidian://open?vault=ObsidianDoc&file="
    23. obsidianURL = prefixStr + quote(mdLongName, 'utf-8')
    24. chapterInfo = "{}{}::{}{}".format("\r\n<p>", mdShortName, obsidianURL, "</p>")
    25. chapterInfoCnt += chapterInfo
    26. except RuntimeError:
    27. print("RuntimeError...")
    28. chapterInfoCnt += "\r\n</body>\r\n</html>"
    29. outHtmlName = "../md/mdList-outline.html"
    30. with open(outHtmlName, mode="w", encoding="utf-8") as f:
    31. f.write(chapterInfoCnt)

    提取 Video URI 信息 - 生成网页

    1. #!/usr/bin/python3
    2. # 提取 Video URI 信息
    3. with open("../mv/list/mv-files.txt") as f1:
    4. mvShortNameArr = [] # duplicate remove
    5. chapterInfoCnt = "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; " \
    6. "charset=UTF-8\"/>\r\n</head>\r\n<body>"
    7. for mvLongName in f1.readlines():
    8. mvLongName = mvLongName.rstrip("\n") # strip()
    9. mvSuffix = mvLongName.rsplit(".")[-1]
    10. if mvSuffix in ["mp4", "avi", "mpg", "mkv", "mp3"]:
    11. try:
    12. # mvNameList = mvLongName.split("/")
    13. # mvShortName = mvNameList[len(mvNameList) - 1]
    14. # if mvShortName in mvShortNameArr:
    15. # print(mvShortName + " is exits, so skip !")
    16. # continue
    17. # if mvShortName.find("-") > -1:
    18. # print(mvShortName + " contains '-' , so skip !")
    19. # continue
    20. # mvShortNameArr.append(mvShortName)
    21. chapterInfo = "{}{}{}".format("\r\n<p>", mvLongName, "</p>")
    22. chapterInfoCnt += chapterInfo
    23. except RuntimeError:
    24. print("RuntimeError...")
    25. chapterInfoCnt += "\r\n</body>\r\n</html>"
    26. outHtmlName = "../mv/mvList-outline.html"
    27. with open(outHtmlName, mode="w", encoding="utf-8") as f:
    28. f.write(chapterInfoCnt)

    提取 GitBook URI 信息 - 生成网页

    1. #!/usr/bin/env python3
    2. # -*- coding:utf-8 -*-
    3. # from calibre.web.feeds.recipes import BasicNewsRecipe # 引入 Recipe 基础类
    4. from bs4 import BeautifulSoup
    5. import requests
    6. import re
    7. from concurrent.futures import ThreadPoolExecutor, as_completed, wait, FIRST_COMPLETED
    8. from concurrent.futures import Future
    9. from multiprocessing import Pool
    10. # 写入有效的网址链接
    11. def write_html(article_obj):
    12. chapterInfoCnt = "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; " \
    13. "charset=UTF-8\"/>\r\n</head>\r\n<body>"
    14. article_Title = "".join(re.findall("[^\x00-\xff]|[A-Za-z0-9_]", article_obj['title']))
    15. # print(article_obj['title'])
    16. print(article_Title)
    17. href_obj_array = article_obj['href_obj_array']
    18. for href_obj in href_obj_array:
    19. linkHrefStr = str(href_obj.get('href'))
    20. try:
    21. # respCode = requests.get(linkHrefStr).status_code
    22. if linkHrefStr.startswith("http"):
    23. chapterInfo = "{}{}{}".format("\r\n<p>", href_obj, "</p>")
    24. chapterInfoCnt += chapterInfo
    25. except RuntimeError:
    26. print("RuntimeError...")
    27. chapterInfoCnt += "\r\n</body>\r\n</html>"
    28. outHtmlName = "../git/gitBooks-" + article_Title + "-outline.html"
    29. with open(outHtmlName, mode="w", encoding="utf-8") as f:
    30. f.write(chapterInfoCnt)
    31. # 获取所有的子链接
    32. def get_links(url_site):
    33. href_obj_array = [] # 定义链接内容数组
    34. siteUrls = re.findall(r"(?i)(^https?://(?:\w+\.)*?\w*\.(?:com|club\.cn|com|net|me|xyz|info|org)[\/]*)", url_site)
    35. if siteUrls:
    36. siteDomain = siteUrls[0]
    37. # 解析列表页返回 BeautifulSoup 对象 #.txt .content .url
    38. soup = BeautifulSoup(requests.get(url_site).content, 'html.parser', from_encoding="utf-8")
    39. links = soup.findAll("a")
    40. # links = soup.findAll("li",{"class":"list-group-item title"}) # 获取所有文章链接
    41. # siteUrls = re.findall(r"(?i)((^https?://(?:\w+\.)*?)(\w*\.(?:com|club\.cn|com|net|me|xyz|info))[\/]*)", site)
    42. title = soup.find("title").get_text()
    43. for link in links: # 循环处理所有文章链接
    44. if link.string:
    45. hrefText = str(link.get_text()).strip("\n").strip("\t").lstrip(" ").rstrip(" ")
    46. link.string.replace_with(hrefText)
    47. link.string = hrefText
    48. hrefLink = str(link.get('href'))
    49. sliceReverseIdx = 1 # 值为0或1时正向截取,大于1时则反向截取
    50. siteDomain = siteDomain.replace(".com/", ".com")
    51. # in current site
    52. if hrefLink.startswith("../"):
    53. if hrefLink.count("/") > 1:
    54. sliceReverseIdx = - hrefLink.count("/")
    55. siteContent = url_site.removeprefix(siteDomain)
    56. middlePathArr = siteContent.split("/")[slice(sliceReverseIdx)]
    57. # remove null obj
    58. middlePathArr = [arrStr for arrStr in middlePathArr if arrStr != '']
    59. siteMiddlePath = "/" + "/".join(middlePathArr) + "/"
    60. hrefLink_ = siteDomain + siteMiddlePath + hrefLink.replace("../", "")
    61. link['href'] = hrefLink_
    62. elif hrefLink.startswith("/"):
    63. hrefLink_ = siteDomain + hrefLink
    64. link['href'] = hrefLink_
    65. # link to another site
    66. # else:
    67. # # print(link)
    68. # 1 == 1
    69. # return href 's text and url
    70. href_obj_array.append(link)
    71. # 多线程测试链接并写网页
    72. # thread.start_new_thread(write_html(article_links))
    73. # task2 = executor.submit(write_html, article_links)
    74. # wait([task2], return_when=FIRST_COMPLETED) # as_completed
    75. write_html({'title': title, 'href_obj_array': href_obj_array})
    76. # 抓取页面内容设置
    77. def read_Files():
    78. with open("../git/list/git-files.txt") as f1:
    79. siteArr = [] # duplicate remove
    80. executor = ThreadPoolExecutor(max_workers=3)
    81. for site in f1.readlines():
    82. try:
    83. site = site.rstrip("\n") # strip()
    84. if site in siteArr:
    85. print(site + " is exits, so skip !")
    86. continue
    87. siteArr.append(site)
    88. # 获取链接地址
    89. get_links(site)
    90. except RuntimeError:
    91. print("RuntimeError...")
    92. # 获取各个网址的链接
    93. # thread.start_new_thread(get_links(site))
    94. # all_task = [executor.submit(get_links, url) for url in siteArr]
    95. # wait(all_task, return_when=FIRST_COMPLETED)
    96. if __name__ == '__main__':
    97. # print(__doc__)
    98. read_Files()

    以上生成的网页索引文件使用 IE 打开, 导入 SuperMemo 后, 可按具体情况进行 Split Article 处理.

    SuperMemo实践闭环(1)-学习流程及时间管理 - 知乎 - 图7

    PDF 文件及 Obsidian 笔记导入

    另外, 我们浏览器所有的收藏网址也可以批量导出后放入 SuperMemo 软件中增量, 如下图所示:

    SuperMemo实践闭环(1)-学习流程及时间管理 - 知乎 - 图8

    导出生成一个 favorites_2021_2_24.html

    IE 浏览器打开导出的网页并按常规流程导入 SuperMemo 中, 接下来按标签 Split 分割成多个条目.

    SuperMemo实践闭环(1)-学习流程及时间管理 - 知乎 - 图9

    IE 打开导出网页再导入 SM 并按标签 Split

    SuperMemo实践闭环(1)-学习流程及时间管理 - 知乎 - 图10

    收藏夹的网址在 SM 中分割后的效果

    2. 使用 Keyboard Maestro 脚本学习 SM 中的材料

    如下为 SuperMemo 跳转至外部软件进行材料学习的相关脚本, 因为我使用的系统为 MacOS, 所以用的是 Keyboard Maestro 软件来实现的, Win 系统你可以自己用 AHK 或者 Quicker 脚本来实现.

    SuperMemo实践闭环(1)-学习流程及时间管理 - 知乎 - 图11

    SM 软件跳转至 PDF 阅读器

    SuperMemo实践闭环(1)-学习流程及时间管理 - 知乎 - 图12

    PDF 阅读器中添加时间戳

    SuperMemo实践闭环(1)-学习流程及时间管理 - 知乎 - 图13

    SM 软件跳至 Obsidian 笔记

    SuperMemo实践闭环(1)-学习流程及时间管理 - 知乎 - 图14

    SM 软件跳至 PotPlayer 软件

    网页链接类内容可直接复用 Obsidian 的脚本, 或者直接在 SuperMemo 软件内部打开就可以的.

    SuperMemo实践闭环(1)-学习流程及时间管理 - 知乎 - 图15

    收藏夹的网址直接在 SM 中打开也行


    结尾:

    脚本内容我放置在网盘了, 我会尽量保持更新,你可以在本文评论区发现链接。 如脚本内容与文中有些许差异,一般不会影响运行,当然你也可稍微自行调整来适应自己个性化的需求。

    我是一只热爱学习的小胖子, 如果你也热爱学习, 并且对 SuperMemo 感兴趣, 欢迎转发和评论!