Skip to content

Commit

Permalink
add subtitle path to timestamp link
Browse files Browse the repository at this point in the history
  • Loading branch information
zuluwi committed Jan 27, 2024
1 parent 1499809 commit d529816
Show file tree
Hide file tree
Showing 5 changed files with 257 additions and 41 deletions.
3 changes: 3 additions & 0 deletions src/language/locale/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export default {
"No video information available": "No video information available",
//
"Select a file to open with VLC Player": "Select a file to open with VLC Player",
"Add subtitles (if you want subtitle path in the timestamp link, you need to add them with this command)":
"Add subtitles (if you want subtitle path in the timestamp link, you need to add them with this command)",
"A video must be open to add subtitles": "A video must be open to add subtitles",
"Seek forward": "Seek forward",
"Seek backward": "Seek backward",
"Long seek forward": "Long seek forward",
Expand Down
3 changes: 3 additions & 0 deletions src/language/locale/tr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export default {
"No video information available": "Mevcut video bilgisine ulaşılamadı",
//
"Select a file to open with VLC Player": "VLC Player ile açmak için bir dosya seçin",
"Add subtitles (if you want subtitle path in the timestamp link, you need to add them with this command)":
"Altyazı ekle (zaman damgalı linkte altyazı adresinin bulunmasını istiyorsanız bu komutla eklemeniz gerekmekte)",
"A video must be open to add subtitles": "Altyazı ekleyebilmek için bir video açık olmalı",
"Seek forward": "İleri sar",
"Seek backward": "Geri sar",
"Long seek forward": "İleri uzun sar",
Expand Down
163 changes: 136 additions & 27 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
import { App, Editor, MarkdownView, Modal, Notice, ObsidianProtocolData, Plugin, PluginSettingTab, RequestUrlResponse, RequestUrlResponsePromise, Setting } from "obsidian";
import { DEFAULT_SETTINGS, VBPluginSettingsTab, VBPluginSettings } from "./settings";
import { passPlugin, currentConfig } from "./vlcHelper";
import { passPlugin, currentConfig, currentMedia, vlcStatusResponse } from "./vlcHelper";
import { t } from "./language/helpers";

// Remember to rename these classes and interfaces!
declare global {
interface File {
readonly path: string;
}
}

export default class VLCBridgePlugin extends Plugin {
settings: VBPluginSettings;
openVideo: (filePath: string, time?: number) => void;
openVideo: ({ filePath, subPath, subDelay, time }: { filePath: string; subPath?: string; subDelay?: number; time?: number }) => void;
addSubtitle: (filePath: string, subDelay?: number) => void;
sendVlcRequest: (command: string) => Promise<RequestUrlResponse | undefined>;
getStatus: () => Promise<RequestUrlResponse>;
getCurrentVideo: () => Promise<string | null>;
vlcExecOptions: () => string[];

async onload() {
await this.loadSettings();
var { getStatus, getCurrentVideo, checkPort, sendVlcRequest, openVideo, launchVLC, vlcExecOptions } = passPlugin(this);
var { getStatus, getCurrentVideo, checkPort, sendVlcRequest, openVideo, launchVLC, vlcExecOptions, addSubtitle } = passPlugin(this);
this.openVideo = openVideo;
this.addSubtitle = addSubtitle;
this.sendVlcRequest = sendVlcRequest;
this.getStatus = getStatus;
this.getCurrentVideo = getCurrentVideo;
Expand All @@ -27,13 +34,23 @@ export default class VLCBridgePlugin extends Plugin {
});

this.registerObsidianProtocolHandler("vlcBridge", (params: ObsidianProtocolData) => {
var { mediaPath, timestamp } = params;
var { mediaPath, subPath, subDelay, timestamp } = params;
if (!mediaPath) {
return new Notice(t("The link does not have a 'mediaPath' parameter to play"));
}
mediaPath = decodeURIComponent(mediaPath);
var time = Number(timestamp);
this.openVideo(mediaPath, time);
var openParams: { filePath: string; subPath?: string; subDelay?: number; time?: number } = { filePath: mediaPath };
if (timestamp) {
openParams.time = Number(timestamp);
}
if (subPath) {
openParams.subPath = decodeURIComponent(subPath);
}
if (subDelay) {
openParams.subDelay = Number(subDelay);
}

this.openVideo(openParams);
});

this.addCommand({
Expand All @@ -43,29 +60,36 @@ export default class VLCBridgePlugin extends Plugin {
if (this.settings.pauseOnPasteLink) {
this.sendVlcRequest("pl_forcepause");
}
var currentStats = await this.getStatus();
if (!currentStats) {
try {
var status = await this.getStatus();
} catch (error) {
// if (!currentStatusResponse) {
console.log(error);
return new Notice(t("VLC Player must be open to use this command"));
// }
}
var currentFile = await this.getCurrentVideo();
if (!currentFile) {
return new Notice(t("No video information available"));
}
var currentTime = currentStats.json.time;
var timestamp = this.secondsToTimestamp(currentTime);
editor.replaceSelection(`[${timestamp}](obsidian://vlcBridge?mediaPath=${encodeURIComponent(currentFile)}&timestamp=${currentTime}) `);
editor.replaceSelection(`${await this.getTimestampLink(status)} `);
},
});

this.addCommand({
id: "open-video-with-vlc",
icon: "lucide-video",
name: t("Select a file to open with VLC Player"),
callback: async () => {
this.fileOpen();
},
});

// This adds an editor command that can perform some operation on the current editor instance
this.addCommand({
id: "add-subtitle",
icon: "lucide-subtitles",
name: t("Add subtitles (if you want subtitle path in the timestamp link, you need to add them with this command)"),
callback: async () => {
this.subtitleOpen();
},
});

this.addCommand({
id: "vlc-normal-seek-forward",
name: t("Seek forward"),
Expand Down Expand Up @@ -120,7 +144,13 @@ export default class VLCBridgePlugin extends Plugin {
if (currentConfig.snapshotFolder && currentConfig.snapshotFolder !== this.settings.snapshotFolder) {
new Notice(t("You must restart VLC for the snapshots to be saved in the folder you set."));
}
if ((await this.getStatus()).json.state == "stopped") {
try {
var status = await this.getStatus();
} catch (error) {
console.log(error);
return new Notice(t("VLC Player must be open to use this command"));
}
if (status.json.state == "stopped") {
return new Notice(t("No video is currently playing"));
}
if (this.settings.pauseOnPasteSnapshot) {
Expand All @@ -142,13 +172,7 @@ export default class VLCBridgePlugin extends Plugin {
.filter((f) => f.path.startsWith(`${currentConfig.snapshotFolder || this.settings.snapshotFolder}/`) && f.stat.mtime > beforeReq && f.stat.mtime < afterReq)
?.first();
if (snapshot) {
editor.replaceSelection(
`${
currentFile
? `[${this.secondsToTimestamp(response.json.time)}](obsidian://vlcBridge?mediaPath=${encodeURIComponent(currentFile)}&timestamp=${response.json.time})`
: `${this.secondsToTimestamp(response.json.time)}`
} ![](${snapshot.path})\n`
);
editor.replaceSelection(`${currentFile ? `${await this.getTimestampLink(response)}` : `${this.secondsToTimestamp(response.json.time)}`} ![](${snapshot.path})\n`);
} else {
new Notice(t("Snapshot not found, if you made a change to the snapshot folder name, try restarting VLC."));
}
Expand All @@ -170,6 +194,40 @@ export default class VLCBridgePlugin extends Plugin {
secondsToTimestamp(seconds: number) {
return new Date(seconds * 1000).toISOString().slice(seconds < 3600 ? 14 : 11, 19);
}

getTimestampLink = async (response: RequestUrlResponse) => {
return new Promise<string>(async (resolve, reject) => {
var currentStats: vlcStatusResponse = response?.json;
if (!currentStats) {
reject();
return new Notice(t("VLC Player must be open to use this command"));
}
var currentFile = await this.getCurrentVideo();
if (!currentFile) {
return new Notice(t("No video information available"));
}
var currentTime: number = currentStats.time;
var timestamp = this.secondsToTimestamp(currentTime);
var params: {
mediaPath: string;
timestamp: string;
subPath?: string;
subDelay?: string;
} = {
mediaPath: encodeURIComponent(currentFile),
timestamp: currentTime.toString(),
};

if (currentMedia.subtitlePath && currentMedia.mediaPath == currentFile) {
params.subPath = encodeURIComponent(currentMedia.subtitlePath);
}
if (typeof currentStats.subtitledelay == "number" && currentStats.subtitledelay !== 0) {
params.subDelay = currentStats.subtitledelay.toString();
}
var paramStr = new URLSearchParams(params).toString();
resolve(`[${timestamp}](obsidian://vlcBridge?${paramStr})`);
});
};
async fileOpen() {
if (!this.settings.vlcPath) {
return new Notice(t("Before you can use the plugin, you need to select 'vlc.exe' in the plugin settings"));
Expand All @@ -182,10 +240,61 @@ export default class VLCBridgePlugin extends Plugin {
var files = (e.target as HTMLInputElement)?.files as FileList;
for (let i = 0; i < files.length; i++) {
var file = files[i];
// @ts-ignore

var fileURI = new URL(file.path).href;
// console.log(fileURI);
this.openVideo(fileURI);
this.openVideo({ filePath: fileURI });

input.remove();
}
};

input.click();
}
async subtitleOpen() {
if (!this.settings.vlcPath) {
return new Notice(t("Before you can use the plugin, you need to select 'vlc.exe' in the plugin settings"));
}
var mevcutVideo = await this.getCurrentVideo();
if (!mevcutVideo) {
return new Notice(t("A video must be open to add subtitles"));
}
const input = document.createElement("input");
input.setAttribute("type", "file");
// https://wiki.videolan.org/subtitles#Subtitles_support_in_VLC
let supportedSubtitleFormats = [
".aqt",
".usf",
".txt",
".svcd",
".sub",
".idx",
".sub",
".sub",
".sub",
".ssa",
".ass",
".srt",
".smi",
".rt",
".pjs",
".mpl",
".jss",
".dks",
".cvd",
".aqt",
".ttxt",
".ssf",
".psb",
];
input.accept = supportedSubtitleFormats.join(",");
input.onchange = (e: Event) => {
var files = (e.target as HTMLInputElement)?.files as FileList;
for (let i = 0; i < files.length; i++) {
var file = files[i];
// var fileURI = new URL(file.path).href;
// console.log(file, file.path, fileURI);
this.addSubtitle(file.path);

input.remove();
}
Expand Down
4 changes: 2 additions & 2 deletions src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ export class VBPluginSettingsTab extends PluginSettingTab {
copyArgEl.setDesc(`${this.plugin.vlcExecOptions().join(" ").replace(/["]/g, "")}`);

if (/\s/.test(this.plugin.app.vault.adapter.getFullRealPath(this.plugin.settings.snapshotFolder))) {
console.log("boşluk var");

MarkdownRenderer.render(
this.app,
Expand Down Expand Up @@ -269,7 +268,8 @@ export class VBPluginSettingsTab extends PluginSettingTab {
);
copyArgEl = new Setting(containerEl).setName(t("Copy arguments for starting VLC (for Syncplay)")).addButton((btn) =>
btn.setButtonText(t("Copy to clipboard")).onClick(async () => {
await navigator.clipboard.writeText(`${this.plugin.vlcExecOptions().join(" ").trim().replace(/["]/g, "")}`);
// await navigator.clipboard.writeText(`${this.plugin.vlcExecOptions().join(" ").trim().replace(/["]/g, "")}`);
await navigator.clipboard.writeText(`${this.plugin.vlcExecOptions().join(" ").trim()}`);
new Notice(t("Copied to clipboard"));
})
);
Expand Down
Loading

0 comments on commit d529816

Please sign in to comment.