obsidian#request TypeScript Examples

The following examples show how to use obsidian#request. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: main.ts    From obsidian-ics with MIT License 6 votes vote down vote up
async onload() {
		console.log('loading ics plugin');
		await this.loadSettings();
		this.addSettingTab(new ICSSettingsTab(this.app, this));
		this.addCommand({
			id: "import_events",
			name: "import events",
			hotkeys: [{
				modifiers: ["Alt", "Shift"],
				key: 'T',
			}, ],
			callback: async () => {
				const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
				const fileDate = getDateFromFile(activeView.file, "day").format("YYYY-MM-DD");
				var mdArray: string[] = [];

				for (const calendar in this.data.calendars) {
					const calendarSetting = this.data.calendars[calendar];
					console.log(calendarSetting);
					var icsArray: any[] = [];
					var icsArray = parseIcs(await request({
						url: calendarSetting.icsUrl
					}));
					const todayEvents = filterMatchingEvents(icsArray, fileDate);
					console.log(todayEvents);
	
					todayEvents.forEach((e) => {
						mdArray.push(`- [ ] ${moment(e.start).format("HH:mm")} ${calendarSetting.icsName} ${e.summary} ${e.location}`.trim());
					});
				}

				activeView.editor.replaceRange(mdArray.sort().join("\n"), activeView.editor.getCursor());
			}
		});
	}
Example #2
Source File: remoteForOnedrive.ts    From remotely-save with Apache License 2.0 6 votes vote down vote up
sendRefreshTokenReq = async (
  clientID: string,
  authority: string,
  refreshToken: string
) => {
  // also use Obsidian request to bypass CORS issue.
  const rsp1 = await request({
    url: `${authority}/oauth2/v2.0/token`,
    method: "POST",
    contentType: "application/x-www-form-urlencoded",
    body: new URLSearchParams({
      tenant: "consumers",
      client_id: clientID,
      scope: SCOPES.join(" "),
      refresh_token: refreshToken,
      grant_type: "refresh_token",
    }).toString(),
  });

  const rsp2 = JSON.parse(rsp1);
  // log.info(rsp2);

  if (rsp2.error !== undefined) {
    return rsp2 as AccessCodeResponseFailedType;
  } else {
    return rsp2 as AccessCodeResponseSuccessfulType;
  }
}
Example #3
Source File: remoteForOnedrive.ts    From remotely-save with Apache License 2.0 6 votes vote down vote up
patchJson = async (pathFragOrig: string, payload: any) => {
    const theUrl = this.buildUrl(pathFragOrig);
    log.debug(`patchJson, theUrl=${theUrl}`);
    return JSON.parse(
      await request({
        url: theUrl,
        method: "PATCH",
        contentType: "application/json",
        body: JSON.stringify(payload),
        headers: {
          Authorization: `Bearer ${await this.authGetter.getAccessToken()}`,
        },
      })
    );
  };
Example #4
Source File: remoteForOnedrive.ts    From remotely-save with Apache License 2.0 6 votes vote down vote up
postJson = async (pathFragOrig: string, payload: any) => {
    const theUrl = this.buildUrl(pathFragOrig);
    log.debug(`postJson, theUrl=${theUrl}`);
    return JSON.parse(
      await request({
        url: theUrl,
        method: "POST",
        contentType: "application/json",
        body: JSON.stringify(payload),
        headers: {
          Authorization: `Bearer ${await this.authGetter.getAccessToken()}`,
        },
      })
    );
  };
Example #5
Source File: remoteForOnedrive.ts    From remotely-save with Apache License 2.0 6 votes vote down vote up
getJson = async (pathFragOrig: string) => {
    const theUrl = this.buildUrl(pathFragOrig);
    log.debug(`getJson, theUrl=${theUrl}`);
    return JSON.parse(
      await request({
        url: theUrl,
        method: "GET",
        contentType: "application/json",
        headers: {
          Authorization: `Bearer ${await this.authGetter.getAccessToken()}`,
          "Cache-Control": "no-cache",
        },
      })
    );
  };
