feat: added auto time based moving, ribbon and cmd access to manual

This commit is contained in:
Al0cam 2025-04-17 18:16:09 +02:00
parent 8bd4d68467
commit 6f4cc32364
7 changed files with 148 additions and 18 deletions

View file

@ -150,10 +150,11 @@ Thank you!
- [x] Add excluded folder support
- [x] Add excluded file support
- [x] Add regex support for excluded folders and files (must support language accents like ñ, á, š, đ, こ, 猫, etc.)
- [x] Add time based execution of rule sorting
- [x] Exposing the move files button to the left toolbar
- [x] Exposing the move files to the commands accessible via command palette
- [ ] Add a file like .gitignore which contains all the moving rules (i am assuming the list can grow quite big for some people)
- [ ] Add import and export of rules
- [ ] Add time based execution of rule sorting
- [ ] Exposing the move files button to the left toolbar
- [ ] Auto tagging of moved files with the destination folder name (last folder in the path)

View file

@ -7,6 +7,8 @@ export interface AutoMoverSettings {
// moveOnSave: boolean;
movingRules: MovingRule[];
exclusionRules: ExclusionRule[];
automaticMoving: boolean;
timer: number | null; // in miliseconds
}
export const DEFAULT_SETTINGS: Partial<AutoMoverSettings> = {
@ -14,6 +16,8 @@ export const DEFAULT_SETTINGS: Partial<AutoMoverSettings> = {
// moveOnSave: true,
movingRules: [],
exclusionRules: [],
automaticMoving: false,
timer: null,
};
function loadSettings(

View file

@ -2,6 +2,7 @@ import type AutoMoverPlugin from "main";
import { ExclusionRule } from "Models/ExclusionRule";
import { MovingRule } from "Models/MovingRule";
import * as obsidian from "obsidian";
import timerUtil from "Utils/TimerUtil";
export class SettingsTab extends obsidian.PluginSettingTab {
plugin: AutoMoverPlugin;
@ -38,6 +39,44 @@ export class SettingsTab extends obsidian.PluginSettingTab {
});
});
const automaticMovingContainer = containerEl.createDiv({});
new obsidian.Setting(automaticMovingContainer)
.setName("Automatic moving")
.setDesc(
`Execute a timed event that goes through all the files and moves them according to the rules specified below.
The formatting is hh:mm:ss.
If the timer is set to 0, the automatic moving will do nothing.`,
)
.setClass("timer-setting")
.addToggle((cb) =>
cb
.setValue(this.plugin.settings.automaticMoving)
.onChange(async (value) => {
this.plugin.settings.automaticMoving = value;
await this.plugin.saveData(this.plugin.settings);
this.app.workspace.trigger(
"AutoMover:automatic-moving-update",
this.plugin.settings,
);
this.display();
}),
)
.addText((cb) =>
cb
.setDisabled(!this.plugin.settings.automaticMoving)
.setValue(timerUtil.formatTime(this.plugin.settings.timer))
.setPlaceholder("hh:mm:ss")
.onChange(async (value) => {
this.plugin.settings.timer = timerUtil.parseTimeToMs(value);
await this.plugin.saveData(this.plugin.settings);
this.app.workspace.trigger(
"AutoMover:automatic-moving-update",
this.plugin.settings,
);
}),
);
// there is no default event to move on save, therefore, i'd need to define a new one
// running move on change could be an option, but it would produce an overhead in performance because of constant checking for changes
//

View file

