generated from obsidianmd/obsidian-sample-plugin
-
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
See README changes for a description of the new functionality. The implementation is at the "get it working stage", not at the "get it right" stage. I'm also not a Typescript developer and have definitely committed some code violations. But it's powerful functionality and I'd like to get it out there early. Known issues: - If settings like "noteLocation" or "pollFilename" are empty, strange things will happen. Defaults are not enforced. - An error like "images failed to download" sometimes appears. But images seem to be downloading. More investigation necessary. - There is very little feedback on progress to the user. This is challenging to do well. - The process cannot be interrupted (or monitored, easily), so mistakes can result in a lot of downloaded tweets! - Every Tweet duplicates a lot of front matter. On reflection, this is still better than any alternative I could think of. - Speaking of, the "fetch new tweets" functionality relies on frontmatter being present and will quietly download all tweets again if it is not there. - There is now a lot of code repetition. This is so my additions are well contained, rather than modifying too much existing code at this stage. - Testing, and tests, are basically non-existent at this stage.
- Loading branch information
Showing
7 changed files
with
474 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
import {App, Notice, TFile, parseFrontMatterEntry} from 'obsidian' | ||
import TTM from 'main' | ||
import {createDownloadManager, DownloadManager} from './downloadManager' | ||
import {buildMarkdown, getBearerToken, getUser, getTimeline} from './util' | ||
import {createFilename, doesFileExist, sanitizeFilename} from './util' | ||
import type {Tweet, User} from './types/tweet' | ||
import { TweetCompleteActions } from './types/plugin' | ||
|
||
|
||
export const createPollManager = (app: App, plugin: TTM): PollManager => { | ||
const pollRun = (): void => { | ||
if (!navigator.onLine) { | ||
new Notice('Polling for new tweets skipped because you appear to be offline.') | ||
return | ||
} | ||
|
||
const bearerToken = getBearerToken(plugin) | ||
if (!bearerToken) { | ||
new Notice('Polling for new tweets skipped because bearer token was not found.') | ||
return | ||
} | ||
|
||
const handles:string[] = plugin.settings.pollHandles.replace(/\s|@/g, '').split(",") | ||
var downloadManager = createDownloadManager() | ||
plugin.bearerToken = bearerToken | ||
|
||
handles.forEach(async handle => { | ||
|
||
let user | ||
try { | ||
//Note the term for a "handle" in the Twitter API is "username" | ||
user = await getUser(handle, bearerToken); | ||
} catch (error) { | ||
new Notice(error.message) | ||
return | ||
} | ||
|
||
//Hella hacky way to make use of the existing createFilename interface | ||
const dummyTweet:Tweet = { | ||
includes: {users: [user]}, | ||
data: {id: "", text: "", created_at: "", author_id: "", | ||
public_metrics: {retweet_count: 0, reply_count: 0, like_count: 0, quote_count: 0}} | ||
} | ||
|
||
let fname = createFilename( | ||
dummyTweet, | ||
plugin.settings.pollFilename, | ||
{ locale: plugin.settings.dateLocale, format: plugin.settings.dateFormat }) | ||
|
||
const fpath = createFilename( | ||
dummyTweet, | ||
plugin.settings.noteLocation ? plugin.settings.noteLocation : "./", //fix broken location default | ||
{ locale: plugin.settings.dateLocale, format: plugin.settings.dateFormat }, | ||
'directory') | ||
|
||
if (!fname || !fpath) { | ||
new Notice('Failed to create filepath for timeline.') | ||
return | ||
} | ||
|
||
if (! await app.vault.adapter.exists(fpath)) { | ||
await app.vault.createFolder(fpath).catch(error => { | ||
new Notice('Error creating tweet directory.') | ||
console.error( | ||
'There was an error creating the tweet directory.', | ||
error | ||
) | ||
return | ||
}) | ||
} | ||
|
||
//Seems getAbstractFileByPath doesn't handle "./" path. Strip it out if necessary here. | ||
let abstractFile = app.vault.getAbstractFileByPath(fpath == "./" ? fname : `${fpath}/${fname}`) | ||
let file: TFile | ||
let since: Date | ||
if(abstractFile && abstractFile instanceof TFile) { | ||
file = abstractFile | ||
if(file) | ||
{ | ||
let metadata = app.metadataCache.getFileCache(file) | ||
//If the parse fails, date will be the unix epoch, which is as good as undefined. | ||
since = new Date(parseFrontMatterEntry(metadata.frontmatter, "fetched")) | ||
} | ||
} | ||
|
||
let tweets: Tweet[] | ||
new Notice(`Polling for new Tweets from ${handle}...`) | ||
|
||
try { | ||
tweets = await getTimeline(user.id, since, bearerToken) | ||
} catch (error) { | ||
new Notice(error.message) | ||
return | ||
} | ||
|
||
plugin.tweetMarkdown = '' | ||
|
||
const markdowns = await Promise.all( | ||
tweets.map(async tweet => { | ||
let markdown | ||
try { | ||
markdown = await buildMarkdown(app, plugin, downloadManager, tweet, 'normal', null) | ||
} catch (error) { | ||
new Notice('There was a problem processing the downloaded tweet') | ||
console.error(error) | ||
} | ||
return markdown | ||
}) | ||
) | ||
|
||
if(markdowns && markdowns.length > 0) { | ||
plugin.tweetMarkdown = markdowns.join('\n\n---\n\n') | ||
|
||
await downloadManager | ||
.finishDownloads() | ||
.catch(error => { | ||
new Notice('There was an error downloading the images.') | ||
console.error(error) | ||
}) | ||
|
||
// clean up excessive newlines | ||
plugin.tweetMarkdown = plugin.tweetMarkdown.replace(/\n{2,}/g, '\n\n') | ||
|
||
// write the note to file | ||
if(file) | ||
{ | ||
var t = await app.vault.read(file) | ||
app.vault.modify(file, [plugin.tweetMarkdown, t].join('\n\n---\n\n')) | ||
new Notice(`${fname} updated.`) | ||
} | ||
else | ||
{ | ||
const newFile = await app.vault.create(`${fpath}/${fname}`, plugin.tweetMarkdown) | ||
new Notice(`${fname} created.`) | ||
} | ||
} | ||
}) | ||
|
||
// clean up | ||
plugin.tweetMarkdown = '' | ||
} | ||
|
||
return { | ||
pollRun, | ||
} as PollManager | ||
} | ||
|
||
export interface PollManager { | ||
pollRun: () => void | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.