Skip to content

Commit

Permalink
refactor(app): logic of leaf detection
Browse files Browse the repository at this point in the history
  • Loading branch information
aidenlx committed Jan 13, 2024
1 parent 9e984ad commit ee651d2
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 72 deletions.
43 changes: 15 additions & 28 deletions apps/app/src/lib/link-click/external.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
import type { Workspace, WorkspaceLeaf } from "obsidian";
import {
MEDIA_EMBED_VIEW_TYPE,
type MediaEmbedViewState,
import type { WorkspaceLeaf } from "obsidian";
import { MEDIA_EMBED_VIEW_TYPE } from "@/media-view/iframe-view";
import type {
MediaEmbedViewType,
MediaEmbedViewState,
} from "@/media-view/iframe-view";
import type { MediaUrlViewType } from "@/media-view/url-view";
import { MEDIA_URL_VIEW_TYPE } from "@/media-view/url-view";
import {
MEDIA_WEBPAGE_VIEW_TYPE,
type MediaWebpageViewState,
import { MEDIA_WEBPAGE_VIEW_TYPE } from "@/media-view/webpage-view";
import type {
MediaWebpageViewType,
MediaWebpageViewState,
} from "@/media-view/webpage-view";
import type MxPlugin from "@/mx-main";
import { matchHostForEmbed } from "@/web/match-embed";
import { matchHostForUrl } from "@/web/match-url";
import { matchHostForWeb, SupportedWebHost } from "@/web/match-webpage";
import { noHash } from "../url";
import { openInOpenedPlayer } from "./opened";

interface UrlInfo {
viewType: string;
export interface UrlMediaInfo {
viewType: MediaUrlViewType | MediaEmbedViewType | MediaWebpageViewType;
source: URL;
original: string;
hash: string;
isSameSource: (src: string) => boolean;
}
export function parseUrl(url: string): UrlInfo | null {
export function parseUrl(url: string): UrlMediaInfo | null {
const directlinkInfo = matchHostForUrl(url);

if (directlinkInfo) {
Expand Down Expand Up @@ -75,23 +79,6 @@ export function parseUrl(url: string): UrlInfo | null {
return null;
}

export function openInOpenedPlayer(
{ hash, isSameSource, viewType }: UrlInfo,
workspace: Workspace,
) {
const opened = workspace.getLeavesOfType(viewType).filter((l) => {
const { source } = l.view.getState() as
| MediaEmbedViewState
| MediaWebpageViewState;
return source && isSameSource(source);
});
if (opened.length > 0) {
opened[0].setEphemeralState({ subpath: hash });
return true;
}
return false;
}

export async function onExternalLinkClick(
this: MxPlugin,
url: string,
Expand All @@ -115,7 +102,7 @@ export async function onExternalLinkClick(
await openInLeaf(urlInfo, leaf);
}

export async function openInLeaf(info: UrlInfo, leaf: WorkspaceLeaf) {
export async function openInLeaf(info: UrlMediaInfo, leaf: WorkspaceLeaf) {
const state: MediaEmbedViewState | MediaWebpageViewState = {
source: info.original,
};
Expand Down
47 changes: 26 additions & 21 deletions apps/app/src/lib/link-click/internal.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
import type { TFile, Workspace } from "obsidian";
import type { TFile } from "obsidian";
import { parseLinktext } from "obsidian";
import { MEDIA_FILE_VIEW_TYPE } from "@/media-view/file-view";
import {
MEDIA_FILE_VIEW_TYPE,
isMediaFileViewType,
type MediaFileViewType,
} from "@/media-view/file-view";
import type MxPlugin from "@/mx-main";
import type { MediaType } from "@/patch/utils";
import { checkMediaType } from "@/patch/utils";
import { openInOpenedPlayer } from "./opened";

export interface FileMediaInfo {
viewType: MediaFileViewType;
file: TFile;
hash: string;
}

export function isFileMediaInfo(info: unknown): info is FileMediaInfo {
return isMediaFileViewType((info as FileMediaInfo).viewType);
}

export function onInternalLinkClick(
this: MxPlugin,
linktext: string,
Expand All @@ -21,26 +36,16 @@ export function onInternalLinkClick(
}
if (
!newLeaf &&
openInOpenedPlayer({ file: linkFile, subpath, mediaType }, workspace)
openInOpenedPlayer(
{
file: linkFile,
hash: subpath,
viewType: MEDIA_FILE_VIEW_TYPE[mediaType],
},
workspace,
)
) {
return;
}
fallback();
}

export function openInOpenedPlayer(
linkInfo: { file: TFile; subpath: string; mediaType: MediaType },
workspace: Workspace,
) {
const opened = workspace
.getLeavesOfType(MEDIA_FILE_VIEW_TYPE[linkInfo.mediaType])
.filter((l) => {
const { file: filePath } = l.view.getState() as { file: string };
return filePath === linkInfo.file.path;
});
if (opened.length > 0) {
opened[0].setEphemeralState({ subpath: linkInfo.subpath });
return true;
}
return false;
}
48 changes: 48 additions & 0 deletions apps/app/src/lib/link-click/opened.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type { Workspace, WorkspaceLeaf } from "obsidian";
import type { MediaEmbedViewState } from "@/media-view/iframe-view";
import type { MediaUrlViewState } from "@/media-view/url-view";
import type { MediaWebpageViewState } from "@/media-view/webpage-view";
import type { UrlMediaInfo } from "./external";
import { isFileMediaInfo, type FileMediaInfo } from "./internal";

function filterFileLeaf(leaf: WorkspaceLeaf, info: FileMediaInfo) {
const { file: filePath } = leaf.view.getState() as { file: string };
return filePath === info.file.path;
}

function filterUrlLeaf(leaf: WorkspaceLeaf, info: UrlMediaInfo) {
const { source } = leaf.view.getState() as
| MediaEmbedViewState
| MediaWebpageViewState
| MediaUrlViewState;
return source && info.isSameSource(source);
}

export function getLeavesOfMedia(
info: UrlMediaInfo | FileMediaInfo,
workspace: Workspace,
) {
return workspace.getLeavesOfType(info.viewType).filter((leaf) => {
if (isFileMediaInfo(info)) {
return filterFileLeaf(leaf, info);
} else {
return filterUrlLeaf(leaf, info);
}
});
}

export function updateHash(hash: string, leaf: WorkspaceLeaf) {
leaf.setEphemeralState({ subpath: hash });
}

export function openInOpenedPlayer(
info: FileMediaInfo | UrlMediaInfo,
workspace: Workspace,
): boolean {
const opened = getLeavesOfMedia(info, workspace);
if (opened.length > 0) {
updateHash(info.hash, opened[0]);
return true;
}
return false;
}
7 changes: 2 additions & 5 deletions apps/app/src/media-note/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import type { CachedMetadata, TAbstractFile } from "obsidian";
import { Notice, TFile, parseLinktext } from "obsidian";
import { openInOpenedPlayer } from "@/lib/link-click/opened";
import type MxPlugin from "@/mx-main";
import { checkMediaType } from "@/patch/utils";
import {
openInLeaf,
openInOpenedPlayer,
parseUrl,
} from "../lib/link-click/external";
import { openInLeaf, parseUrl } from "../lib/link-click/external";
import { toURL } from "../lib/url";

export const mediaSourceField = {
Expand Down
37 changes: 22 additions & 15 deletions apps/app/src/media-view/base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,31 @@ export interface PlayerComponent extends Component {
root: ReactDOM.Root | null;
}

export function setTempFrag(hash: string, store: MediaViewStoreApi) {
export function setTempFrag(
hash: string,
store: MediaViewStoreApi,
playAfterSeek = false,
) {
store.setState({ hash });
const tf = parseTempFrag(hash);
const player = store.getState().player;
if (player && tf) {
// allow 0.25s offset from end, in case delay in seeking
const allowedOffset = 0.25;
if (
isTimestamp(tf) ||
player.currentTime < tf.start ||
Math.abs(player.currentTime - tf.end) < allowedOffset
) {
player.currentTime = tf.start;
} else if (player.currentTime - allowedOffset > tf.end) {
player.currentTime = tf.end;
}
if (isTimestamp(tf)) {
player.play(new Event("hashchange"));
if (!player || !tf) return;
// allow 0.25s offset from end, in case delay in seeking
const allowedOffset = 0.25;
if (
isTimestamp(tf) ||
player.currentTime < tf.start ||
Math.abs(player.currentTime - tf.end) < allowedOffset
) {
player.currentTime = tf.start;
} else if (player.currentTime - allowedOffset > tf.end) {
player.currentTime = tf.end;
}

if (isTimestamp(tf)) {
const evt = new Event("hashchange");
if (playAfterSeek) {
player.play(evt);
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions apps/app/src/media-view/file-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ export const MEDIA_FILE_VIEW_TYPE = {
audio: "mx-file-audio",
} as const;

const viewTypes = new Set(Object.values(MEDIA_FILE_VIEW_TYPE));

export type MediaFileViewType =
(typeof MEDIA_FILE_VIEW_TYPE)[keyof typeof MEDIA_FILE_VIEW_TYPE];

export function isMediaFileViewType(type: string): type is MediaFileViewType {
return viewTypes.has(type as any);
}

abstract class MediaFileView
extends EditableFileView
implements PlayerComponent
Expand Down
3 changes: 2 additions & 1 deletion apps/app/src/media-view/iframe-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import type { MediaRemoteViewState } from "./base";
import { MediaRemoteView } from "./base";

// eslint-disable-next-line @typescript-eslint/naming-convention
export const MEDIA_EMBED_VIEW_TYPE = "mx-embed";
export const MEDIA_EMBED_VIEW_TYPE = "mx-embed" as const;
export type MediaEmbedViewType = typeof MEDIA_EMBED_VIEW_TYPE;

export type MediaEmbedViewState = MediaRemoteViewState;

Expand Down
4 changes: 3 additions & 1 deletion apps/app/src/media-view/url-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import type { MediaRemoteViewState, PlayerComponent } from "./base";
export const MEDIA_URL_VIEW_TYPE = {
video: "mx-url-video",
audio: "mx-url-audio",
};
} as const;
export type MediaUrlViewType =
(typeof MEDIA_URL_VIEW_TYPE)[keyof typeof MEDIA_URL_VIEW_TYPE];

export type MediaUrlViewState = MediaRemoteViewState;

Expand Down
3 changes: 2 additions & 1 deletion apps/app/src/media-view/webpage-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import type { MediaRemoteViewState } from "./base";
import { MediaRemoteView } from "./base";

// eslint-disable-next-line @typescript-eslint/naming-convention
export const MEDIA_WEBPAGE_VIEW_TYPE = "mx-webpage";
export const MEDIA_WEBPAGE_VIEW_TYPE = "mx-webpage" as const;
export type MediaWebpageViewType = typeof MEDIA_WEBPAGE_VIEW_TYPE;

export type MediaWebpageViewState = MediaRemoteViewState;

Expand Down

0 comments on commit ee651d2

Please sign in to comment.