mirror of
https://github.com/mousebomb/obsidian-diary-ics.git
synced 2026-07-22 05:49:47 +00:00
支持从标题中提取时间填充到生成的ics事件中
console.log (this.extractTimeFromTitle("10:00~12:00嘿嘿"))
console.log (this.extractTimeFromTitle("10:00-12:00 嘿嘿2"))
console.log (this.extractTimeFromTitle("嘿嘿3 10:00~12:00"))
console.log (this.extractTimeFromTitle("嘿嘿410:00~12:00"))
console.log (this.extractTimeFromTitle("09:00diary-ics支持时间的方案"))
console.log (this.extractTimeFromTitle("09:00 diary-ics支持时间的方案2"))
This commit is contained in:
parent
ceb7350a29
commit
149a99e4ba
3 changed files with 115 additions and 9 deletions
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "diary-ics",
|
||||
"name": "Diary ICS",
|
||||
"version": "1.0.10",
|
||||
"version": "1.0.11",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "Sync diary entries to system calendar via ICS feed.",
|
||||
"author": "Mousebomb",
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ interface LanguageStrings {
|
|||
h2Option: string;
|
||||
includeSubheadingsSetting: string;
|
||||
includeSubheadingsDesc: string;
|
||||
extractTimeRangeSetting: string;
|
||||
extractTimeRangeDesc: string;
|
||||
diarySettingsTitle: string;
|
||||
diaryFormatSetting: string;
|
||||
diaryFormatDesc: string;
|
||||
|
|
@ -83,6 +85,8 @@ const en: LanguageStrings = {
|
|||
h2Option: "Level 2 heading (##)",
|
||||
includeSubheadingsSetting: "Include subheadings",
|
||||
includeSubheadingsDesc: "Include subheadings under the heading in the calendar event description",
|
||||
extractTimeRangeSetting: "Auto-extract time range",
|
||||
extractTimeRangeDesc: "Automatically extract HH:mm or HH:mm~HH:mm format time from title as event start and end time",
|
||||
diarySettingsTitle: "Diary",
|
||||
diaryFormatSetting: "Diary naming format",
|
||||
diaryFormatDesc: "The naming format of diary files, e.g., YYYY-MM-DD",
|
||||
|
|
@ -137,6 +141,8 @@ const zh: LanguageStrings = {
|
|||
h2Option: "二级标题 (##)",
|
||||
includeSubheadingsSetting: "包含子级标题",
|
||||
includeSubheadingsDesc: "在日历事件描述中包含标题下的子级标题",
|
||||
extractTimeRangeSetting: "自动提取时间段",
|
||||
extractTimeRangeDesc: "自动从标题中提取HH:mm或HH:mm~HH:mm格式的时间作为事件的开始和结束时间",
|
||||
diarySettingsTitle: "日记设置",
|
||||
diaryFormatSetting: "日记命名格式",
|
||||
diaryFormatDesc: "日记文件的命名格式,例如YYYY-MM-DD",
|
||||
|
|
|
|||
116
src/main.ts
116
src/main.ts
|
|
@ -15,6 +15,8 @@ interface DiaryIcsSettings {
|
|||
// 日记设置
|
||||
diaryFormat: string;
|
||||
diaryFolder: string;
|
||||
// 时间提取设置
|
||||
extractTimeRange: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_DAILY_NOTE_FORMAT = 'YYYY-MM-DD';
|
||||
|
|
@ -28,7 +30,8 @@ const DEFAULT_SETTINGS: DiaryIcsSettings = {
|
|||
frontmatterTemplate: '',
|
||||
frontmatterTitleTemplate: '',
|
||||
diaryFormat: DEFAULT_DAILY_NOTE_FORMAT,
|
||||
diaryFolder: ''
|
||||
diaryFolder: '',
|
||||
extractTimeRange: true
|
||||
}
|
||||
|
||||
export default class DiaryIcsPlugin extends Plugin {
|
||||
|
|
@ -173,8 +176,6 @@ export default class DiaryIcsPlugin extends Plugin {
|
|||
if (this.dailyNoteFolder && !file.path.startsWith(matchFolder)) return false;
|
||||
|
||||
// 使用moment库验证文件名是否符合日期格式
|
||||
// @ts-ignore - window.moment 在Obsidian中已经内置
|
||||
// const moment = window.moment;
|
||||
if (!moment) {
|
||||
console.error(this.locale.cannotGetMoment);
|
||||
return false;
|
||||
|
|
@ -259,8 +260,6 @@ export default class DiaryIcsPlugin extends Plugin {
|
|||
new Notice(formatString(this.locale.generatingIcsFiles, files.length), 1000);
|
||||
for (const file of files) {
|
||||
// 从文件名解析日期,使用moment库根据配置的日记格式解析
|
||||
// @ts-ignore - window.moment 在Obsidian中已经内置
|
||||
// const moment = window.moment;
|
||||
const date = moment(file.basename, this.dailyNoteFormat, true);
|
||||
const year = date.year();
|
||||
const month = date.month() + 1; // moment月份从0开始,需要+1
|
||||
|
|
@ -363,13 +362,50 @@ export default class DiaryIcsPlugin extends Plugin {
|
|||
// description += entry.content + '\n\n';
|
||||
// }
|
||||
|
||||
// 处理时间提取
|
||||
let eventTitle = entry.title;
|
||||
// 使用联合类型解决类型问题
|
||||
let eventStart: [number, number, number] | [number, number, number, number, number] = [year, month, day];
|
||||
// 修改duration类型以支持hours和minutes
|
||||
let eventDuration: { days?: number; hours?: number; minutes?: number } = {days: 1}; // 默认为全天事件
|
||||
|
||||
if (this.settings.extractTimeRange) {
|
||||
const timeResult = this.extractTimeFromTitle(entry.title);
|
||||
eventTitle = timeResult.cleanTitle;
|
||||
|
||||
if (timeResult.hasTime && timeResult.startTime) {
|
||||
// 有时间信息,设置为非全天事件
|
||||
eventStart = [year, month, day, timeResult.startTime[0], timeResult.startTime[1]];
|
||||
|
||||
if (timeResult.endTime) {
|
||||
// 计算持续时间
|
||||
const startMinutes = timeResult.startTime[0] * 60 + timeResult.startTime[1];
|
||||
let endMinutes = timeResult.endTime[0] * 60 + timeResult.endTime[1];
|
||||
|
||||
// 如果结束时间小于开始时间,认为是跨天了
|
||||
if (endMinutes < startMinutes) {
|
||||
endMinutes += 24 * 60;
|
||||
}
|
||||
|
||||
const durationMinutes = endMinutes - startMinutes;
|
||||
// 计算小时和分钟
|
||||
const durationHours = Math.floor(durationMinutes / 60);
|
||||
const durationMins = durationMinutes % 60;
|
||||
// 设置正确的duration属性
|
||||
eventDuration = {};
|
||||
if (durationHours > 0) eventDuration.hours = durationHours;
|
||||
if (durationMins > 0) eventDuration.minutes = durationMins;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建事件
|
||||
events.push({
|
||||
title: entry.title,
|
||||
title: eventTitle,
|
||||
url: `obsidian://open?vault=${encodeURIComponent(vaultName)}&file=${encodeURIComponent(file.path)}${encodeURIComponent(`#${entry.title}`)}`,
|
||||
description: description,
|
||||
start: [year, month, day],
|
||||
duration: {days: 1}, // 默认为全天事件
|
||||
start: eventStart,
|
||||
duration: eventDuration,
|
||||
status: 'CONFIRMED',
|
||||
busyStatus: 'FREE'
|
||||
});
|
||||
|
|
@ -387,6 +423,60 @@ export default class DiaryIcsPlugin extends Plugin {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 从标题中提取时间范围
|
||||
extractTimeFromTitle(title: string): { hasTime: boolean; startTime?: [number, number]; endTime?: [number, number]; cleanTitle: string } {
|
||||
// 匹配格式:HH:mm~HH:mm 或 09:00~10:00
|
||||
const timeRangeRegex = /(?<!\d)(\d{1,2}):(\d{2})\s*[~~\-]\s*(\d{1,2}):(\d{2})(?!\d)/;
|
||||
// 匹配单个时间:HH:mm 或 09:00
|
||||
const singleTimeRegex = /(?<!\d)(\d{1,2}):(\d{2})(?!\d)/;
|
||||
|
||||
// 首先尝试匹配时间范围
|
||||
const rangeMatch = title.match(timeRangeRegex);
|
||||
if (rangeMatch) {
|
||||
|
||||
const startHour = parseInt(rangeMatch[1], 10);
|
||||
const startMinute = parseInt(rangeMatch[2], 10);
|
||||
const endHour = parseInt(rangeMatch[3], 10);
|
||||
const endMinute = parseInt(rangeMatch[4], 10);
|
||||
|
||||
|
||||
// 清理标题中的时间部分
|
||||
const cleanTitle = title.replace(timeRangeRegex, '').trim();
|
||||
|
||||
return {
|
||||
hasTime: true,
|
||||
startTime: [startHour, startMinute],
|
||||
endTime: [endHour, endMinute],
|
||||
cleanTitle
|
||||
};
|
||||
}
|
||||
|
||||
// 然后尝试匹配单个时间
|
||||
const singleMatch = title.match(singleTimeRegex);
|
||||
if (singleMatch) {
|
||||
|
||||
const hour = parseInt(singleMatch[1], 10);
|
||||
const minute = parseInt(singleMatch[2], 10);
|
||||
|
||||
// 清理标题中的时间部分
|
||||
const cleanTitle = title.replace(singleTimeRegex, '').trim();
|
||||
|
||||
return {
|
||||
hasTime: true,
|
||||
startTime: [hour, minute],
|
||||
// 单个时间默认1小时后结束
|
||||
endTime: [(hour + 1) % 24, minute],
|
||||
cleanTitle
|
||||
};
|
||||
}
|
||||
|
||||
// 没有找到时间
|
||||
return {
|
||||
hasTime: false,
|
||||
cleanTitle: title
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class DiaryIcsSettingTab extends PluginSettingTab {
|
||||
|
|
@ -447,6 +537,16 @@ class DiaryIcsSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings(false);
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(locale.extractTimeRangeSetting)
|
||||
.setDesc(locale.extractTimeRangeDesc)
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.extractTimeRange)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.extractTimeRange = value;
|
||||
await this.plugin.saveSettings(false);
|
||||
}));
|
||||
|
||||
// new Setting(containerEl)
|
||||
// .setName('包含内容')
|
||||
// .setDesc('在日历事件描述中包含标题下的内容')
|
||||
|
|
|
|||
Loading…
Reference in a new issue