// Name: Preview CSS Color// Description: Preview any CSS color accepted by background-color// Author: Josh Davenport-Smith// Twitter: @joshdprtsimport "@johnlindquist/kit";const color = await arg("Color");await div(`<div class="pt-2 h-full w-full"><div class="checker h-full w-full"><div style="background-color: ${color}" class="h-full w-full flex items-start"><div class="bg-white"><div style="background-color: ${color}" class="p-2"><div style="color: ${color}; filter: invert(100%); text-shadow: 0 0 1px hsla(0, 0%, 100%, 0.2)" class="w-fit text-xs">${color}</div></div></div></div></div></div><style type="text/css">.checker {background-color: #fff;background-size: 24px 24px;background-position: 0 0, 12px 12px;background-image: linear-gradient(45deg, #efefef 25%, transparent 25%, transparent 75%, #efefef 75%, #efefef), linear-gradient(45deg, #efefef 25%, transparent 25%, transparent 75%, #efefef 75%, #efefef);}</style>`);
// Name: Bandcamp Album Player// Description: Stream a bandcamp album// Author: Josh Davenport-Smith// Twitter: @jdprtsimport "@johnlindquist/kit";import { WidgetAPI } from "@johnlindquist/kit/types/pro";const jsdom = await npm('jsdom');const INITIAL_PLAYER_WIDTH = 500;const MAX_PLAYER_WIDTH = 740;const INITIAL_PLAYER_HEIGHT = 120;const htmlDecode = (input: string) => {const doc = new jsdom.JSDOM(`<!DOCTYPE html><div>${input}</div>`);return doc.window.document.querySelector('div').textContent;}const getStyles = () => `:root {--dragbar-width: 30px;}iframe {position: absolute;left: var(--dragbar-width);top: 0;width: calc(100% - var(--dragbar-width));height: 100%;-webkit-app-region: no-drag;}#dragbar {position: absolute;top: 0;left: 0;bottom: 0;width: var(--dragbar-width);cursor: grab;background: #F1F1F1;}#dragbar:after {content: '';position: absolute;inset: 6px;background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1IiBoZWlnaHQ9IjUiPgo8cmVjdCB3aWR0aD0iNSIgaGVpZ2h0PSI1IiBmaWxsPSIjRjFGMUYxIj48L3JlY3Q+CjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIGZpbGw9IiNjY2MiPjwvcmVjdD4KPC9zdmc+");}#dragbar:active {cursor: grabbing;}`;const getScripts = (albumId: number) => `(() => {const url = 'https://bandcamp.com/EmbeddedPlayer/album=${albumId}/size=large/bgcol=ffffff/linkcol=0687f5/tracklist=false/artwork=small/transparent=true/';const iframe = document.createElement('iframe');iframe.setAttribute('src', url);iframe.setAttribute('seamless', true);document.body.appendChild(iframe);})();`;// Obtain the album (or track) URLconst albumUrl = await arg('What is the album URL?');// Bail if the URL is invalidif (!albumUrl.includes('bandcamp.com/album') && !albumUrl.includes('bandcamp.com/track')) {throw new Error('Sorry, I don\'t recognise that URL');}// Give feedback that we're metadata for the albumdiv(md(`Loading album...---Note: Some URLs will not work because of permissions set by the artist`));// Grab the bandcamp page for bc-page-properties which stores meta about the albumconst pageContents = await fetch(albumUrl).then((res) => res.text());const bandcampMetaParse = pageContents.match(/<meta name="bc-page-properties".*?content="([^"]+)">/);await Promise.all([// Give the user a chance to read the message (some URLs will not work and there's no obious way to tell in advance)new Promise((resolve) => setTimeout(resolve, 2000)),// Also wait for the data to load, so we continue when both promises resolvepageContents,])if (!bandcampMetaParse) {throw new Error('Sorry, I couldn\'t find the album ID');}// Parse the meta we foundconst bandcampMeta: { item_type?: string, item_id?: number, tralbum_page_version?: number } | undefined = JSON.parse(htmlDecode(bandcampMetaParse[1]));if (!bandcampMeta?.item_id) {throw new Error('Sorry, I couldn\'t find the album ID');}// Create a widget with the player!const w: WidgetAPI = await widget(`<div id="dragbar"></div><style type="text/css">${getStyles()}</style><script type="text/javascript">${getScripts(bandcampMeta.item_id)}</script>`,{alwaysOnTop: true,width: INITIAL_PLAYER_WIDTH,maxWidth: MAX_PLAYER_WIDTH,height: INITIAL_PLAYER_HEIGHT,minHeight: INITIAL_PLAYER_HEIGHT,maxHeight: INITIAL_PLAYER_HEIGHT,roundedCorners: false,thickFrame: false,});w.setSize(INITIAL_PLAYER_WIDTH, INITIAL_PLAYER_HEIGHT);
// Name: BBC Sounds Player// Description: Stream a radio station from BBC Sounds// Author: Josh Davenport-Smith// Twitter: @jdprtsimport "@johnlindquist/kit";import { WidgetAPI } from "@johnlindquist/kit/types/pro";const PLAYER_WIDTH = 180;const PLAYER_HEIGHT = 195;const getStyles = () => `:root {--player-width: ${PLAYER_WIDTH}px;--player-height: ${PLAYER_HEIGHT}px;--header-offset: 25px;--footer-offset: 25px;--scale: 2.2;}#player {width: var(--player-width);height: var(--player-height);overflow: hidden;position: relative;}iframe {position: absolute;left: 0;width: calc(var(--player-width) * var(--scale));height: calc((var(--player-height) * var(--scale)) + (var(--header-offset) * var(--scale)) + (var(--footer-offset) * var(--scale)));top: calc(var(--header-offset) * -1);transform: scale(calc(1 / var(--scale)));transform-origin: 0 0;}`;const getScripts = (station: string) => `(() => {const playerContainer = document.getElementById('player');const url = 'https://www.bbc.co.uk/sounds/player/bbc_${station}';const iframe = document.createElement('iframe');iframe.setAttribute('src', url);iframe.setAttribute('enablejsapi', true);playerContainer.appendChild(iframe);})();`;const station = await arg('Select station', [{name: '6 Music',value: '6music',img: 'https://sounds.files.bbci.co.uk/3.1.5/networks/bbc_6music/colour_default.svg',},{name: 'Radio 1',value: 'radio_one',img: 'https://sounds.files.bbci.co.uk/3.1.5/networks/bbc_radio_one/colour_default.svg',},{name: 'Radio 2',value: 'radio_two',img: 'https://sounds.files.bbci.co.uk/3.1.5/networks/bbc_radio_two/colour_default.svg',},{name: 'Radio 3',value: 'radio_three',img: 'https://sounds.files.bbci.co.uk/3.1.5/networks/bbc_radio_three/colour_default.svg',},{name: 'Radio 4',value: 'radio_fourfm',img: 'https://sounds.files.bbci.co.uk/3.1.5/networks/bbc_radio_four/colour_default.svg',},{name: 'Radio Five Live',value: 'radio_five_live',img: 'https://sounds.files.bbci.co.uk/3.1.5/networks/bbc_radio_five_live/colour_default.svg',},{name: 'World Service',value: 'world_service',img: 'https://sounds.files.bbci.co.uk/3.1.5/networks/bbc_world_service/colour_default.svg',},])const w: WidgetAPI = await widget(`<div id="player"></div><style type="text/css">${getStyles()}</style><script type="text/javascript">${getScripts(station)}</script>`,{ alwaysOnTop: true });w.setSize(PLAYER_WIDTH, PLAYER_HEIGHT);w.onClick(event => event.targetId === "x" && w.close());w.onResized(() => w.setSize(PLAYER_WIDTH, PLAYER_HEIGHT));
// Name: Open Notion URL in Notion App// Description: Open a Notion URL in the desktio Notion App instead of the browser// Author: Josh Davenport-Smithimport "@johnlindquist/kit"const url = await arg('What is the Notion URL?');if (!url.includes('notion.so')) {throw new Error('Not a Notion URL');}await applescript(String.raw`tell application "Notion"activateopen location "${url}"end tell`);