Check if Dataview is loaded before attempting to use

This commit is contained in:
Bob 2026-05-14 08:42:16 -04:00
parent cf9bd8367b
commit 0108f6a66d
10 changed files with 54 additions and 47 deletions

View file

@ -30,9 +30,13 @@ jobs:
main.js
manifest.json
styles.css
- name: Generate Release Notes
run: |
git log -1 --pretty=%B > release-notes.md
- name: Create Release
# https://github.com/ncipollo/release-action
uses: ncipollo/release-action@v1.20.0
with:
artifacts: "main.js,manifest.json,styles.css"
bodyFile: release-notes.md
token: ${{ secrets.GITHUB_TOKEN }}

View file

@ -24,17 +24,18 @@ https://github.com/user-attachments/assets/ab89ea54-b529-49e0-aa6a-15a6ee7679ca
This plugin makes the following network requests:
| URL | Purpose | When | Initiated by |
| --- | ------- | ---- | ------------ |
| Streaming Availability API by Movie of the Night | Search movies and TV shows, fetch availability by TMDB ID, and load the supported country list | Searches, note refreshes, syncs, and settings views that need country data | The plugin calls the `streaming-availability` client, which sends the request |
| User-configured Jellyfin server URL | Search Jellyfin libraries for matching movies or series and read watched status for a configured user | Jellyfin sync commands and show syncs with Jellyfin enabled | This plugin's source code, using Obsidian `requestUrl` |
| Poster image URLs returned by the Streaming Availability API | Download poster images into the vault when local poster saving is enabled | Show syncs where the poster file is missing | This plugin's source code, using Obsidian `requestUrl` |
| `https://www.movieofthenight.com/about/api` and RapidAPI documentation/pricing pages | Open API documentation and signup pages | User clicks from settings or README links | Obsidian/browser link handling |
| Package | URL | Purpose |
| ------- | --- | ------- |
| `streaming-availability` | Streaming Availability API by Movie of the Night | Search movies and TV shows, fetch availability by TMDB ID, and load supported countries. |
| Who Is Streaming | User-configured Jellyfin server URL | Search Jellyfin libraries for matching shows and read watched status. |
| Who Is Streaming | Poster image URLs returned by the Streaming Availability API | Download poster images into the vault when local poster saving is enabled. |
## Dependencies
| Package | Description |
| ------- | ----------- |
| [streaming-availability](https://www.npmjs.com/package/streaming-availability) | Calls the Streaming Availability API by Movie of the Night |
| [he](https://github.com/mathiasbynens/he) | Decodes HTML entities in movie and show metadata |
| Package | Description |
| ------------------------------------------------------------------------------ | ------------------------------------------------------------ |
| [streaming-availability](https://www.npmjs.com/package/streaming-availability) | Calls the Streaming Availability API by Movie of the Night |
| [he](https://github.com/mathiasbynens/he) | Decodes HTML entities in movie and show metadata |
| [Dataview](https://blacksmithgu.github.io/obsidian-dataview/) | Optional. Used for bulk refresh features |

View file

@ -15,6 +15,9 @@ const context = await esbuild.context({
banner: {
js: banner,
},
alias: {
"streaming-availability": "./node_modules/streaming-availability/src/index.ts",
},
entryPoints: ["src/main.ts"],
bundle: true,
external: [

View file

@ -15,14 +15,18 @@ const obsidianRecommended = obsidianmd.configs.recommended.map((config) => {
: config;
});
const brands = [
...DEFAULT_BRANDS,
const pluginBrands = [
"Dataview",
"Jellyfin",
"Movie of the Night",
"Streaming Availability API",
];
const brands = [
...DEFAULT_BRANDS,
...pluginBrands.filter((brand) => !DEFAULT_BRANDS.includes(brand)),
];
export default tseslint.config(
{
languageOptions: {

View file

@ -1,7 +1,7 @@
{
"id": "who-is-streaming",
"name": "Who Is Streaming",
"version": "1.1.1",
"version": "1.1.2",
"minAppVersion": "1.10.0",
"description": "Discover and document which streaming services a movie is currently available to be streamed on.",
"author": "Bob Stanton",

2
package-lock.json generated
View file

@ -1,6 +1,6 @@
{
"name": "who-is-streaming",
"version": "1.1.1",
"version": "1.1.2",
"lockfileVersion": 3,
"requires": true,
"packages": {

View file

@ -1,6 +1,6 @@
{
"name": "who-is-streaming",
"version": "1.1.1",
"version": "1.1.2",
"description": "Discover and keep track of which streaming services a movie is currently available to be streamed on.",
"main": "main.js",
"scripts": {

View file

@ -49,14 +49,19 @@ export default class WhoIsStreamingPlugin extends Plugin {
this.addCommand({ id: "refresh", name: "Refresh", editorCallback: async (editor: Editor, view: MarkdownView) => {
await this.refreshActiveFile();
}});
this.addCommand({ id: "bulk-refresh", name: "Bulk refresh", callback: async () => {
const hasDataview = isDataviewPluginEnabled(this.app);
if (hasDataview) {
this.addCommand({ id: "bulk-refresh", name: "Bulk refresh", callback: async () => {
await this.refreshAllFiles();
}});
}});
}
if (this.settings.jellyfinInstances && this.settings.jellyfinInstances.length > 0) {
this.addCommand({ id: "bulk-refresh-jellyfin", name: "Bulk refresh Jellyfin", callback: async () => {
if (hasDataview) {
this.addCommand({ id: "bulk-refresh-jellyfin", name: "Bulk refresh Jellyfin", callback: async () => {
await this.syncJellyfinForAllFiles();
}});
}});
}
this.addCommand({ id: "sync-jellyfin", name: "Sync Jellyfin", editorCallback: async (editor: Editor, view: MarkdownView) => {
await this.syncJellyfinActiveFile();
}});
@ -185,27 +190,12 @@ export default class WhoIsStreamingPlugin extends Plugin {
return;
}
const findingNotice = new Notice("🔄 Finding files with TMDB ID...", 0);
const allFiles = this.app.vault.getMarkdownFiles();
const filesWithTmdbId: TFile[] = [];
for (const file of allFiles) {
const [tmdb_id] = await this.getTmdbId(file);
if (tmdb_id) {
filesWithTmdbId.push(file);
}
}
findingNotice.hide();
if (filesWithTmdbId.length === 0) {
new Notice("No files with TMDB ID found");
const files = await this.getFilesToSync();
if (files.length === 0) {
new Notice("No files to sync");
return;
}
const files = filesWithTmdbId;
await this.runBulkOperation(files, "⚠️ Bulk Jellyfin refresh cancelled by user", async (file) => {
const [tmdb_id, showType] = await this.getTmdbId(file);
if (!tmdb_id || !showType) {
@ -306,16 +296,23 @@ export default class WhoIsStreamingPlugin extends Plugin {
}
async getFilesToSync(): Promise<TFile[]> {
if (!isDataviewPluginEnabled(this.app) || this.settings.bulkSyncDataviewQuery.length === 0) {
return this.app.vault.getMarkdownFiles();
if (!isDataviewPluginEnabled(this.app)) {
new Notice("Enable Dataview to use bulk refresh.");
return [];
}
const dataview = getDataviewApi<DataviewValue>(this.app);
if (!dataview) {
return this.app.vault.getMarkdownFiles();
new Notice("Dataview is unavailable. Reload Obsidian and try again.");
return [];
}
let dataviewQuery = this.settings.bulkSyncDataviewQuery.trim();
if (dataviewQuery.length === 0) {
new Notice("Set a Dataview query before using bulk refresh.");
return [];
}
let dataviewQuery = this.settings.bulkSyncDataviewQuery;
if (!dataviewQuery.startsWith("LIST")) {
dataviewQuery = "LIST \n" + dataviewQuery;
}

View file

@ -4,7 +4,7 @@
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES6",
"target": "ES2020",
"allowJs": true,
"noImplicitAny": true,
"moduleResolution": "node",
@ -13,10 +13,7 @@
"strictNullChecks": true,
"lib": [
"DOM",
"ES5",
"ES6",
"ES7",
"ES2019"
"ES2020"
]
},
"include": [

View file

@ -1,4 +1,5 @@
{
"1.0.0": "1.8.0",
"1.1.1": "1.10.0"
"1.1.1": "1.10.0",
"1.1.2": "1.10.0"
}