Skip to content

Commit a53a2cc

Browse files
committedSep 13, 2024·
1.1.1 obsidian.rb
1 parent eaefa62 commit a53a2cc

File tree

1 file changed

+166
-168
lines changed

1 file changed

+166
-168
lines changed
 

‎lib/jekyll/obsidian.rb

+166-168
Original file line numberDiff line numberDiff line change
@@ -9,134 +9,14 @@
99

1010
module Jekyll
1111
module Obsidian
12-
def self.collect_files(rootdir, path = "", counts = {dirs: 0, files: 0, size: 0})
13-
root_files_ = []
14-
Dir.entries(rootdir).each do |entry|
15-
next if entry.start_with?(".", "_")
16-
entry_path = File.join(rootdir, entry)
17-
root_files_ << if File.directory?(entry_path)
18-
next if entry.start_with?(".obsidian")
19-
counts[:dirs] += 1
20-
{name: entry, type: "dir", path: File.join(path, entry),
21-
children: collect_files(entry_path, File.join(path, entry), counts)}
22-
else
23-
next if File.zero?(entry_path) || File.empty?(entry_path)
24-
25-
file_name = entry
26-
file_name += "note" if File.extname(entry) == ".md"
27-
entry = file_name
28-
file_size = File.size(entry_path)
29-
counts[:files] += 1
30-
counts[:size] += File.size(entry_path)
31-
{name: entry, type: "file", path: File.join(path, entry), size: file_size}
32-
end
33-
end
34-
root_files_
35-
end
36-
37-
def self.build_links(rootdir, root_files_, root_files, backlinks = {}, embeds = {})
38-
root_files_.each do |file|
39-
if file[:type] == "dir"
40-
build_links(rootdir, file[:children], root_files, backlinks, embeds)
41-
elsif file[:type] == "file"
42-
entry_path = File.join(rootdir, file[:path])
43-
next if File.zero?(entry_path) || Obsidian.excluded_file_exts(file[:name])
44-
if file[:name].end_with?(".mdnote", ".canvas")
45-
begin
46-
content = File.read(entry_path)
47-
rescue Errno::ENOENT
48-
puts "Error reading file: #{entry_path} - No such file"
49-
next
50-
rescue Errno::EACCES
51-
puts "Error reading file: #{entry_path} - Permission denied"
52-
next
53-
end
54-
55-
links = content.scan(/\[\[(.*?)\]\]/).flatten
56-
57-
backlinks[file[:path]] ||= {"backlink_paths" => []}
58-
59-
links.each do |link|
60-
lowercase_link = link.downcase
61-
matched_entry = find_matching_entry(root_files, lowercase_link)
62-
if matched_entry
63-
unless matched_entry[:path] == file[:path] ||
64-
backlinks[file[:path]]["backlink_paths"].include?(matched_entry[:path])
65-
backlinks[file[:path]]["backlink_paths"] << matched_entry[:path]
66-
end
67-
end
68-
end
69-
elsif !file[:name].end_with?(".mdnote", ".canvas")
70-
if embeds[file[:path]].nil? || embeds[file[:path]]["embed_paths"].nil?
71-
embeds[file[:path]] = {"embed_paths" => [entry_path]}
72-
else
73-
unless embeds[file[:path]]["embed_paths"].include?(entry_path)
74-
embeds[file[:path]]["embed_paths"] << entry_path
75-
end
76-
end
77-
end
78-
else
79-
puts "Skipping non-markdown file: #{file[:name]}"
80-
end
81-
end
82-
[backlinks, embeds]
83-
end
84-
85-
def self.find_matching_entry(files, lowercase_link)
86-
stripped_link = lowercase_link.sub(/\|.*$/, "").sub(/#.*$/, "")
87-
files.each do |file|
88-
if file[:type] == "dir"
89-
result = find_matching_entry(file[:children], lowercase_link)
90-
return result if result
91-
elsif file[:type] == "file" && file[:name].end_with?(".mdnote", ".canvas")
92-
file_name_without_extension = file[:name].sub(/\.\w+$/, "").downcase
93-
return file if file_name_without_extension == stripped_link
94-
end
95-
end
96-
nil
97-
end
98-
99-
def self.excluded_file_exts(filename)
100-
extensions = [".exe", ".bat", ".sh", ".zip", ".7z", ".stl", ".fbx"]
101-
is_excluded = extensions.any? { |ext| filename.end_with?(ext) }
102-
if is_excluded
103-
puts "Excluded file: #{filename}"
104-
end
105-
is_excluded
106-
end
107-
108-
# ------------------------ Ruby Hash object formatters ----------------------- #
109-
def self.escape_backlinks(backlinks)
110-
escaped_backlinks = {}
111-
backlinks.each do |path, data|
112-
escaped_path = escape_path(path)
113-
escaped_data = {
114-
"backlink_paths" => data["backlink_paths"].map do |path|
115-
escape_path(path)
116-
end
117-
}
118-
escaped_backlinks[escaped_path] = escaped_data
119-
end
120-
JSON.pretty_generate(escaped_backlinks.to_json)
121-
end
122-
123-
def self.escape_embeds(embeds)
124-
escaped_embeds = {}
125-
embeds.each do |path, _|
126-
escaped_path = escape_path(path)
127-
escaped_embeds[escaped_path] = {}
128-
end
129-
JSON.pretty_generate(escaped_embeds.to_json)
130-
end
131-
132-
def self.escape_path(path)
133-
escaped_path = path.gsub("'", "/:|").gsub('"', "/:|")
134-
(escaped_path[0] == "/") ? escaped_path.slice(1..-1) : escaped_path
135-
end
136-
137-
# ---------------------------------------------------------------------------- #
138-
# FileTreeGenerator #
139-
# ---------------------------------------------------------------------------- #
12+
# Jekyll::Hooks.register :site, :post_write do |site|
13+
# vault = site.config["obsidian_vault"]
14+
# vault_path = File.join(site.dest, vault)
15+
# Dir.glob(File.join(vault_path, "**", "*.md")).each do |md_file|
16+
# new_file_path = md_file.sub(/\.md$/, ".mdnote")
17+
# File.rename(md_file, new_file_path)
18+
# end
19+
# end
14020
class FileTreeGenerator < Jekyll::Generator
14121
safe true
14222
priority :lowest
@@ -148,11 +28,43 @@ def generate(site)
14828
puts "Error: obsidian_vault is not set in config.yml"
14929
exit(1)
15030
end
151-
site.config["obsidian_homepage"]
31+
enable_backlinks = site.config["obsidian_backlinks"]
32+
enable_embeds = site.config["obsidian_embeds"]
15233

15334
# --------------------------------- site data -------------------------------- #
35+
data_dir = File.join(File.dirname(site.dest), "_data", "obsidian")
36+
FileUtils.mkdir_p(data_dir) unless File.directory?(data_dir)
37+
15438
site.data["obsidian"] = {} unless site.data["obsidian"]
15539

40+
counts = {dirs: 0, files: 0, size: 0}
41+
obsidian_files = collect_files(vault, "", counts)
42+
vault_data_json = File.join(data_dir, "vault_data.json")
43+
File.write(vault_data_json, JSON.pretty_generate(counts.to_json))
44+
45+
vault_files_json = File.join(data_dir, "vault_files.json")
46+
File.write(vault_files_json, JSON.pretty_generate(obsidian_files.to_json))
47+
48+
backlinks, embeds = build_links(vault, obsidian_files, obsidian_files)
49+
50+
if enable_backlinks || enable_backlinks.nil?
51+
backlinks_json = File.join(data_dir, "backlinks.json")
52+
File.write(backlinks_json, escape_backlinks(backlinks))
53+
puts "Backlinks built."
54+
else
55+
puts "Backlinks disabled"
56+
end
57+
58+
if enable_embeds || enable_embeds.nil?
59+
embeds_json = File.join(data_dir, "embeds.json")
60+
File.write(embeds_json, escape_embeds(embeds))
61+
puts "Embeds built."
62+
else
63+
puts "Embeds disabled"
64+
end
65+
66+
site.config["obsidian_homepage"]
67+
15668
obsidian_dir = File.join(File.dirname(site.dest), "_includes", "obsidian")
15769
FileUtils.mkdir_p(obsidian_dir) unless File.directory?(obsidian_dir)
15870

@@ -203,50 +115,136 @@ def copy_files_from_dir(source_dir, destination_dir, overwrite = false)
203115
copy_file_to_dir(file_path, destination_dir, overwrite)
204116
end
205117
end
206-
end
207118

208-
# ---------------------------------------------------------------------------- #
209-
# POST_WRITE HOOK REGISTER #
210-
# ---------------------------------------------------------------------------- #
211-
Jekyll::Hooks.register :site, :post_write do |site|
212-
vault = site.config["obsidian_vault"]
213-
vault_path = File.join(site.dest, vault)
214-
Dir.glob(File.join(vault_path, "**", "*.md")).each do |md_file|
215-
new_file_path = md_file.sub(/\.md$/, ".mdnote")
216-
File.rename(md_file, new_file_path)
119+
def excluded_file_exts(filename)
120+
extensions = [".exe", ".bat", ".sh", ".zip", ".7z", ".stl", ".fbx"]
121+
is_excluded = extensions.any? { |ext| filename.end_with?(ext) }
122+
if is_excluded
123+
puts "Excluded file: #{filename}"
124+
end
125+
is_excluded
217126
end
218-
data_dir = File.join(File.dirname(site.dest), "_data", "obsidian")
219-
FileUtils.mkdir_p(data_dir) unless File.directory?(data_dir)
220-
enable_backlinks = site.config["obsidian_backlinks"]
221-
enable_embeds = site.config["obsidian_embeds"]
222-
223-
counts = {dirs: 0, files: 0, size: 0}
224-
obsidian_files = Obsidian.collect_files(vault, "", counts)
225-
vault_data_json = File.join(data_dir, "vault_data.json")
226-
File.write(vault_data_json, JSON.pretty_generate(counts.to_json))
227-
228-
vault_files_json = File.join(data_dir, "vault_files.json")
229-
File.write(vault_files_json, JSON.pretty_generate(obsidian_files.to_json))
230-
231-
vault_path = File.join(site.dest, vault)
232-
backlinks, embeds = Obsidian.build_links(vault_path, obsidian_files, obsidian_files)
233-
234-
if enable_backlinks || enable_backlinks.nil?
235-
backlinks_json = File.join(data_dir, "backlinks.json")
236-
File.write(backlinks_json, Obsidian.escape_backlinks(backlinks))
237-
puts "Backlinks built."
238-
else
239-
puts "Backlinks disabled"
127+
128+
# ------------------------ Ruby Hash object generators ----------------------- #
129+
def collect_files(rootdir, path = "", counts = {dirs: 0, files: 0, size: 0})
130+
root_files_ = []
131+
Dir.entries(rootdir).each do |entry|
132+
next if entry.start_with?(".", "_")
133+
entry_path = File.join(rootdir, entry)
134+
root_files_ << if File.directory?(entry_path)
135+
next if entry.start_with?(".obsidian")
136+
counts[:dirs] += 1
137+
{name: entry, type: "dir", path: File.join(path, entry),
138+
children: collect_files(entry_path, File.join(path, entry), counts)}
139+
else
140+
next if File.zero?(entry_path) || File.empty?(entry_path)
141+
142+
if File.extname(entry) == ".md"
143+
new_name = entry.sub(".md", ".mdnote")
144+
new_path = File.join(rootdir, new_name)
145+
File.rename(entry_path, new_path)
146+
entry_path = new_path
147+
entry = new_name
148+
end
149+
150+
counts[:files] += 1
151+
counts[:size] += File.size(entry_path)
152+
{name: entry, type: "file", path: File.join(path, entry), size: File.size(entry_path)}
153+
end
154+
end
155+
root_files_
240156
end
241157

242-
if enable_embeds || enable_embeds.nil?
243-
embeds_json = File.join(data_dir, "embeds.json")
244-
File.write(embeds_json, Obsidian.escape_embeds(embeds))
245-
puts "Embeds built."
246-
else
247-
puts "Embeds disabled"
158+
def build_links(rootdir, root_files_, root_files, backlinks = {}, embeds = {})
159+
root_files_.each do |file|
160+
if file[:type] == "dir"
161+
build_links(rootdir, file[:children], root_files, backlinks, embeds)
162+
elsif file[:type] == "file"
163+
entry_path = File.join(rootdir, file[:path])
164+
next if File.zero?(entry_path) || excluded_file_exts(file[:name])
165+
if file[:name].end_with?(".mdnote", ".canvas")
166+
begin
167+
content = File.read(entry_path)
168+
rescue Errno::ENOENT
169+
puts "Error reading file: #{entry_path} - No such file"
170+
next
171+
rescue Errno::EACCES
172+
puts "Error reading file: #{entry_path} - Permission denied"
173+
next
174+
end
175+
176+
links = content.scan(/\[\[(.*?)\]\]/).flatten
177+
178+
backlinks[file[:path]] ||= {"backlink_paths" => []}
179+
180+
links.each do |link|
181+
lowercase_link = link.downcase
182+
matched_entry = find_matching_entry(root_files, lowercase_link)
183+
if matched_entry
184+
unless matched_entry[:path] == file[:path] ||
185+
backlinks[file[:path]]["backlink_paths"].include?(matched_entry[:path])
186+
backlinks[file[:path]]["backlink_paths"] << matched_entry[:path]
187+
end
188+
end
189+
end
190+
elsif !file[:name].end_with?(".mdnote", ".canvas")
191+
if embeds[file[:path]].nil? || embeds[file[:path]]["embed_paths"].nil?
192+
embeds[file[:path]] = {"embed_paths" => [entry_path]}
193+
else
194+
unless embeds[file[:path]]["embed_paths"].include?(entry_path)
195+
embeds[file[:path]]["embed_paths"] << entry_path
196+
end
197+
end
198+
end
199+
else
200+
puts "Skipping non-markdown file: #{file[:name]}"
201+
end
202+
end
203+
[backlinks, embeds]
204+
end
205+
206+
def find_matching_entry(files, lowercase_link)
207+
stripped_link = lowercase_link.sub(/\|.*$/, "").sub(/#.*$/, "")
208+
files.each do |file|
209+
if file[:type] == "dir"
210+
result = find_matching_entry(file[:children], lowercase_link)
211+
return result if result
212+
elsif file[:type] == "file" && file[:name].end_with?(".mdnote", ".canvas")
213+
file_name_without_extension = file[:name].sub(/\.\w+$/, "").downcase
214+
return file if file_name_without_extension == stripped_link
215+
end
216+
end
217+
nil
218+
end
219+
220+
# ------------------------ Ruby Hash object formatters ----------------------- #
221+
def escape_backlinks(backlinks)
222+
escaped_backlinks = {}
223+
backlinks.each do |path, data|
224+
escaped_path = escape_path(path)
225+
escaped_data = {
226+
"backlink_paths" => data["backlink_paths"].map do |path|
227+
escape_path(path)
228+
end
229+
}
230+
escaped_backlinks[escaped_path] = escaped_data
231+
end
232+
JSON.pretty_generate(escaped_backlinks.to_json)
248233
end
249-
end
250234

235+
def escape_embeds(embeds)
236+
escaped_embeds = {}
237+
embeds.each do |path, _|
238+
escaped_path = escape_path(path)
239+
escaped_embeds[escaped_path] = {}
240+
end
241+
JSON.pretty_generate(escaped_embeds.to_json)
242+
end
243+
244+
def escape_path(path)
245+
escaped_path = path.gsub("'", "/:|").gsub('"', "/:|")
246+
(escaped_path[0] == "/") ? escaped_path.slice(1..-1) : escaped_path
247+
end
248+
end
251249
end
252250
end

0 commit comments

Comments
 (0)
Please sign in to comment.