Compare commits

...
7 Commits
Author SHA1 Message Date
Tobias Gesellchen e424ee6546 Extract all icons, add mapping including names 2026-03-28 15:49:06 +01:00
Tobias Gesellchen d9d9a67f0e Add font-icon-extractor tool 2026-03-28 15:49:06 +01:00
Tobias Gesellchen e0a84d5904 Split register and unregister device tests (#133) 2026-03-27 22:03:21 +01:00
dependabot[bot]andlnx01 5d080cf35f ci(deps): bump codecov/codecov-action from 5 to 6 in the security-actions group (#132)
Bumps the security-actions group with 1 update:
[codecov/codecov-action](https://github.com/codecov/codecov-action).

Updates `codecov/codecov-action` from 5 to 6
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/codecov/codecov-action/releases">codecov/codecov-action's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.0</h2>
<h2>⚠️ This version introduces support for node24 which make cause
breaking changes for systems that do not currently support node24.
⚠️</h2>
<h2>What's Changed</h2>
<ul>
<li>Revert &quot;Revert &quot;build(deps): bump actions/github-script
from 7.0.1 to 8.0.0&quot;&quot; by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1929">codecov/codecov-action#1929</a></li>
<li>Th/6.0.0 by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1928">codecov/codecov-action#1928</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.5.4...v6.0.0">https://github.com/codecov/codecov-action/compare/v5.5.4...v6.0.0</a></p>
<h2>v5.5.4</h2>
<p>This is a mirror of <code>v5.5.2</code>. <code>v6</code> will be
released which requires <code>node24</code></p>
<h2>What's Changed</h2>
<ul>
<li>Revert &quot;build(deps): bump actions/github-script from 7.0.1 to
8.0.0&quot; by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1926">codecov/codecov-action#1926</a></li>
<li>chore(release): 5.5.4 by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1927">codecov/codecov-action#1927</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.5.3...v5.5.4">https://github.com/codecov/codecov-action/compare/v5.5.3...v5.5.4</a></p>
<h2>v5.5.3</h2>
<h2>What's Changed</h2>
<ul>
<li>build(deps): bump actions/github-script from 7.0.1 to 8.0.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1874">codecov/codecov-action#1874</a></li>
<li>chore(release): bump to 5.5.3 by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1922">codecov/codecov-action#1922</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.5.2...v5.5.3">https://github.com/codecov/codecov-action/compare/v5.5.2...v5.5.3</a></p>
<h2>v5.5.2</h2>
<h2>What's Changed</h2>
<ul>
<li>check gpg only when skip-validation = false by <a
href="https://github.com/maxweng-sentry"><code>@​maxweng-sentry</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1894">codecov/codecov-action#1894</a></li>
<li>chore: <code>disable_search</code> alignment by <a
href="https://github.com/freemanzMrojo"><code>@​freemanzMrojo</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1881">codecov/codecov-action#1881</a></li>
<li>chore(release): 5.5.2 by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1902">codecov/codecov-action#1902</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/maxweng-sentry"><code>@​maxweng-sentry</code></a>
made their first contribution in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1894">codecov/codecov-action#1894</a></li>
<li><a
href="https://github.com/freemanzMrojo"><code>@​freemanzMrojo</code></a>
made their first contribution in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1881">codecov/codecov-action#1881</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.5.1...v5.5.2">https://github.com/codecov/codecov-action/compare/v5.5.1...v5.5.2</a></p>
<h2>v5.5.1</h2>
<h2>What's Changed</h2>
<ul>
<li>build(deps): bump ossf/scorecard-action from 2.4.1 to 2.4.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1833">codecov/codecov-action#1833</a></li>
<li>build(deps): bump github/codeql-action from 3.28.18 to 3.29.9 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1861">codecov/codecov-action#1861</a></li>
<li>Document a <code>codecov-cli</code> version reference example by <a
href="https://github.com/webknjaz"><code>@​webknjaz</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1774">codecov/codecov-action#1774</a></li>
<li>docs: fix typo in README by <a
href="https://github.com/datalater"><code>@​datalater</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1866">codecov/codecov-action#1866</a></li>
<li>fix: update to use local app/ dir by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1872">codecov/codecov-action#1872</a></li>
<li>build(deps): bump github/codeql-action from 3.29.9 to 3.29.11 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1867">codecov/codecov-action#1867</a></li>
<li>build(deps): bump actions/checkout from 4.2.2 to 5.0.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1868">codecov/codecov-action#1868</a></li>
<li>fix: overwrite pr number on fork by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1871">codecov/codecov-action#1871</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md">codecov/codecov-action's
changelog</a>.</em></p>
<blockquote>
<h2>v5.5.2</h2>
<h3>What's Changed</h3>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.5.1..v5.5.2">https://github.com/codecov/codecov-action/compare/v5.5.1..v5.5.2</a></p>
<h2>v5.5.1</h2>
<h3>What's Changed</h3>
<ul>
<li>fix: overwrite pr number on fork by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1871">codecov/codecov-action#1871</a></li>
<li>build(deps): bump actions/checkout from 4.2.2 to 5.0.0 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1868">codecov/codecov-action#1868</a></li>
<li>build(deps): bump github/codeql-action from 3.29.9 to 3.29.11 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1867">codecov/codecov-action#1867</a></li>
<li>fix: update to use local app/ dir by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1872">codecov/codecov-action#1872</a></li>
<li>docs: fix typo in README by <a
href="https://github.com/datalater"><code>@​datalater</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1866">codecov/codecov-action#1866</a></li>
<li>Document a <code>codecov-cli</code> version reference example by <a
href="https://github.com/webknjaz"><code>@​webknjaz</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1774">codecov/codecov-action#1774</a></li>
<li>build(deps): bump github/codeql-action from 3.28.18 to 3.29.9 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1861">codecov/codecov-action#1861</a></li>
<li>build(deps): bump ossf/scorecard-action from 2.4.1 to 2.4.2 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1833">codecov/codecov-action#1833</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.5.0..v5.5.1">https://github.com/codecov/codecov-action/compare/v5.5.0..v5.5.1</a></p>
<h2>v5.5.0</h2>
<h3>What's Changed</h3>
<ul>
<li>feat: upgrade wrapper to 0.2.4 by <a
href="https://github.com/jviall"><code>@​jviall</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1864">codecov/codecov-action#1864</a></li>
<li>Pin actions/github-script by Git SHA by <a
href="https://github.com/martincostello"><code>@​martincostello</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1859">codecov/codecov-action#1859</a></li>
<li>fix: check reqs exist by <a
href="https://github.com/joseph-sentry"><code>@​joseph-sentry</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1835">codecov/codecov-action#1835</a></li>
<li>fix: Typo in README by <a
href="https://github.com/spalmurray"><code>@​spalmurray</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1838">codecov/codecov-action#1838</a></li>
<li>docs: Refine OIDC docs by <a
href="https://github.com/spalmurray"><code>@​spalmurray</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1837">codecov/codecov-action#1837</a></li>
<li>build(deps): bump github/codeql-action from 3.28.17 to 3.28.18 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1829">codecov/codecov-action#1829</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.4.3..v5.5.0">https://github.com/codecov/codecov-action/compare/v5.4.3..v5.5.0</a></p>
<h2>v5.4.3</h2>
<h3>What's Changed</h3>
<ul>
<li>build(deps): bump github/codeql-action from 3.28.13 to 3.28.17 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1822">codecov/codecov-action#1822</a></li>
<li>fix: OIDC on forks by <a
href="https://github.com/joseph-sentry"><code>@​joseph-sentry</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1823">codecov/codecov-action#1823</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.4.2..v5.4.3">https://github.com/codecov/codecov-action/compare/v5.4.2..v5.4.3</a></p>
<h2>v5.4.2</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/codecov/codecov-action/commit/57e3a136b779b570ffcdbf80b3bdc90e7fab3de2"><code>57e3a13</code></a>
Th/6.0.0 (<a
href="https://redirect.github.com/codecov/codecov-action/issues/1928">#1928</a>)</li>
<li><a
href="https://github.com/codecov/codecov-action/commit/f67d33dda8a42b51c42a8318a1f66468119e898b"><code>f67d33d</code></a>
Revert &quot;Revert &quot;build(deps): bump actions/github-script from
7.0.1 to 8.0.0&quot;&quot;...</li>
<li>See full diff in <a
href="https://github.com/codecov/codecov-action/compare/v5...v6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=codecov/codecov-action&package-manager=github_actions&previous-version=5&new-version=6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-27 08:47:00 +01:00
dependabot[bot]andlnx01 bcd383bdff ci(deps): bump actions/deploy-pages from 4 to 5 in the actions-core group (#131)
Bumps the actions-core group with 1 update:
[actions/deploy-pages](https://github.com/actions/deploy-pages).

Updates `actions/deploy-pages` from 4 to 5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/deploy-pages/releases">actions/deploy-pages's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<h1>Changelog</h1>
<ul>
<li>Update Node.js version to 24.x <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> (<a
href="https://redirect.github.com/actions/deploy-pages/issues/404">#404</a>)</li>
<li>Add workflow file for publishing releases to immutable action
package <a
href="https://github.com/Jcambass"><code>@​Jcambass</code></a> (<a
href="https://redirect.github.com/actions/deploy-pages/issues/374">#374</a>)</li>
<li>Bump braces from 3.0.2 to 3.0.3 in the npm_and_yarn group across 1
directory <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> (<a
href="https://redirect.github.com/actions/deploy-pages/issues/360">#360</a>)</li>
<li>Make the rebuild dist workflow work nicer with Dependabot <a
href="https://github.com/yoannchaudet"><code>@​yoannchaudet</code></a>
(<a
href="https://redirect.github.com/actions/deploy-pages/issues/361">#361</a>)</li>
<li>Bump the non-breaking-changes group across 1 directory with 3
updates <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> (<a
href="https://redirect.github.com/actions/deploy-pages/issues/358">#358</a>)</li>
<li>Delete repeated sentence <a
href="https://github.com/garethsb"><code>@​garethsb</code></a> (<a
href="https://redirect.github.com/actions/deploy-pages/issues/359">#359</a>)</li>
<li>Update README.md <a
href="https://github.com/tsusdere"><code>@​tsusdere</code></a> (<a
href="https://redirect.github.com/actions/deploy-pages/issues/348">#348</a>)</li>
<li>Bump the non-breaking-changes group with 4 updates <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> (<a
href="https://redirect.github.com/actions/deploy-pages/issues/341">#341</a>)</li>
<li>Remove error message for file permissions <a
href="https://github.com/TooManyBees"><code>@​TooManyBees</code></a> (<a
href="https://redirect.github.com/actions/deploy-pages/issues/340">#340</a>)</li>
</ul>
<hr />
<p>See details of <a
href="https://github.com/actions/deploy-pages/compare/v4.0.5...v4.0.6">all
code changes</a> since previous release.</p>
<p>⚠️ For use with products other than GitHub.com, such as GitHub
Enterprise Server, please consult the <a
href="https://github.com/actions/deploy-pages/#compatibility">compatibility
table</a>.</p>
<h2>v4.0.5</h2>
<h1>Changelog</h1>
<ul>
<li>On API error, the error message will surface the API request ID <a
href="https://github.com/TooManyBees"><code>@​TooManyBees</code></a> (<a
href="https://redirect.github.com/actions/deploy-pages/issues/324">#324</a>)</li>
<li>Bump the non-breaking-changes group with 2 updates <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> (<a
href="https://redirect.github.com/actions/deploy-pages/issues/318">#318</a>)</li>
<li>Bump the non-breaking-changes group with 1 update <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> (<a
href="https://redirect.github.com/actions/deploy-pages/issues/316">#316</a>)</li>
<li>Bump the non-breaking-changes group with 3 updates <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> (<a
href="https://redirect.github.com/actions/deploy-pages/issues/314">#314</a>)</li>
<li>Bump release-drafter/release-drafter from 5.25.0 to 6.0.0 <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> (<a
href="https://redirect.github.com/actions/deploy-pages/issues/311">#311</a>)</li>
</ul>
<hr />
<p>See details of <a
href="https://github.com/actions/deploy-pages/compare/v4.0.4...v4.0.5">all
code changes</a> since previous release.</p>
<p>⚠️ For use with products other than GitHub.com, such as GitHub
Enterprise Server, please consult the <a
href="https://github.com/actions/deploy-pages/#compatibility">compatibility
table</a>.</p>
<h2>v4.0.4</h2>
<h1>Changelog</h1>
<ul>
<li>Update api-client.js <a
href="https://github.com/lmammino"><code>@​lmammino</code></a> (<a
href="https://redirect.github.com/actions/deploy-pages/issues/295">#295</a>)</li>
<li>fix typo: compatibilty -&gt; compatibility <a
href="https://github.com/SimonSiefke"><code>@​SimonSiefke</code></a> (<a
href="https://redirect.github.com/actions/deploy-pages/issues/298">#298</a>)</li>
<li>Bump <code>@​actions/artifact</code> from 2.0.1 to 2.1.1 <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> (<a
href="https://redirect.github.com/actions/deploy-pages/issues/310">#310</a>)</li>
<li>Update Dependabot config to group non-breaking changes <a
href="https://github.com/JamesMGreene"><code>@​JamesMGreene</code></a>
(<a
href="https://redirect.github.com/actions/deploy-pages/issues/307">#307</a>)</li>
</ul>
<hr />
<p>See details of <a
href="https://github.com/actions/deploy-pages/compare/v4.0.3...v4.0.4">all
code changes</a> since previous release.</p>
<p>⚠️ For use with products other than GitHub.com, such as GitHub
Enterprise Server, please consult the <a
href="https://github.com/actions/deploy-pages/#compatibility">compatibility
table</a>.</p>
<h2>v4.0.3</h2>
<h1>Changelog</h1>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/deploy-pages/commit/cd2ce8fcbc39b97be8ca5fce6e763baed58fa128"><code>cd2ce8f</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/deploy-pages/issues/404">#404</a>
from salmanmkc/node24</li>
<li><a
href="https://github.com/actions/deploy-pages/commit/bbe2a950ee52d4f5cbe74e6d9d6a8803676e91d5"><code>bbe2a95</code></a>
Update Node.js version to 24.x</li>
<li><a
href="https://github.com/actions/deploy-pages/commit/854d7aa1b99e4509c4d1b53d69b7ba4eaf39215a"><code>854d7aa</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/deploy-pages/issues/374">#374</a>
from actions/Jcambass-patch-1</li>
<li><a
href="https://github.com/actions/deploy-pages/commit/306bb814f29679fd12f0e4b0014bc1f3a7e7f4bc"><code>306bb81</code></a>
Add workflow file for publishing releases to immutable action
package</li>
<li><a
href="https://github.com/actions/deploy-pages/commit/b74272834adc04f971da4b0b055c49fa8d7f90c9"><code>b742728</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/deploy-pages/issues/360">#360</a>
from actions/dependabot/npm_and_yarn/npm_and_yarn-513...</li>
<li><a
href="https://github.com/actions/deploy-pages/commit/72732942c639e67ea3f70165fd2e012dd6d95027"><code>7273294</code></a>
Bump braces in the npm_and_yarn group across 1 directory</li>
<li><a
href="https://github.com/actions/deploy-pages/commit/963791f01c40ef3eff219c255dbfb97a6f2c9f87"><code>963791f</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/deploy-pages/issues/361">#361</a>
from actions/dependabot-friendly</li>
<li><a
href="https://github.com/actions/deploy-pages/commit/51bb29d9d7bfe15d731c4957ce1887b5ae8c6727"><code>51bb29d</code></a>
Make the rebuild dist workflow safer for Dependabot</li>
<li><a
href="https://github.com/actions/deploy-pages/commit/89f3d10406f57ee86e6517a982b3fb0438bd6dc5"><code>89f3d10</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/deploy-pages/issues/358">#358</a>
from actions/dependabot/npm_and_yarn/non-breaking-cha...</li>
<li><a
href="https://github.com/actions/deploy-pages/commit/bce735589bbbfa569f1d2ac003277b590d743e4c"><code>bce7355</code></a>
Merge branch 'main' into
dependabot/npm_and_yarn/non-breaking-changes-99c12deb21</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/deploy-pages/compare/v4...v5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/deploy-pages&package-manager=github_actions&previous-version=4&new-version=5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-27 08:46:51 +01:00
dependabot[bot]andlnx01 7a09a2ddc0 deps(deps): bump golang.org/x/image from 0.37.0 to 0.38.0 in the golang group (#130)
Bumps the golang group with 1 update:
[golang.org/x/image](https://github.com/golang/image).

Updates `golang.org/x/image` from 0.37.0 to 0.38.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/image/commit/23ae9ed61c1d3343fb95015810f62dcbf444976e"><code>23ae9ed</code></a>
tiff: cap buffer growth to prevent OOM from malicious IFD offset</li>
<li><a
href="https://github.com/golang/image/commit/e589e60f29d0bbbf6400e250e024f93cbc4961ee"><code>e589e60</code></a>
webp: allow VP8L + VP8X(with alpha)</li>
<li>See full diff in <a
href="https://github.com/golang/image/compare/v0.37.0...v0.38.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=golang.org/x/image&package-manager=go_modules&previous-version=0.37.0&new-version=0.38.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-27 08:46:41 +01:00
Tobias Gesellchen b04b0bcc32 Add account registration/login (#129) 2026-03-27 08:37:50 +01:00
486 changed files with 3993 additions and 18 deletions
+7 -1
View File
@@ -43,8 +43,14 @@ jobs:
- name: Run tests
run: go test -v -race -coverprofile=coverage.out ./...
- name: Build service
run: make build-service
- name: Run HTTP client integration tests
run: make test-http-client
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v6
with:
file: ./coverage.out
flags: unittests
+1 -1
View File
@@ -34,4 +34,4 @@ jobs:
path: '_site'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v5
+31 -1
View File
@@ -103,7 +103,37 @@ test-coverage:
$(GOCMD) tool cover -html=coverage.out -o coverage.html
@echo "Coverage report generated: coverage.html"
check: fmt vet test
check: fmt vet test test-http-client
test-http-client:
@echo "Running HTTP client integration tests..."
@docker network create soundtouch-test-net || true
@docker build -t soundtouch-service-test .
@docker run -d --name soundtouch-service --network soundtouch-test-net \
-e PORT=8000 \
soundtouch-service-test
@echo "Waiting for service to start..."
@sleep 5
@docker run --rm --network soundtouch-test-net \
-v $(PWD)/tests/integration/http-client:/workdir \
jetbrains/intellij-http-client:2026.1 \
--env-file /workdir/http-client.env.json \
--env ci \
/workdir/create_account.http \
/workdir/register_device.http \
/workdir/power_on.http \
/workdir/get_provider_settings.http \
/workdir/get_full_account.http \
/workdir/get_group.http \
/workdir/unregister_device.http \
--report; \
EXIT_CODE=$$?; \
docker logs soundtouch-service; \
docker stop soundtouch-service; \
docker rm soundtouch-service; \
docker rmi soundtouch-service-test; \
docker network rm soundtouch-test-net; \
exit $$EXIT_CODE
fmt:
@echo "Formatting code..."
+1
View File
@@ -0,0 +1 @@
test_output/
+305
View File
@@ -0,0 +1,305 @@
// Package main provides a utility to extract icons from Bose-branded TrueType fonts.
package main
import (
"encoding/json"
"flag"
"fmt"
"image"
"image/color"
"image/draw"
"image/png"
"log"
"os"
"path/filepath"
"sort"
"github.com/srwiley/rasterx"
"golang.org/x/image/font"
"golang.org/x/image/font/sfnt"
"golang.org/x/image/math/fixed"
)
type IconMapping struct {
Hex string `json:"hex"`
GlyphName string `json:"glyph_name"`
File string `json:"file"`
SVGFile string `json:"svg_file,omitempty"`
}
func main() {
fontPath := flag.String("font", "/path/to/bose.ttf", "Path to the TTF font file")
outputDir := flag.String("output", "extracted_icons", "Output directory for icons")
imgSize := flag.Int("size", 256, "Size of the PNG icons")
flag.Parse()
if err := os.MkdirAll(*outputDir, 0755); err != nil {
log.Fatalf("Failed to create output directory: %v", err)
}
data, err := os.ReadFile(*fontPath)
if err != nil {
log.Fatalf("Failed to read font file: %v", err)
}
f, err := sfnt.Parse(data)
if err != nil {
log.Fatalf("Failed to parse font: %v", err)
}
var (
buffer sfnt.Buffer
glyphIndex sfnt.GlyphIndex
glyphName string
segments sfnt.Segments
pngFile *os.File
)
unitsPerEm := f.UnitsPerEm()
ppem := fixed.Int26_6(unitsPerEm) << 6
m, err := f.Metrics(&buffer, ppem, font.HintingNone)
if err != nil {
log.Fatalf("Failed to get metrics: %v", err)
}
mapping := make(map[rune]IconMapping)
// Iterate through common ranges
ranges := []struct{ start, end rune }{
{0x20, 0x7E}, // Basic Latin
{0xA0, 0xFF}, // Latin-1 Supplement
{0xE000, 0xF8FF}, // Private Use Area
}
for _, rg := range ranges {
for r := rg.start; r <= rg.end; r++ {
glyphIndex, err = f.GlyphIndex(&buffer, r)
if err != nil || glyphIndex == 0 {
continue
}
glyphName, err = f.GlyphName(&buffer, glyphIndex)
if err != nil {
glyphName = fmt.Sprintf("uni%04X", r)
}
segments, err = f.LoadGlyph(&buffer, glyphIndex, ppem, nil)
if err != nil {
fmt.Printf("Failed to load glyph 0x%04X: %v\n", r, err)
continue
}
if len(segments) == 0 {
continue
}
charHex := fmt.Sprintf("%04X", r)
pngFilename := fmt.Sprintf("icon_%s.png", charHex)
svgFilename := fmt.Sprintf("icon_%s.svg", charHex)
// 1. Extract SVG
svgPath := segmentsToSVGPath(segments)
totalHeight := float64(m.Ascent+m.Descent) / 64.0
svgContent := fmt.Sprintf(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 %g %d %g">
<g transform="scale(1, -1)">
<path d="%s" />
</g>
</svg>`, -float64(m.Ascent)/64.0, int(unitsPerEm), totalHeight, svgPath)
if err = os.WriteFile(filepath.Join(*outputDir, svgFilename), []byte(svgContent), 0644); err != nil {
fmt.Printf("Failed to write SVG 0x%s: %v\n", charHex, err)
}
// 2. Render PNG
img := renderGlyphToPNG(segments, int(unitsPerEm), int(m.Ascent), int(m.Descent), *imgSize)
pngFile, err = os.Create(filepath.Join(*outputDir, pngFilename))
if err == nil {
if err = png.Encode(pngFile, img); err != nil {
fmt.Printf("Failed to encode PNG 0x%s: %v\n", charHex, err)
}
pngFile.Close()
} else {
fmt.Printf("Failed to create PNG file 0x%s: %v\n", charHex, err)
}
mapping[r] = IconMapping{
Hex: fmt.Sprintf("0x%s", charHex),
GlyphName: glyphName,
File: pngFilename,
SVGFile: svgFilename,
}
}
}
// Save mapping.json
mappingList := make(map[string]IconMapping)
var keys []int
for r, m := range mapping {
mappingList[fmt.Sprintf("%d", r)] = m
keys = append(keys, int(r))
}
sort.Ints(keys)
jsonData, err := json.MarshalIndent(mappingList, "", " ")
if err != nil {
log.Fatalf("Failed to marshal mapping: %v", err)
}
_ = os.WriteFile(filepath.Join(*outputDir, "mapping.json"), jsonData, 0644)
// Save mapping.md
mdFile, _ := os.Create(filepath.Join(*outputDir, "mapping.md"))
fmt.Fprintln(mdFile, "# Bose Icons Mapping")
fmt.Fprintln(mdFile, "")
fmt.Fprintln(mdFile, "| Char Code | Glyph Name | PNG | SVG |")
fmt.Fprintln(mdFile, "| --- | --- | --- | --- |")
for _, k := range keys {
m := mapping[rune(k)]
fmt.Fprintf(mdFile, "| %s | %s | ![%s](%s) | [SVG](%s) |\n", m.Hex, m.GlyphName, m.GlyphName, m.File, m.SVGFile)
}
mdFile.Close()
fmt.Printf("Extracted %d icons to %s\n", len(mapping), *outputDir)
}
func segmentsToSVGPath(segments sfnt.Segments) string {
var path string
for _, seg := range segments {
switch seg.Op {
case sfnt.SegmentOpMoveTo:
path += fmt.Sprintf("M%g %g ", float64(seg.Args[0].X)/64.0, -float64(seg.Args[0].Y)/64.0)
case sfnt.SegmentOpLineTo:
path += fmt.Sprintf("L%g %g ", float64(seg.Args[0].X)/64.0, -float64(seg.Args[0].Y)/64.0)
case sfnt.SegmentOpQuadTo:
path += fmt.Sprintf("Q%g %g %g %g ", float64(seg.Args[0].X)/64.0, -float64(seg.Args[0].Y)/64.0, float64(seg.Args[1].X)/64.0, -float64(seg.Args[1].Y)/64.0)
case sfnt.SegmentOpCubeTo:
path += fmt.Sprintf("C%g %g %g %g %g %g ", float64(seg.Args[0].X)/64.0, -float64(seg.Args[0].Y)/64.0, float64(seg.Args[1].X)/64.0, -float64(seg.Args[1].Y)/64.0, float64(seg.Args[2].X)/64.0, -float64(seg.Args[2].Y)/64.0)
}
}
return path
}
func renderGlyphToPNG(segments sfnt.Segments, _, _, _, imgSize int) image.Image {
rgba := image.NewRGBA(image.Rect(0, 0, imgSize, imgSize))
draw.Draw(rgba, rgba.Bounds(), image.Transparent, image.Point{}, draw.Src)
// Calculate glyph bounds
var xmin, ymin, xmax, ymax float64
initialized := false
for _, seg := range segments {
for _, arg := range seg.Args {
x, y := float64(arg.X)/64.0, float64(arg.Y)/64.0
if !initialized {
xmin, xmax = x, x
ymin, ymax = y, y
initialized = true
} else {
if x < xmin {
xmin = x
}
if x > xmax {
xmax = x
}
if y < ymin {
ymin = y
}
if y > ymax {
ymax = y
}
}
}
}
w := xmax - xmin
h := ymax - ymin
// If no width/height, return empty image
if w <= 0 || h <= 0 {
return rgba
}
// Calculate scale to fit in imgSize with padding
padding := 20.0
available := float64(imgSize) - 2*padding
scale := available / w
if h*scale > available {
scale = available / h
}
// Center the glyph
// X: center of image (imgSize/2) - (center of glyph (xmin+xmax)/2) * scale
offsetX := float64(imgSize)/2.0 - (xmin+xmax)/2.0*scale
// Y: center of image (imgSize/2) - (center of glyph (ymin+ymax)/2) * scale
offsetY := float64(imgSize)/2.0 - (ymin+ymax)/2.0*scale
scanner := rasterx.NewScannerGV(imgSize, imgSize, rgba, rgba.Bounds())
filler := rasterx.NewFiller(imgSize, imgSize, scanner)
filler.SetColor(color.Black)
for _, seg := range segments {
switch seg.Op {
case sfnt.SegmentOpMoveTo:
filler.Start(fixedP(
offsetX+float64(seg.Args[0].X)/64.0*scale,
offsetY+float64(seg.Args[0].Y)/64.0*scale,
))
case sfnt.SegmentOpLineTo:
filler.Line(fixedP(
offsetX+float64(seg.Args[0].X)/64.0*scale,
offsetY+float64(seg.Args[0].Y)/64.0*scale,
))
case sfnt.SegmentOpQuadTo:
filler.QuadBezier(
fixedP(
offsetX+float64(seg.Args[0].X)/64.0*scale,
offsetY+float64(seg.Args[0].Y)/64.0*scale,
),
fixedP(
offsetX+float64(seg.Args[1].X)/64.0*scale,
offsetY+float64(seg.Args[1].Y)/64.0*scale,
),
)
case sfnt.SegmentOpCubeTo:
filler.CubeBezier(
fixedP(
offsetX+float64(seg.Args[0].X)/64.0*scale,
offsetY+float64(seg.Args[0].Y)/64.0*scale,
),
fixedP(
offsetX+float64(seg.Args[1].X)/64.0*scale,
offsetY+float64(seg.Args[1].Y)/64.0*scale,
),
fixedP(
offsetX+float64(seg.Args[2].X)/64.0*scale,
offsetY+float64(seg.Args[2].Y)/64.0*scale,
),
)
}
}
filler.Stop(true)
filler.Draw()
return rgba
}
func fixedP(x, y float64) fixed.Point26_6 {
return fixed.Point26_6{X: fixed.Int26_6(x * 64), Y: fixed.Int26_6(y * 64)}
}
+103
View File
@@ -0,0 +1,103 @@
package main
import (
"fmt"
"image/png"
"os"
"path/filepath"
"testing"
"golang.org/x/image/font"
"golang.org/x/image/font/sfnt"
"golang.org/x/image/math/fixed"
)
func TestExtractE115(t *testing.T) {
fontPath := "testdata/bose_subset.ttf"
outputDir := "test_output"
refDir := "testdata/references"
imgSize := 256
targetRune := rune(0xE115)
if err := os.MkdirAll(outputDir, 0755); err != nil {
t.Fatalf("Failed to create output directory: %v", err)
}
data, err := os.ReadFile(fontPath)
if err != nil {
t.Fatalf("Failed to read font file: %v", err)
}
f, err := sfnt.Parse(data)
if err != nil {
t.Fatalf("Failed to parse font: %v", err)
}
var buffer sfnt.Buffer
unitsPerEm := f.UnitsPerEm()
ppem := fixed.Int26_6(unitsPerEm) << 6
m, err := f.Metrics(&buffer, ppem, font.HintingNone)
if err != nil {
t.Fatalf("Failed to get metrics: %v", err)
}
glyphIndex, err := f.GlyphIndex(&buffer, targetRune)
if err != nil || glyphIndex == 0 {
t.Fatalf("Failed to find glyph for 0x%X", targetRune)
}
segments, err := f.LoadGlyph(&buffer, glyphIndex, ppem, nil)
if err != nil {
t.Fatalf("Failed to load glyph 0x%X: %v", targetRune, err)
}
charHex := fmt.Sprintf("%04X", targetRune)
pngFilename := fmt.Sprintf("icon_%s.png", charHex)
svgFilename := fmt.Sprintf("icon_%s.svg", charHex)
// 1. Extract SVG
svgPath := segmentsToSVGPath(segments)
totalHeight := float64(m.Ascent+m.Descent) / 64.0
svgContent := fmt.Sprintf(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 %g %d %g">
<g transform="scale(1, -1)">
<path d="%s" />
</g>
</svg>`, -float64(m.Ascent)/64.0, int(unitsPerEm), totalHeight, svgPath)
svgFilePath := filepath.Join(outputDir, svgFilename)
if err = os.WriteFile(svgFilePath, []byte(svgContent), 0644); err != nil {
t.Errorf("Failed to write SVG 0x%s: %v", charHex, err)
}
// 2. Render PNG
img := renderGlyphToPNG(segments, int(unitsPerEm), int(m.Ascent), int(m.Descent), imgSize)
pngFilePath := filepath.Join(outputDir, pngFilename)
pngFile, err := os.Create(pngFilePath)
if err == nil {
if err = png.Encode(pngFile, img); err != nil {
t.Errorf("Failed to encode PNG 0x%s: %v", charHex, err)
}
pngFile.Close()
} else {
t.Errorf("Failed to create PNG file 0x%s: %v", charHex, err)
}
// 3. Compare with references
for _, filename := range []string{svgFilename, pngFilename} {
generated, err := os.ReadFile(filepath.Join(outputDir, filename))
if err != nil {
t.Errorf("Failed to read generated file %s: %v", filename, err)
continue
}
reference, err := os.ReadFile(filepath.Join(refDir, filename))
if err != nil {
t.Errorf("Failed to read reference file %s: %v", filename, err)
continue
}
if string(generated) != string(reference) {
t.Errorf("Mismatch in %s: generated does not match reference", filename)
}
}
}
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M119 -31 L828 678 L871 635 L162 -74 L119 -31 M206 194 L206 405 Q206 426 220 440 Q235 455 256 455 L405 455 L602 654 L668 654 L668 638 L607 572 L430 394 L267 394 L267 204 L269 204 L222 157 Q206 171 206 194 M435 112 L478 155 L607 26 L607 285 L668 345 L668 -56 L602 -56 L435 112 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 404 B

+67
View File
@@ -652,6 +652,73 @@ func listMusicServiceAccounts(c *cli.Context) error {
return nil
}
// pairDevice triggers the Stockholm registration flow via WebSocket
func pairDevice(c *cli.Context) error {
clientConfig := GetClientConfig(c)
client, err := CreateSoundTouchClient(clientConfig)
if err != nil {
return err
}
accountID := c.String("id")
token := c.String("token")
PrintDeviceHeader("Pairing device with Marge account", clientConfig.Host, clientConfig.Port)
fmt.Printf(" Account ID: %s\n", accountID)
// We need a WebSocket client for this
ws := client.NewWebSocketClient(nil)
err = ws.Connect()
if err != nil {
return fmt.Errorf("failed to connect to device WebSocket: %w", err)
}
defer func() { _ = ws.Disconnect() }()
err = ws.PairWithAccount(accountID, token)
if err != nil {
return fmt.Errorf("failed to send pairing request: %w", err)
}
PrintSuccess("Pairing request sent successfully")
fmt.Println("💡 The device will now register itself with the cloud service.")
return nil
}
// unpairDevice triggers the Stockholm unregistration flow via WebSocket
func unpairDevice(c *cli.Context) error {
clientConfig := GetClientConfig(c)
client, err := CreateSoundTouchClient(clientConfig)
if err != nil {
return err
}
PrintDeviceHeader("Unpairing device from Marge account", clientConfig.Host, clientConfig.Port)
// We need a WebSocket client for this
ws := client.NewWebSocketClient(nil)
err = ws.Connect()
if err != nil {
return fmt.Errorf("failed to connect to device WebSocket: %w", err)
}
defer func() { _ = ws.Disconnect() }()
err = ws.UnPairFromAccount()
if err != nil {
return fmt.Errorf("failed to send unpairing request: %w", err)
}
PrintSuccess("Unpairing request sent successfully")
return nil
}
// getServiceDisplayName returns a user-friendly display name for a service
func getServiceDisplayName(source string) string {
switch source {
+2 -2
View File
@@ -196,7 +196,7 @@ var httpClient = &http.Client{
}
func fetchTuneInMetadata(url string) (*Metadata, error) {
if !strings.Contains(url, "tunein.com/radio/") {
if !strings.Contains(url, "tunein.com/radio/") && !strings.Contains(url, "127.0.0.1") && !strings.Contains(url, "localhost") {
return nil, fmt.Errorf("url is not a TuneIn radio URL")
}
@@ -256,7 +256,7 @@ func fetchTuneInMetadata(url string) (*Metadata, error) {
}
func fetchSpotifyMetadata(url string) (*Metadata, error) {
if !strings.Contains(url, "open.spotify.com/") {
if !strings.Contains(url, "open.spotify.com/") && !strings.Contains(url, "127.0.0.1") && !strings.Contains(url, "localhost") {
return nil, fmt.Errorf("url is not a Spotify URL")
}
+4 -4
View File
@@ -7,7 +7,7 @@ import (
)
func TestFetchTuneInMetadata(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
html := `
<!doctype html>
<html>
@@ -30,7 +30,7 @@ func TestFetchTuneInMetadata(t *testing.T) {
defer func() { httpClient = oldClient }()
metadata, err := fetchTuneInMetadata("https://tunein.com/radio/WDR-2-Rheinland-1004-s213886/")
metadata, err := fetchTuneInMetadata(ts.URL + "/radio/WDR-2-Rheinland-1004-s213886/")
if err != nil {
t.Fatalf("fetchTuneInMetadata() error = %v", err)
}
@@ -162,7 +162,7 @@ func TestResolveLocationSpotify(t *testing.T) {
}
func TestFetchSpotifyMetadata(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
html := `
<!doctype html>
<html>
@@ -185,7 +185,7 @@ func TestFetchSpotifyMetadata(t *testing.T) {
defer func() { httpClient = oldClient }()
metadata, err := fetchSpotifyMetadata("https://open.spotify.com/album/7F50uh7oGitmAEScRKV6pD")
metadata, err := fetchSpotifyMetadata(ts.URL + "/album/7F50uh7oGitmAEScRKV6pD")
if err != nil {
t.Fatalf("fetchSpotifyMetadata() error = %v", err)
}
+24
View File
@@ -2038,6 +2038,30 @@ func main() {
},
},
},
{
Name: "pair",
Usage: "Pair the device with a Marge cloud account (Stockholm registration)",
Action: pairDevice,
Before: RequireHost,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "id",
Usage: "Marge account ID (e.g., 1234567)",
Required: true,
},
&cli.StringFlag{
Name: "token",
Usage: "User authorization token",
Required: true,
},
},
},
{
Name: "unpair",
Usage: "Unpair the device from its Marge cloud account",
Action: unpairDevice,
Before: RequireHost,
},
},
},
// Token commands
+2
View File
@@ -677,6 +677,8 @@ func setupRouter(server *handlers.Server) *chi.Mux {
streamingRoutes := func(r chi.Router) {
r.Get("/sourceproviders", server.HandleMargeSourceProviders)
r.Post("/account", server.HandleMargeCreateAccount)
r.Post("/account/login", server.HandleMargeLogin)
r.Get("/account/{account}/device/{device}/recent", server.HandleMargeRecents)
r.Post("/account/{account}/device/{device}/recent", server.HandleMargeAddRecent)
r.Get("/account/{account}/device/{device}/presets", server.HandleMargePresets)
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M101 600 L528 300 L101 1 L101 600 M610 600 L713 600 L713 1 L610 1 L610 600 M795 600 L897 600 L897 1 L795 1 L795 600 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M328 598 L770 299 L328 -1 L328 598 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M338 595 L766 295 L338 -4 L338 595 M659 295 L399 478 L399 113 L659 295 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M305 595 L407 595 L407 -3 L305 -3 L305 595 M590 595 L693 595 L693 -3 L590 -3 L590 595 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 936 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M358 600 L419 600 L419 2 L358 2 L358 600 M584 600 L645 600 L645 2 L584 2 L584 600 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M46 302 L487 601 L487 352 L853 601 L853 2 L487 251 L487 2 L46 302 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M59 295 L486 594 L486 337 L853 594 L853 -5 L486 253 L486 -5 L59 295 M425 477 L165 295 L425 112 L425 477 M792 477 L532 295 L792 112 L792 477 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 269 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M260 598 L363 598 L363 347 L731 598 L731 -1 L363 250 L363 -1 L260 -1 L260 598 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M284 597 L345 597 L345 340 L713 597 L713 -1 L345 257 L345 -1 L284 -1 L284 597 M652 480 L392 299 L652 116 L652 480 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M80 598 L182 598 L182 348 L551 598 L551 349 L918 598 L918 -0 L551 249 L551 -0 L182 250 L182 -0 L80 -0 L80 598 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M98 600 L159 600 L159 343 L527 600 L527 343 L895 600 L895 1 L527 259 L527 1 L159 260 L159 1 L98 1 L98 600 M466 483 L206 301 L466 119 L466 483 M834 483 L573 301 L834 119 L834 483 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M147 600 L514 351 L514 600 L956 301 L514 2 L514 251 L147 2 L147 600 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M145 594 L512 336 L512 594 L939 294 L512 -5 L512 252 L145 -5 L145 594 M466 294 L206 476 L206 112 L466 294 M833 294 L573 476 L573 112 L833 294 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M260 598 L629 347 L629 598 L731 598 L731 -1 L629 -1 L629 250 L260 -1 L260 598 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M284 597 L652 339 L652 597 L713 597 L713 -1 L652 -1 L652 256 L284 -1 L284 597 M605 298 L345 480 L345 116 L605 298 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M80 598 L447 349 L447 598 L815 348 L815 598 L918 598 L918 -0 L815 -0 L815 250 L447 -0 L447 248 L80 -0 L80 598 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M98 599 L465 342 L465 599 L833 341 L833 599 L894 599 L894 1 L833 1 L833 258 L465 1 L465 257 L98 1 L98 599 M419 300 L159 482 L159 118 L419 300 M786 300 L526 482 L526 118 L786 300 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 902 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M200 597 L798 597 L798 -2 L200 -2 L200 597 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M200 597 L798 597 L798 -2 L200 -2 L200 597 M737 59 L737 536 L260 536 L260 59 L737 59 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M155 178 L334 357 L377 314 L271 209 L614 209 Q658 209 695 231 Q732 253 754 290 Q776 327 776 371 Q776 415 754 452 Q732 489 695 511 Q658 533 614 533 L431 533 L431 594 L614 594 Q674 594 725 564 Q777 534 807 482 Q837 431 837 371 Q837 311 807 259 Q777 208 725 178 Q674 148 614 148 L272 148 L379 41 L336 -2 L155 178 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M466 140 L318 140 Q297 140 282 155 Q268 170 268 191 L268 402 Q268 423 282 437 Q297 452 317 452 L467 452 L664 651 L730 651 L730 -59 L664 -59 L466 140 M669 570 L510 410 L492 391 L329 391 L329 201 L492 201 L509 183 L669 23 L669 570 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 358 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M119 -31 L828 678 L871 635 L162 -74 L119 -31 M206 194 L206 405 Q206 426 220 440 Q235 455 256 455 L405 455 L602 654 L668 654 L668 638 L607 572 L430 394 L267 394 L267 204 L269 204 L222 157 Q206 171 206 194 M435 112 L478 155 L607 26 L607 285 L668 345 L668 -56 L602 -56 L435 112 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M238 141 L90 141 Q69 141 54 156 Q39 171 39 191 L39 403 Q39 423 53 438 Q68 453 89 453 L238 453 L435 652 L501 652 L501 -58 L435 -58 L238 141 M440 570 L281 410 L264 392 L100 392 L100 202 L263 202 L440 24 L440 570 M784 272 L665 272 L665 333 L784 333 L784 446 L845 446 L845 333 L964 333 L964 272 L845 272 L845 147 L784 147 L784 272 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M238 141 L90 141 Q69 141 54 156 Q39 171 39 191 L39 403 Q39 423 53 438 Q68 453 89 453 L238 453 L435 652 L501 652 L501 -58 L435 -58 L238 141 M440 570 L281 410 L264 392 L100 392 L100 202 L263 202 L440 24 L440 570 M665 333 L964 333 L964 272 L665 272 L665 333 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M284 189 L170 189 Q154 189 142 200 Q130 212 130 228 L130 392 Q130 408 141 419 Q153 431 169 431 L285 431 L437 585 L488 585 L488 35 L437 35 L284 189 M711 91 Q739 117 770 173 Q802 229 802 309 Q802 388 771 442 Q740 496 711 525 L759 574 Q794 539 831 472 Q869 405 869 308 Q869 211 831 143 Q794 75 760 41 L711 91 M598 211 Q610 221 624 246 Q638 272 638 307 Q638 342 625 365 Q613 388 598 405 L646 453 Q665 434 685 397 Q706 361 706 308 Q706 255 685 218 Q665 181 646 162 L598 211 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 989 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M467 271 L142 271 L142 332 L467 332 L467 656 L528 656 L528 332 L852 332 L852 271 L528 271 L528 -53 L467 -53 L467 271 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 888 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M142 332 L852 332 L852 271 L142 271 L142 332 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M121 100 Q65 133 32 189 Q0 245 0 311 Q0 377 32 433 Q65 489 121 522 Q177 555 243 555 L406 555 L406 652 L588 523 L406 395 L406 494 L243 494 Q194 494 152 469 Q110 445 85 403 Q61 361 61 311 Q61 261 85 219 Q110 177 152 152 Q194 128 244 128 L339 128 Q342 93 352 67 L243 67 Q177 67 121 100 M871 150 Q871 165 870 172 Q901 198 918 234 Q935 270 935 311 Q935 361 910 403 Q885 445 843 469 Q801 494 751 494 L695 494 L695 555 L751 555 Q817 555 873 522 Q929 489 962 433 Q995 377 995 311 Q995 242 960 184 Q925 127 866 96 Q871 124 871 150 M501 -28 Q454 -1 426 46 Q399 94 399 150 Q399 206 426 253 Q454 301 501 328 Q549 356 605 356 Q661 356 708 328 Q755 301 782 253 Q810 206 810 150 Q810 94 782 46 Q755 -1 708 -28 Q661 -56 605 -56 Q549 -56 501 -28 M637 30 L637 270 L602 270 L534 250 L545 209 L587 219 L587 30 L637 30 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 927 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M122 93 Q66 126 33 182 Q0 238 0 304 Q0 370 33 426 Q66 483 122 516 Q179 549 245 549 L420 549 L420 630 L578 518 L420 406 L420 488 L245 488 Q195 488 152 463 Q110 439 85 396 Q61 354 61 304 Q61 255 85 213 Q110 171 152 146 Q195 121 245 121 L303 121 L303 60 L245 60 Q179 60 122 93 M420 91 L578 202 L578 121 L755 121 Q805 121 847 146 Q889 171 914 213 Q939 255 939 304 Q939 354 914 396 Q889 439 847 464 Q805 489 755 489 L698 489 L698 549 L755 549 Q821 549 877 516 Q934 483 967 426 Q1000 370 1000 304 Q1000 239 967 183 Q934 127 877 93 Q821 60 755 60 L578 60 L578 -21 L420 91 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 694 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M798 82 Q664 84 571 146 Q514 183 454 252 Q421 214 392 187 Q364 160 331 138 Q232 73 94 73 L60 73 L60 134 L94 134 Q163 134 217 151 Q269 168 309 197 Q349 226 389 270 Q415 299 414 298 Q368 351 328 385 Q288 419 230 440 Q173 462 94 462 L60 462 L60 523 L94 523 Q230 523 331 458 Q364 436 392 409 Q421 382 454 344 Q479 373 517 409 L521 412 Q539 428 571 450 Q666 513 798 514 L798 595 L956 484 L798 372 L798 453 Q724 452 669 431 Q615 411 576 379 Q537 347 495 298 Q538 249 576 216 Q615 184 669 163 Q724 143 798 143 L798 224 L956 112 L798 -0 L798 82 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M156 310 L501 655 L845 310 L802 267 L501 569 L199 267 L156 310 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M156 292 L199 335 L501 33 L802 335 L845 292 L501 -53 L156 292 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M145 300 L490 645 L533 601 L231 300 L533 -2 L490 -45 L145 300 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M467 -2 L768 300 L467 601 L510 645 L855 300 L510 -45 L467 -2 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M457 452 L200 452 L200 513 L798 513 L798 452 L539 452 L798 84 L200 84 L457 452 M681 145 L498 405 L317 145 L681 145 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M200 145 L458 145 L200 513 L798 513 L541 145 L798 145 L798 84 L200 84 L200 145 M681 452 L317 452 L499 192 L681 452 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M143 223 L186 266 L346 106 L819 579 L862 536 L346 20 L143 223 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M500 513 L799 85 L201 85 L500 513 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M201 513 L799 513 L500 85 L201 513 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M286 299 L714 598 L714 -0 L286 299 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M285 598 L713 299 L285 -0 L285 598 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M500 614 L798 187 L200 187 L500 614 M200 85 L799 85 L799 -17 L200 -17 L200 85 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -765 1000 924">
<g transform="scale(1, -1)">
<path d="M413 213 Q378 249 378 299 Q378 349 413 384 Q449 420 499 420 Q549 420 584 384 Q619 349 619 299 Q619 249 584 213 Q549 178 499 178 Q449 178 413 213 M162 256 Q144 274 144 299 Q144 324 162 342 Q180 360 205 360 Q230 360 248 342 Q266 324 266 299 Q266 274 248 256 Q230 238 205 238 Q180 238 162 256 M749 256 Q732 274 732 299 Q732 324 749 342 Q767 360 792 360 Q817 360 835 342 Q853 324 853 299 Q853 274 835 256 Q818 238 792 238 Q767 238 749 256 " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 564 B

Some files were not shown because too many files have changed in this diff Show More