Example #6
Source File: synonymoAPI.ts    From obsidian-dictionary with GNU Affero General Public License v3.0 6 votes vote down vote up
async requestSynonyms(query: string): Promise<Synonym[]> {
        const synonyms: Synonym[] = [];
        let result: string;
        try {
            result = await request({url: this.constructRequest(query)});
        } catch (error) {
            return Promise.reject(error);
        }

        if(!result){
            return Promise.reject("Word doesnt exist in this Dictionary");
        }

        const parser = new DOMParser();

        const doc = parser.parseFromString(result, 'text/html');

        const x = doc.body.getElementsByClassName("fiche").item(0).getElementsByClassName("word");

        for(let i = 0; i < x.length; i++){
            synonyms.push({word: x.item(i).textContent});
        }
        
        return synonyms;
    }
Example #7
Source File: openThesaurusAPI.ts    From obsidian-dictionary with GNU Affero General Public License v3.0 6 votes vote down vote up
async requestSynonyms(query: string): Promise<Synonym[]> {
        let result: string;
        try {
            result = await request({url: this.constructRequest(query)});
        } catch (error) {
            return Promise.reject(error);
        }

        if(!result){
            return Promise.reject("Word doesnt exist in this Dictionary");
        }

        const response = await JSON.parse(result);

        if(!response.synsets){
            return Promise.reject("Word doesnt exist in this Dictionary");
        }
        
        if (response.synsets.length <= 0) {
            return Promise.reject("No Synonym found");
        }
        const synonymList: Array<Record<string, string>> = response.synsets[0].terms;

        const synonyms: Synonym[] = [];
        synonymList.forEach((synonym) => {
            const word: string = synonym["term"];
            if (query != word) {
                synonyms.push({ word: word });
            }
        });
        return synonyms;
    }
Example #8
Source File: offlineDic.ts    From obsidian-dictionary with GNU Affero General Public License v3.0 6 votes vote down vote up
async getOfflineDictionary(): Promise<Record<string, OfflineDic>> {
        const { plugin } = this.manager;
        const { adapter } = plugin.app.vault;
        const path = normalizePath(`${plugin.manifest.dir}/offlineDictionary.json`);
        if (!this.offlineDic) {
            if (!await adapter.exists(path)) {
                const data = await request({ url: `https://github.com/phibr0/obsidian-dictionary/releases/download/${plugin.manifest.version}/dictionary.json` });
                await adapter.write(path, data);
            }
            this.offlineDic = JSON.parse(await adapter.read(path));
        }
        return this.offlineDic;
    }
Example #9
Source File: freeDictionaryAPI.ts    From obsidian-dictionary with GNU Affero General Public License v3.0 6 votes vote down vote up
/**
     * Sends a request with the passed query to the End Point and returns the Result
     *
     * @param query - The term you want to look up
     * @param lang - The language to use
     * @param _ - For now unused parameter, debouncing mechanism planned
     * @returns The API Response of the API as Promise<DictionaryWord>
     */
    async requestDefinitions(query: string, lang: string, _ = true): Promise<DictionaryWord> {
        let result: string;
        try {
            const url = this.constructRequest(encodeURIComponent(query), this.languageCodes[lang]);
            result = await request({url});
        } catch (error) {
            return Promise.reject(error);
        }

        const json = (await JSON.parse(result) as DictionaryWord[]);

        if(!json || json["title"]){
            return Promise.reject(json["title"]);
        }

        return json.first();
    }
Example #10
Source File: altervistaAPI.ts    From obsidian-dictionary with GNU Affero General Public License v3.0 6 votes vote down vote up
async requestSynonyms(query: string, lang: string, _?: PartOfSpeech): Promise<Synonym[]> {
        const synonyms: Synonym[] = [];
        let result: string;
        try {
            result = await request({url: this.constructRequest(encodeURIComponent(query), lang)});
        } catch (error) {
            return Promise.reject(error);
        }

        if(!result){
            return Promise.reject("Word doesnt exist in this Dictionary");
        }

        const json = await JSON.parse(result);

        for(const c of json.response){
            const words = c.list.synonyms.split('|');
            words.forEach((word: string) => {
                synonyms.push({word: word});
            });
        }

        return synonyms;
    }
