Skip to content

Commit

Permalink
feat: copy universal pod.link for episode to clipboard
Browse files Browse the repository at this point in the history
looks up episode on itunes to get collection ID for podcast, then looks up podcast on pod.link to
get episodes, and finally copies episode url to clipboard

closes #36
  • Loading branch information
chhoumann committed Feb 9, 2023
1 parent 7d1b73d commit 89e18bb
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 7 deletions.
5 changes: 3 additions & 2 deletions src/iTunesAPIConsumer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ export async function queryiTunesPodcasts(query: string): Promise<PodcastFeed[]>
const res = await requestUrl({ url: url.href });
const data = res.json.results;

return data.map((d: { collectionName: string, feedUrl: string, artworkUrl100: string }) => ({
return data.map((d: { collectionName: string, feedUrl: string, artworkUrl100: string, collectionId: string }) => ({
title: d.collectionName,
url: d.feedUrl,
artworkUrl: d.artworkUrl100
artworkUrl: d.artworkUrl100,
collectionId: d.collectionId
}));
}
87 changes: 82 additions & 5 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ import {
savedFeeds,
viewState,
} from "src/store";
import { Notice, Plugin, TAbstractFile, WorkspaceLeaf } from "obsidian";
import {
Notice,
Plugin,
requestUrl,
TAbstractFile,
WorkspaceLeaf,
} from "obsidian";
import { API } from "src/API/API";
import { IAPI } from "src/API/IAPI";
import { DEFAULT_SETTINGS, VIEW_TYPE } from "src/constants";
Expand Down Expand Up @@ -42,6 +48,7 @@ import { createMediaUrlObjectFromFilePath } from "./utility/createMediaUrlObject
import { LocalFilesController } from "./store_controllers/LocalFilesController";
import PartialAppExtension from "./global";
import { LocalEpisode } from "./types/LocalEpisode";
import { queryiTunesPodcasts } from "./iTunesAPIConsumer";

export default class PodNotes extends Plugin implements IPodNotes {
public api: IAPI;
Expand Down Expand Up @@ -121,8 +128,8 @@ export default class PodNotes extends Plugin implements IPodNotes {
app.workspace.getRightLeaf(false).setViewState({
type: VIEW_TYPE,
});
}
})
},
});

this.addCommand({
id: "start-playing",
Expand Down Expand Up @@ -236,6 +243,76 @@ export default class PodNotes extends Plugin implements IPodNotes {
},
});

this.addCommand({
id: "get-share-link-episode",
name: "Copy universal episode link to clipboard",
checkCallback: (checking) => {
if (checking) {
return !!this.api.podcast;
}

const api = this.api;
const { title, itunesTitle, podcastName, feedUrl } = api.podcast;

(async function () {
try {
const iTunesResponse = await queryiTunesPodcasts(
api.podcast.podcastName
);
const podcast = iTunesResponse.find(
(pod) =>
pod.title === podcastName && pod.url === feedUrl
);

if (!podcast || !podcast.collectionId) {
throw new Error(
"Failed to get podcast from iTunes."
);
}

const podLinkUrl = `https://pod.link/${podcast.collectionId}.json?limit=1000`;
const res = await requestUrl({
url: podLinkUrl,
});

if (res.status !== 200) {
throw new Error(
`Failed to get response from pod.link: ${podLinkUrl}`
);
}

const targetTitle = itunesTitle ?? title;

const ep = res.json.episodes.find(
(episode: {
episodeId: string;
title: string;
[key: string]: string;
}) => episode.title === targetTitle
);
if (!ep) {
throw new Error(
`Failed to find episode "${targetTitle}" on pod.link. URL: ${podLinkUrl}`
);
}

window.navigator.clipboard.writeText(
`https://pod.link/${podcast.collectionId}/episode/${ep.episodeId}`
);

new Notice(
"Universal episode link copied to clipboard."
);
} catch (error) {
new Notice("Could not get podcast link.");
console.error(error);

return;
}
})();
},
});

this.addSettingTab(new PodNotesSettingsTab(this.app, this));

this.registerView(VIEW_TYPE, (leaf: WorkspaceLeaf) => {
Expand Down Expand Up @@ -268,14 +345,14 @@ export default class PodNotes extends Plugin implements IPodNotes {
}

const localFile = app.vault.getAbstractFileByPath(url);

let episode: Episode | undefined;

if (localFile) {
episode = localFiles.getLocalEpisode(decodedName);
} else {
const feedparser = new FeedParser();

episode = await feedparser.findItemByTitle(
decodedName,
url
Expand Down
3 changes: 3 additions & 0 deletions src/parser/feedParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export default class FeedParser {
const contentEl = item.querySelector("*|encoded");
const pubDateEl = item.querySelector("pubDate");
const itunesImageEl = item.querySelector("image");
const itunesTitleEl = item.getElementsByTagName('itunes:title')[0];

if (!titleEl || !streamUrlEl || !pubDateEl) {
return null;
Expand All @@ -109,6 +110,7 @@ export default class FeedParser {
const pubDate = new Date(pubDateEl.textContent as string);
const artworkUrl =
itunesImageEl?.getAttribute("href") || this.feed?.artworkUrl;
const itunesTitle = itunesTitleEl?.textContent;

return {
title,
Expand All @@ -120,6 +122,7 @@ export default class FeedParser {
artworkUrl,
episodeDate: pubDate,
feedUrl: this.feed?.url || "",
itunesTitle: itunesTitle || ""
};
}

Expand Down
1 change: 1 addition & 0 deletions src/types/Episode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export interface Episode {
feedUrl?: string,
artworkUrl?: string;
episodeDate?: Date;
itunesTitle?: string;
}
1 change: 1 addition & 0 deletions src/types/PodcastFeed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export interface PodcastFeed {
title: string;
url: string;
artworkUrl: string;
collectionId?: string;
}

0 comments on commit 89e18bb

Please sign in to comment.