Skip to content

Commit

Permalink
feat(playlist): export to m3u8
Browse files Browse the repository at this point in the history
  • Loading branch information
aidenlx committed Mar 19, 2024
1 parent f5b7cdb commit 7414cd7
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 0 deletions.
69 changes: 69 additions & 0 deletions apps/app/src/media-note/playlist/export.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { pathToFileURL } from "url";
import type { Vault } from "obsidian";
import { FileSystemAdapter, Notice } from "obsidian";

import { isFileMediaInfo } from "@/info/media-info";
import { MediaURL } from "@/info/media-url";
import { toInfoKey } from "../note-index/def";
import type { Playlist } from "./def";

export function generateM3U8File(playlist: Playlist, vault: Vault) {
// Start of the M3U8 file
let m3u8Content = "#EXTM3U\n";

// Iterate over the playlist items and add them to the file content
const skippedItems: string[] = [];
let fileNotSupported = false;
for (const item of playlist.list) {
if (item.media instanceof MediaURL) {
// Ensure there's a media URL
m3u8Content += `#EXTINF:-1,${item.title}\n${item.media.href}\n`;
} else if (isFileMediaInfo(item.media)) {
if (vault.adapter instanceof FileSystemAdapter) {
const fileFullPath = vault.adapter.getFullPath(item.media.file.path);
try {
const fileUrl = pathToFileURL(fileFullPath).href;
m3u8Content += `#EXTINF:-1,${item.title}\n${fileUrl}\n`;
} catch (e) {
new Notice(`Failed to convert file path to URL: ${e}`);
skippedItems.push(item.title || toInfoKey(item.media));
}
} else {
fileNotSupported = true;
skippedItems.push(item.title || toInfoKey(item.media));
}
}
}
if (skippedItems.length > 0) {
if (fileNotSupported) {
new Notice(
createFragment((f) => {
f.createDiv({
text: `File URI is not supported in this environment. `,
});
f.createDiv({ text: `Skipped items: ${skippedItems.join(", ")}` });
}),
);
} else {
new Notice(`Skipped items: ${skippedItems.join(", ")}`);
}
}

// Convert the file content to a Blob
saveM3U8(m3u8Content, playlist.title);
}
function saveM3U8(m3u8Content: string, title: string) {
const blob = new Blob([m3u8Content], {
type: "application/vnd.apple.mpegurl",
});

// Create a temporary anchor element to trigger the download
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = `${title}.m3u8`;

// Append the anchor to the body, click it, and then remove it
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
33 changes: 33 additions & 0 deletions apps/app/src/media-note/playlist/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { iterateFiles } from "../../lib/iterate-files";
import { toInfoKey } from "../note-index/def";
import { emptyLists } from "./def";
import type { PlaylistWithActive, Playlist } from "./def";
import { generateM3U8File } from "./export";
import { getPlaylistMeta } from "./extract";

export class PlaylistIndex extends Component {
Expand Down Expand Up @@ -135,5 +136,37 @@ export class PlaylistIndex extends Component {
waitUntilResolve(this.app.metadataCache, this).then(() => {
this.onResolve();
});
this.plugin.addCommand({
id: "playlist-export",
name: "Export current playlist to m3u8 file",
editorCheckCallback: (checking, editor, ctx) => {
if (!ctx.file || !this.listFileCache.has(ctx.file.path)) return false;
if (checking) return true;
generateM3U8File(
this.listFileCache.get(ctx.file.path)!,
this.app.vault,
);
},
});
this.registerEvent(
this.app.workspace.on(
"file-menu",
(menu, file, source) =>
source === "more-options" &&
this.listFileCache.has(file.path) &&
menu.addItem((item) =>
item
.setTitle("Export to m3u8...")
.setIcon("file-down")
.setSection("action")
.onClick(() => {
generateM3U8File(
this.listFileCache.get(file.path)!,
this.app.vault,
);
}),
),
),
);
}
}

0 comments on commit 7414cd7

Please sign in to comment.