Example #11
Source File: TwitterParser.ts    From obsidian-ReadItLater with MIT License 6 votes vote down vote up
async prepareNote(url: string): Promise<Note> {
        const response = JSON.parse(
            await request({
                method: 'GET',
                contentType: 'application/json',
                url: `https://publish.twitter.com/oembed?url=${url}`,
            }),
        );

        const tweetAuthorName = response.author_name;
        const content = await parseHtmlContent(response.html);

        const processedContent = this.settings.twitterNote
            .replace(/%tweetAuthorName%/g, tweetAuthorName)
            .replace(/%tweetURL%/g, response.url)
            .replace(/%tweetContent%/g, content);

        const fileNameTemplate = this.settings.twitterNoteTitle
            .replace(/%tweetAuthorName%/g, tweetAuthorName)
            .replace(/%date%/g, this.getFormattedDateForFilename());

        const fileName = `${fileNameTemplate}.md`;

        return new Note(fileName, processedContent);
    }
Example #12
Source File: serverProcessor.ts    From obsidian-plantuml with MIT License 6 votes vote down vote up
ascii = async(source: string, el: HTMLElement, _: MarkdownPostProcessorContext) => {
        //make sure url is defined, once the setting gets reset to default, an empty string will be returned by settings
        let url = this.plugin.settings.server_url;
        if (url.length == 0) {
            url = DEFAULT_SETTINGS.server_url;
        }
        const asciiUrlBase = url + "/txt/";
        const encodedDiagram = plantuml.encode(source);

        const result = await request({url: asciiUrlBase + encodedDiagram});

        if (result.startsWith("�PNG")) {
            const text = document.createElement("p");
            text.style.color = "red";
            text.innerText = "Your configured PlantUML Server does not support ASCII Art";
            el.appendChild(text);
            return;
        }

        insertAsciiImage(el, result);
    }
Example #13
Source File: serverProcessor.ts    From obsidian-plantuml with MIT License 6 votes vote down vote up
png = async(source: string, el: HTMLElement, _: MarkdownPostProcessorContext) => {
        //make sure url is defined. once the setting gets reset to default, an empty string will be returned by settings
        let url = this.plugin.settings.server_url;
        if (url.length == 0) {
            url = DEFAULT_SETTINGS.server_url;
        }

        const imageUrlBase = url + "/png/";

        const encodedDiagram = plantuml.encode(source);
        const image = imageUrlBase + encodedDiagram;

        //get image map data to support clicking links in diagrams
        const mapUrlBase = url + "/map/";
        const map = await request({url: mapUrlBase + encodedDiagram, method: "GET"});

        insertImageWithMap(el, image, map, encodedDiagram);
    }
Example #14
Source File: serverProcessor.ts    From obsidian-plantuml with MIT License 6 votes vote down vote up
svg = async(source: string, el: HTMLElement, _: MarkdownPostProcessorContext) => {
        //make sure url is defined. once the setting gets reset to default, an empty string will be returned by settings
        let url = this.plugin.settings.server_url;
        if (url.length == 0) {
            url = DEFAULT_SETTINGS.server_url;
        }

        const imageUrlBase = url + "/svg/";
        const encodedDiagram = plantuml.encode(source);

        request({url: imageUrlBase + encodedDiagram, method: 'GET'}).then((value: string) => {
            insertSvgImage(el, value);
        }).catch((error: Error) => {
            if (error)
                console.error(error);
        });
    };
Example #15
Source File: urlConvertor.ts    From obsidian-map-view with GNU General Public License v3.0 6 votes vote down vote up
async getGeolocationFromGoogleLink(
        url: string,
        settings: PluginSettings
    ): Promise<leaflet.LatLng> {
        const content = await request({ url: url });
        if (this.settings.debug) console.log('Google link: searching url', url);
        const placeNameMatch = content.match(
            /<meta content="([^\"]*)" itemprop="name">/
        );
        if (placeNameMatch) {
            const placeName = placeNameMatch[1];
            if (this.settings.debug)
                console.log('Google link: found place name = ', placeName);
            const googleApiKey = settings.geocodingApiKey;
            const params = {
                query: placeName,
                key: googleApiKey,
            };
            const googleUrl =
                'https://maps.googleapis.com/maps/api/place/textsearch/json?' +
                querystring.stringify(params);
            const googleContent = await request({ url: googleUrl });
            const jsonContent = JSON.parse(googleContent) as any;
            if (
                jsonContent &&
                'results' in jsonContent &&
                jsonContent?.results.length > 0
            ) {
                const location = jsonContent.results[0].location;
                if (location && location.lat && location.lng)
                    return new leaflet.LatLng(location.lat, location.lng);
            }
        }
        return null;
    }