@ -20,12 +20,8 @@ class ExclusionMatcherUtil {
* @returns true if the file path is excluded, false otherwise
*/
isFilePathExcluded(file: TFile, exclusionRules: ExclusionRule[]): boolean {
console.log("Exclusion rules: ", exclusionRules);
for (const rule of exclusionRules) {
const regex = new RegExp(rule.regex);
console.log("Regex: ", regex);
console.log("File path: ", file.path);
console.log("Result: ", regex.test(file.path));
if (regex.test(file.path)) {
return true;
}

44
Utils/TimerUtil.ts Normal file
View file

@ -0,0 +1,44 @@
class TimerUtil {
private static instance: TimerUtil;
private timer: NodeJS.Timeout | null = null;
private constructor() {}
static getInstance(): TimerUtil {
if (!TimerUtil.instance) {
TimerUtil.instance = new TimerUtil();
}
return TimerUtil.instance;
}
formatTime(ms: number | null): string {
if (ms == null) return "00:00:00";
const totalSeconds = Math.floor(ms / 1000);
const hours = String(Math.floor(totalSeconds / 3600)).padStart(2, "0");
const minutes = String(Math.floor((totalSeconds % 3600) / 60)).padStart(
2,
"0",
);
const seconds = String(totalSeconds % 60).padStart(2, "0");
return `${hours}:${minutes}:${seconds}`;
}
parseTimeToMs(timeStr: string): number {
const [h, m, s] = timeStr.split(":").map(Number);
if ([h, m, s].some((n) => Number.isNaN(n))) return 0;
return ((h ?? 0) * 3600 + (m ?? 0) * 60 + (s ?? 0)) * 1000;
}
startTimer(callback: () => void, interval: number) {
if (this.timer) {
// console.log("Clearing existing timer");
clearInterval(this.timer);
}
// console.log("Starting timer with interval: ", interval);
this.timer = setTimeout(callback, interval);
}
}
const timerUtil = TimerUtil.getInstance();
export default timerUtil;

57
main.ts
View file

@ -4,6 +4,8 @@ import movingUtil from "Utils/MovingUtil";
import ruleMatcherUtil from "Utils/RuleMatcherUtil";
import * as obsidian from "obsidian";
import exclusionMatcherUtil from "Utils/ExclusionMatcherUtil";
import timerUtil from "Utils/TimerUtil";
import { addIcon } from "obsidian";
export default class AutoMoverPlugin extends obsidian.Plugin {
settings: Settings.AutoMoverSettings;
@ -26,15 +28,47 @@ export default class AutoMoverPlugin extends obsidian.Plugin {
if (!this.areThereRulesToApply()) return;
if (!this.areRulesValid()) return;
if (this.settings.moveOnOpen) {
this.registerEvent(
this.app.workspace.on("file-open", (file: obsidian.TFile) => {
if (file == null || file.path == null) return;
if (this.isFileExcluded(file)) return;
this.matchAndMoveFile(file);
}),
);
}
this.registerEvent(
this.app.workspace.on("file-open", (file: obsidian.TFile) => {
if (!this.settings.moveOnOpen) return;
if (file == null || file.path == null) return;
if (this.isFileExcluded(file)) return;
this.matchAndMoveFile(file);
}),
);
this.registerEvent(
// since i am defining my own event, ts-lint is crying about it but it works in the end
this.app.workspace.on("AutoMover:automatic-moving-update", () => {
// console.log("Automatic moving update");
this.automaticMoving();
}),
);
this.addCommand({
id: "AutoMover:move-files",
name: "Move files",
callback: () => {
this.goThroughAllFiles();
},
});
this.addRibbonIcon("file-input", "AutoMover: Move files", () => {
this.goThroughAllFiles();
});
}
/**
* Reocurring function that will be called by the timer
*
* @returns void
*/
automaticMoving() {
// console.log("Automatic moving run");
if (!this.settings.automaticMoving) return;
if (this.settings.timer == null || this.settings.timer <= 0) return;
this.goThroughAllFiles();
timerUtil.startTimer(this.automaticMoving.bind(this), this.settings.timer);
}
/**
@ -43,11 +77,10 @@ export default class AutoMoverPlugin extends obsidian.Plugin {
* @returns void
*/
goThroughAllFiles() {
// console.log("Going through all files");
const files = this.app.vault.getFiles();
for (const file of files) {
if (file == null || file.path == null) continue;
console.log("Going through file: ", file.path);
console.log("File excluded: ", this.isFileExcluded(file));
if (this.isFileExcluded(file)) continue;
this.matchAndMoveFile(file);
}
@ -77,7 +110,7 @@ export default class AutoMoverPlugin extends obsidian.Plugin {
* @returns void
*/
matchAndMoveFile(file: obsidian.TFile): void {
console.log("Moving file: ", file.path);
// console.log("Moving file: ", file.path);
const rule = ruleMatcherUtil.getMatchingRule(
file,
this.settings.movingRules,

View file

@ -63,3 +63,16 @@ If your plugin does not need CSS, delete this file.
.rule_button_duplicate:hover {
background-color: var(--color-blue) !important;
}
/* Style for timer-setting input field */
.setting-item.timer-setting input[type="text"] {
width: auto;
min-width: 8ch;
/* Minimum for hh:mm:ss */
max-width: 16ch;
/* Allows up to ~9999:59:59 */
/* padding: 2px 6px; */
font-family: monospace;
text-align: center;
/* box-sizing: content-box; */
}