@@ -2,7 +2,9 @@ import { Notice, TFile, requestUrl } from "obsidian";
22import { downloadedEpisodes } from "./store" ;
33import { DownloadPathTemplateEngine } from "./TemplateEngine" ;
44import type { Episode } from "./types/Episode" ;
5+ import type { LocalEpisode } from "./types/LocalEpisode" ;
56import { encodeUrlForRequest } from "./utility/encodeUrlForRequest" ;
7+ import { isLocalFile } from "./utility/isLocalFile" ;
68import getUrlExtension from "./utility/getUrlExtension" ;
79import getExtensionFromContentType from "./utility/getExtensionFromContentType" ;
810
@@ -177,6 +179,56 @@ async function createEpisodeFile({
177179 downloadedEpisodes . addEpisode ( episode , filePath , blob . size ) ;
178180}
179181
182+ function resolveLocalEpisodeFilePath ( episode : LocalEpisode ) : string | null {
183+ const downloadedEpisode = downloadedEpisodes . getEpisode ( episode ) ;
184+ const candidatePaths = [
185+ episode . filePath ,
186+ downloadedEpisode ?. filePath ,
187+ getLocalFilePathFromLink ( episode . url ) ,
188+ ] ;
189+
190+ for ( const possiblePath of candidatePaths ) {
191+ if ( ! possiblePath ) continue ;
192+
193+ const file = app . vault . getAbstractFileByPath ( possiblePath ) ;
194+ if ( file instanceof TFile ) {
195+ return file . path ;
196+ }
197+ }
198+
199+ return null ;
200+ }
201+
202+ function getLocalFilePathFromLink ( link : string ) : string | null {
203+ if ( ! link ) return null ;
204+
205+ const trimmedLink = link . trim ( ) ;
206+ if ( ! trimmedLink ) return null ;
207+
208+ const innerLink = trimmedLink . match ( / ^ \[ \[ ( .* ) \] \] $ / ) ?. [ 1 ] ?? trimmedLink ;
209+ const [ target ] = innerLink . split ( "|" ) ;
210+ const normalizedTarget = target ?. trim ( ) ;
211+
212+ if ( ! normalizedTarget ) {
213+ return null ;
214+ }
215+
216+ const directFile = app . vault . getAbstractFileByPath ( normalizedTarget ) ;
217+ if ( directFile instanceof TFile ) {
218+ return directFile . path ;
219+ }
220+
221+ const linkedFile = app . metadataCache ?. getFirstLinkpathDest (
222+ normalizedTarget ,
223+ "" ,
224+ ) ;
225+ if ( linkedFile instanceof TFile ) {
226+ return linkedFile . path ;
227+ }
228+
229+ return null ;
230+ }
231+
180232async function inferFileExtensionFromDownload (
181233 episode : Episode ,
182234 blob : Blob ,
@@ -198,6 +250,17 @@ export async function downloadEpisode(
198250 episode : Episode ,
199251 downloadPathTemplate : string ,
200252) : Promise < string > {
253+ if ( isLocalFile ( episode ) ) {
254+ const localFilePath = resolveLocalEpisodeFilePath ( episode ) ;
255+ if ( ! localFilePath ) {
256+ throw new Error (
257+ `Unable to locate the local audio file for "${ episode . title } ". Try playing the file again.` ,
258+ ) ;
259+ }
260+
261+ return localFilePath ;
262+ }
263+
201264 const basename = DownloadPathTemplateEngine ( downloadPathTemplate , episode ) ;
202265 const fileExtension = await getFileExtension ( episode . streamUrl ) ;
203266 const filePath = `${ basename } .${ fileExtension } ` ;
0 commit comments