Example #16
Source File: urlConvertor.ts    From obsidian-map-view with GNU General Public License v3.0 6 votes vote down vote up
async parseGeolocationWithFetch(
        url: string,
        rule: UrlParsingRule,
        userTextMatchIndex: number,
        userTextMatchLength: number
    ): Promise<ParsedLocation> {
        const urlContent = await request({ url: url });
        if (this.settings.debug)
            console.log('Fetch result for URL', url, ':', urlContent);
        const contentMatch = urlContent.match(rule.contentParsingRegExp);
        if (!contentMatch) return null;
        let geolocation: leaflet.LatLng = null;
        // TODO: Experimental, possibly unfinished code!
        if (rule.contentType === 'latLng' && contentMatch.length > 2)
            geolocation = new leaflet.LatLng(
                parseFloat(contentMatch[1]),
                parseFloat(contentMatch[2])
            );
        else if (rule.contentType === 'lngLat' && contentMatch.length > 2)
            geolocation = new leaflet.LatLng(
                parseFloat(contentMatch[2]),
                parseFloat(contentMatch[1])
            );
        else if (rule.contentType === 'googlePlace') {
            const placeName = contentMatch[1];
            if (this.settings.debug)
                console.log('Google Place search:', placeName);
            // TODO work in progress
            // const places = await googlePlacesSearch(placeName, this.settings);
            // if (places && places.length > 0) geolocation = places[0].location;
        }
        if (geolocation)
            return {
                location: geolocation,
                index: userTextMatchIndex,
                matchLength: userTextMatchLength,
                ruleName: rule.name,
            };
    }
Example #17
Source File: geosearch.ts    From obsidian-map-view with GNU General Public License v3.0 6 votes vote down vote up
export async function googlePlacesSearch(
    query: string,
    settings: PluginSettings
): Promise<GeoSearchResult[]> {
    if (settings.searchProvider != 'google' || !settings.useGooglePlaces)
        return [];
    const googleApiKey = settings.geocodingApiKey;
    const params = {
        query: query,
        key: googleApiKey,
    };
    const googleUrl =
        'https://maps.googleapis.com/maps/api/place/textsearch/json?' +
        querystring.stringify(params);
    const googleContent = await request({ url: googleUrl });
    const jsonContent = JSON.parse(googleContent) as any;
    let results: GeoSearchResult[] = [];
    if (
        jsonContent &&
        'results' in jsonContent &&
        jsonContent?.results.length > 0
    ) {
        for (const result of jsonContent.results) {
            const location = result.geometry?.location;
            if (location && location.lat && location.lng) {
                const geolocation = new leaflet.LatLng(
                    location.lat,
                    location.lng
                );
                results.push({
                    name: `${result?.name} (${result?.formatted_address})`,
                    location: geolocation,
                    resultType: 'searchResult',
                } as GeoSearchResult);
            }
        }
    }
    return results;
}
Example #18
Source File: YoutubeParser.ts    From obsidian-ReadItLater with MIT License 6 votes vote down vote up
async prepareNote(url: string): Promise<Note> {
        const response = await request({ method: 'GET', url });
        const videoHTML = new DOMParser().parseFromString(response, 'text/html');
        const videoTitle = videoHTML.querySelector("[property~='og:title']").getAttribute('content');
        const videoId = this.PATTERN.exec(url)[4];
        const videoPlayer = `<iframe width="560" height="315" src="https://www.youtube.com/embed/${videoId}" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`;

        const content = this.settings.youtubeNote
            .replace(/%videoTitle%/g, videoTitle)
            .replace(/%videoURL%/g, url)
            .replace(/%videoId%/g, videoId)
            .replace(/%videoPlayer%/g, videoPlayer);

        const fileNameTemplate = this.settings.youtubeNoteTitle.replace(/%title%/g, videoTitle);
        const fileName = `${fileNameTemplate}.md`;
        return new Note(fileName, content);
    }
Example #19
Source File: WebsiteParser.ts    From obsidian-ReadItLater with MIT License 6 votes vote down vote up
async prepareNote(url: string): Promise<Note> {
        const response = await request({ method: 'GET', url });
        const document = new DOMParser().parseFromString(response, 'text/html');

        // Set base to allow Readability to resolve relative path's
        const baseEl = document.createElement('base');
        baseEl.setAttribute('href', getBaseUrl(url));
        document.head.append(baseEl);
        const cleanDocumentBody = DOMPurify.sanitize(document.body.innerHTML);
        document.body.innerHTML = cleanDocumentBody;

        if (!isProbablyReaderable(document)) {
            new Notice('@mozilla/readability considers this document to unlikely be readerable.');
        }
        const readableDocument = new Readability(document).parse();

        return readableDocument?.content
            ? await this.parsableArticle(this.app, readableDocument, url)
            : this.notParsableArticle(url);
    }
Example #20
Source File: rssParser.ts    From obsidian-rss with GNU General Public License v3.0 5 votes vote down vote up
async function requestFeed(feed: RssFeed) : Promise<string> {
    return await request({url: feed.url});
}
Example #21
Source File: freeDictionaryAPI.ts    From obsidian-dictionary with GNU Affero General Public License v3.0 5 votes vote down vote up
/**
     *
     * @param query - The word to look up synonyms for
     * @param lang - The host language
     * @param pos - The part of speech of the target word
     * @returns A list of Synonyms
     */
    async requestSynonyms(query: string, lang: string, pos?: PartOfSpeech): Promise<Synonym[]> {
        let result: string;
        try {
            result = await request({url: this.constructRequest(query, this.languageCodes[lang])});
        } catch (error) {
            return Promise.reject(error);
        }
        
        if(!result){
            return Promise.reject("Word doesnt exist in this Dictionary");
        }

        const meanings: Meaning[] = (await JSON.parse(result) as DictionaryWord[]).first().meanings;
        const synonyms: Synonym[] = [];

        // The default POS provider seems pretty wonky at the moment,
        // so let's include non-matches in the results as well
        const nonPOSMatch: Synonym[] = [];

        meanings.forEach(meaning => {
            if (Number.isNumber(pos) && !this.getDoesPosMatch(meaning, pos)) {
                meaning.definitions.forEach(def => {
                    if (def.synonyms) {
                        def.synonyms.forEach(synonym => {
                            nonPOSMatch.push({
                                word: synonym,
                            })
                        })
                    }
                })
                return;
            }

            meaning.definitions.forEach(def => {
                if (def.synonyms) {
                    def.synonyms.forEach(synonym => {
                        synonyms.push({
                            word: synonym,
                        })
                    })
                }
            })
        })

        return synonyms.concat(nonPOSMatch);
    }
Example #22
Source File: remoteForOnedrive.ts    From remotely-save with Apache License 2.0 5 votes vote down vote up
sendAuthReq = async (
  clientID: string,
  authority: string,
  authCode: string,
  verifier: string
) => {
  // // original code snippets for references
  // const authResponse = await pca.acquireTokenByCode({
  //   redirectUri: REDIRECT_URI,
  //   scopes: SCOPES,
  //   code: authCode,
  //   codeVerifier: verifier, // PKCE Code Verifier
  // });
  // log.info('authResponse')
  // log.info(authResponse)
  // return authResponse;

  // Because of the CORS problem,
  // we need to construct raw request using Obsidian request,
  // instead of using msal
  // https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
  // https://docs.microsoft.com/en-us/onedrive/developer/rest-api/getting-started/graph-oauth?view=odsp-graph-online#code-flow
  const rsp1 = await request({
    url: `${authority}/oauth2/v2.0/token`,
    method: "POST",
    contentType: "application/x-www-form-urlencoded",
    body: new URLSearchParams({
      tenant: "consumers",
      client_id: clientID,
      scope: SCOPES.join(" "),
      code: authCode,
      redirect_uri: REDIRECT_URI,
      grant_type: "authorization_code",
      code_verifier: verifier,
    }).toString(),
  });

  const rsp2 = JSON.parse(rsp1);
  // log.info(rsp2);

  if (rsp2.error !== undefined) {
    return rsp2 as AccessCodeResponseFailedType;
  } else {
    return rsp2 as AccessCodeResponseSuccessfulType;
  }
}
Example #23
Source File: FeedSettings.ts    From obsidian-rss with GNU General Public License v3.0 4 votes vote down vote up
function displayFeedList(plugin: RssReaderPlugin, container: HTMLElement, disabled = false) {

    container.empty();

    const sorted = sortBy(groupBy(plugin.settings.feeds, "folder"), function (o) {
        return o[0].folder;
    });
    for (const [, feeds] of Object.entries(sorted)) {
        for (const id in feeds) {
            const feed = feeds[id];

            const setting = new Setting(container);

            setting.setName((feed.folder ? feed.folder : t("no_folder")) + " - " + feed.name);
            setting.setDesc(feed.url);

            setting
                .addExtraButton((b) => {
                    b
                        .setDisabled(disabled)
                        .setIcon("edit")
                        .setTooltip(t("edit"))
                        .onClick(() => {
                            const modal = new FeedModal(plugin, feed);
                            const oldFeed: RssFeed = feed;

                            modal.onClose = async () => {
                                if (modal.saved) {
                                    const feeds = plugin.settings.feeds;
                                    feeds.remove(oldFeed);
                                    feeds.push({
                                        name: modal.name,
                                        url: modal.url,
                                        folder: modal.folder ? modal.folder : ""
                                    });

                                    let items = plugin.settings.items;

                                    //make sure this data is transferred to the new entry, or this will cause a lot
                                    //of chaos when renaming, like putting entries into the wrong feed.
                                    items = items.filter((content) => {
                                        return content.name === oldFeed.name && content.folder === oldFeed.folder;
                                    });
                                    items.forEach((content) => {
                                        content.name = modal.name;
                                        content.folder = modal.folder;
                                        content.hash = <string>new Md5().appendStr(modal.name).appendStr(modal.folder).end();
                                        content.items.forEach(item => {
                                            item.feed = modal.name;
                                            item.folder = modal.folder ? modal.folder : "";
                                            item.hash = <string>new Md5().appendStr(item.title).appendStr(item.folder).appendStr(item.link).end();
                                        });
                                    });
                                    await plugin.writeFeedContent(() => {
                                        return items;
                                    });

                                    await plugin.writeFeeds(() => (feeds));
                                    displayFeedList(plugin, container);
                                }
                            };

                            modal.open();
                        });
                })
                .addExtraButton((button) => {
                    button
                        .setDisabled(disabled)
                        .setTooltip(t("from_archive"))
                        .setIcon("archive")
                        .onClick(async () => {
                            const modal = new MessageModal(plugin, t("reading_archive"));
                            modal.open();
                            displayFeedList(plugin, container, true);

                            const timemap = await request({
                                method: "GET",
                                url: "https://web.archive.org/web/timemap/link/" + feed.url
                            });
                            const items: RssFeedContent[] = [];
                            const lines = timemap.split("\n");
                            for (const line of lines) {
                                if (line.contains("memento")) {
                                    const link = line.slice(1, line.indexOf(">"));
                                    const first = link.substring(0, 41);
                                    const second = link.substring(42);
                                    items.push(await getFeedItems({
                                        name: feed.name,
                                        url: first + "id_" + second,
                                        folder: feed.folder
                                    }));
                                }
                            }

                            modal.setMessage(t("scanning_duplicates"));

                            for (const feed of plugin.settings.items) {
                                for (const content of items) {
                                    if (feed.folder === content.folder && feed.name === content.name) {
                                        const sortedItems = content.items.sort((a, b) => {
                                            return moment(b.pubDate).diff(moment(a.pubDate));
                                        });
                                        for (const item of sortedItems) {
                                            const filter = feed.items.filter((filterItem) => {
                                                return filterItem.folder === item.folder && filterItem.title === item.title;
                                            });
                                            if (filter.length === 0) {
                                                feed.items.push(item);
                                            }
                                        }
                                    }
                                }
                            }

                            await plugin.writeFeedContent(() => {
                                return plugin.settings.items;
                            });
                            displayFeedList(plugin, container, false);
                            modal.setMessage(t("refreshed_feeds"));
                            modal.close();
                        });
                })
                .addExtraButton((b) => {
                    b
                        .setDisabled(disabled)
                        .setIcon("lucide-trash")
                        .setTooltip(t("delete"))
                        .onClick(async () => {
                            const feeds = plugin.settings.feeds;
                            feeds.remove(feed);
                            await plugin.writeFeeds(() => feeds);

                            //delete wallabag.xml items from feed
                            let content = plugin.settings.items;
                            content = content.filter((content) => {
                                return content.name !== feed.name;
                            });
                            await plugin.writeFeedContent(() => content);

                            displayFeedList(plugin, container);
                        });
                });
        }
    }
}