Deployed 91db1fa with MkDocs version: 1.6.1

This commit is contained in:
2026-09-24 16:18:52 +00:00
parent b2747f3329
commit 1ab97c836f
7 changed files with 139 additions and 50 deletions
+42 -4
View File
@@ -1914,6 +1914,17 @@
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#slow-responses" class="md-nav__link">
<span class="md-ellipsis">
Slow responses
</span>
</a>
</li>
<li class="md-nav__item">
@@ -2785,6 +2796,17 @@
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#slow-responses" class="md-nav__link">
<span class="md-ellipsis">
Slow responses
</span>
</a>
</li>
<li class="md-nav__item">
@@ -2999,7 +3021,7 @@
<li><strong>Authentication.</strong> Every request except <code>GET /api/health</code> requires the <code>X-Secret-Key</code> header when you configure an API key. <code>--no-key</code> disables the check entirely. See <a href="../authentication/">Authentication</a>.</li>
<li><strong>Content type.</strong> Request bodies are JSON (<code>Content-Type: application/json</code>). All success responses are JSON unless this page documents a <code>204 No Content</code>.</li>
<li><strong>CORS.</strong> Every response carries permissive CORS headers, and the server answers <code>OPTIONS</code> preflight requests automatically.</li>
<li><strong>Compression.</strong> JSON responses of 256 bytes or more are gzip-compressed when the client sends <code>Accept-Encoding: gzip</code>.</li>
<li><strong>Compression.</strong> JSON responses of 256 bytes or more are gzip-compressed when the client sends <code>Accept-Encoding: gzip</code>. A <a href="#slow-responses">slow response</a> is not compressed.</li>
<li><strong>Service allowlist.</strong> The effective allowlist for your API key filters the service-facing endpoints (the intersection of the global <code>serve.services</code> list and your per-key list). The server treats services you cannot use as unknown.</li>
</ul>
<div class="admonition warning">
@@ -4647,6 +4669,20 @@ an HTTP caller would be remote code execution. You configure post-scripts only i
</span><span id="__span-28-8"><a id="__codelineno-28-8" name="__codelineno-28-8" href="#__codelineno-28-8"></a>POST /api/session/{id}/keys/bad → report a server-vault content key that did not decrypt
</span><span id="__span-28-9"><a id="__codelineno-28-9" name="__codelineno-28-9" href="#__codelineno-28-9"></a>DELETE /api/session/{id} → tear down, harvest updated cache
</span></code></pre></div>
<h3 id="slow-responses">Slow responses<a class="headerlink" href="#slow-responses" title="Permanent link">&para;</a></h3>
<p>The <code>titles</code>, <code>tracks</code> and <code>license</code> routes can take minutes on a large catalogue. When the
answer is not ready after 30 seconds, the route sends status <code>200</code> and the headers. It then
sends a newline every 30 seconds until the JSON body is ready. JSON parsers ignore the leading
newlines. This keeps the connection open through a reverse proxy that closes an idle request.</p>
<div class="admonition warning">
<p class="admonition-title">A late failure has status <code>200</code></p>
<p>The server sent the status before the work ended. A failure after the first 30 seconds
arrives as the <a href="../errors/#the-standard-error-shape">standard error body</a> with status <code>200</code>.
Check <code>status</code> in the body, not only the HTTP status. The body has no HTTP status field.
Use <code>error_code</code> and <code>retryable</code> to decide what to do.</p>
</div>
<p>A slow response is not gzip-compressed. Gzip output cannot start before the body is ready, and
the newlines must go out at once.</p>
<h3 id="post-apisessioncreate"><code>POST /api/session/create</code><a class="headerlink" href="#post-apisessioncreate" title="Permanent link">&para;</a></h3>
<p>Make a remote session for a service and title. Authentication runs asynchronously in the background. This call returns immediately with <code>status: "authenticating"</code>, and you then poll the prompt endpoint. The body accepts <code>service</code> and <code>title_id</code> (both required). It also accepts a broad set of optional keys, because the body allows <code>additionalProperties</code>. These are <code>credentials</code> (<code>{username, password, extra?}</code>), <code>cookies</code> (base64 of zlib-compressed Netscape cookie file), <code>proxy</code>, <code>no_proxy</code>, <code>profile</code>, <code>cache</code> (map of forwarded cache files, keyed by the file path relative to the service cache directory with <code>/</code> separators and no <code>.json</code> suffix, so a nested key such as <code>session_web/&lt;sha1&gt;</code> lands in a subdirectory), <code>client_region</code>, <code>proxy_region</code>, <code>cdm_type</code>, <code>range_</code>, <code>vcodec</code>, <code>quality</code>, <code>best_available</code>, <code>dl_params</code>, <code>client</code>, and any service CLI options. <code>proxy_region</code> is the country code the client resolved <code>proxy</code> from; the server matches it against its own accounts. <code>client</code> is a freeform object the dashboard shows as sent (the CLI puts <code>version</code>, <code>code_hash</code>, <code>platform</code> and a redacted <code>argv</code> in it); the server ignores it above 4096 bytes of JSON.</p>
<p><code>dl_params</code> is an object with the <code>dl</code> track selection: <code>lang</code>, <code>v_lang</code> and <code>a_lang</code> (arrays of language strings), <code>acodec</code> (an array of audio codec names or <code>dl -a</code> aliases such as <code>ddp</code>) and <code>forced_subs</code> (boolean). The service reads these values from <code>ctx.parent.params</code>. The server uses the <code>dl</code> default for each absent or malformed value, and drops an unknown codec name.</p>
@@ -4816,7 +4852,8 @@ an HTTP caller would be remote code execution. You configure post-scripts only i
</table>
<p>The buffer keeps the newest 500 records. Only the service instance's own logger is mirrored; core pipeline loggers stay on the server. A server-account session gets no log relay at all - auth-time service output can carry the operator account's identity, so it stays server-side.</p>
<h3 id="get-apisessionsession_idtitles"><code>GET /api/session/{session_id}/titles</code><a class="headerlink" href="#get-apisessionsession_idtitles" title="Permanent link">&para;</a></h3>
<p>Fetch the titles for an authenticated remote session.</p>
<p>Fetch the titles for an authenticated remote session.
A slow answer arrives as a <a href="#slow-responses">slow response</a>.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="23:1"><input checked="checked" id="__tabbed_23_1" name="__tabbed_23" type="radio" /><div class="tabbed-labels"><label for="__tabbed_23_1">Response <code>200</code></label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@@ -4830,7 +4867,7 @@ an HTTP caller would be remote code execution. You configure post-scripts only i
</div>
<p>Requires an authenticated remote session. Otherwise it returns <code>404 SESSION_NOT_FOUND</code>.</p>
<h3 id="post-apisessionsession_idtracks"><code>POST /api/session/{session_id}/tracks</code><a class="headerlink" href="#post-apisessionsession_idtracks" title="Permanent link">&para;</a></h3>
<p>Get tracks and chapters for a specific title within the remote session. Body: <code>{ "title_id": "..." }</code> (required). Unlike <code>list-tracks</code>, track objects here <strong>include</strong> download URLs, along with session headers/cookies and manifest data the client needs to download directly.</p>
<p>Get tracks and chapters for a specific title within the remote session. Body: <code>{ "title_id": "..." }</code> (required). Unlike <code>list-tracks</code>, track objects here <strong>include</strong> download URLs, along with session headers/cookies and manifest data the client needs to download directly. A slow answer arrives as a <a href="#slow-responses">slow response</a>.</p>
<p><code>manifests</code> holds each served DASH/ISM manifest once. A service can build an AdaptationSet of its own that the served manifest does not contain. <code>track_manifests</code> holds a one-AdaptationSet MPD for each such track, and the client re-parses that in place of the whole manifest.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="24:1"><input checked="checked" id="__tabbed_24_1" name="__tabbed_24" type="radio" /><div class="tabbed-labels"><label for="__tabbed_24_1">Response <code>200</code></label></div>
<div class="tabbed-content">
@@ -4960,7 +4997,8 @@ an HTTP caller would be remote code execution. You configure post-scripts only i
</tbody>
</table>
<h3 id="post-apisessionsession_idlicense"><code>POST /api/session/{session_id}/license</code><a class="headerlink" href="#post-apisessionsession_idlicense" title="Permanent link">&para;</a></h3>
<p>Get the content keys for the DRM. The <code>mode</code> field selects one of two modes.</p>
<p>Get the content keys for the DRM. The <code>mode</code> field selects one of two modes.
A slow answer arrives as a <a href="#slow-responses">slow response</a>.</p>
<p><strong>Proxy mode</strong> (<code>mode: "proxy"</code>, the default) forwards the client's CDM <code>challenge</code> to the service's license endpoint and returns the raw license bytes:</p>
<div class="tabbed-set tabbed-alternate" data-tabs="27:2"><input checked="checked" id="__tabbed_27_1" name="__tabbed_27" type="radio" /><input id="__tabbed_27_2" name="__tabbed_27" type="radio" /><div class="tabbed-labels"><label for="__tabbed_27_1">Request</label><label for="__tabbed_27_2">Response <code>200</code></label></div>
<div class="tabbed-content">
+35 -1
View File
@@ -1804,6 +1804,17 @@
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#late-failures-with-status-200" class="md-nav__link">
<span class="md-ellipsis">
Late failures with status 200
</span>
</a>
</li>
<li class="md-nav__item">
@@ -2198,6 +2209,17 @@
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#late-failures-with-status-200" class="md-nav__link">
<span class="md-ellipsis">
Late failures with status 200
</span>
</a>
</li>
<li class="md-nav__item">
@@ -2627,6 +2649,17 @@ body that uses an integer <code>status</code> and no <code>error_code</code> or
(integer <code>status</code>, no <code>error_code</code>). The <code>GET /api/health</code> endpoint is exempt
from authentication, so it never returns the key-error shape.</p>
</div>
<h2 id="late-failures-with-status-200">Late failures with status <code>200</code><a class="headerlink" href="#late-failures-with-status-200" title="Permanent link">&para;</a></h2>
<p>The remote session <code>titles</code>, <code>tracks</code> and <code>license</code> routes send status <code>200</code> and the headers
when the work takes longer than 30 seconds. They then send a newline every 30 seconds to keep
the connection open. See <a href="../endpoints/#slow-responses">Slow responses</a>. A failure after that
time arrives as the standard error body, but with status <code>200</code>. The body has no field for the
HTTP status that the error would otherwise have. <code>error_code</code> and <code>retryable</code> stay in the body.</p>
<div class="admonition warning">
<p class="admonition-title">Check the body on these routes</p>
<p>On these routes a <code>200</code> does not always mean success. Parse the body and treat
<code>"status": "error"</code> with an <code>error_code</code> as a failure.</p>
</div>
<h2 id="responses-with-no-body">Responses with no body<a class="headerlink" href="#responses-with-no-body" title="Permanent link">&para;</a></h2>
<p>Not every failure or completion has a JSON body. Some endpoints answer with
<strong><code>204 No Content</code></strong> and an empty body, notably deleting a terminal download job and
@@ -2676,7 +2709,8 @@ debugging, never on a server reachable by untrusted clients.</p>
<div class="admonition note">
<p class="admonition-title">Reference consumer</p>
<p>unshackle's own remote-download client treats any status of <code>400</code> or above as
fatal: it logs <code>Server error [&lt;error_code&gt;]: &lt;message&gt;</code> and exits. It also wraps
fatal, and a <code>200</code> body with <code>"status": "error"</code> and an <code>error_code</code> too: it logs
<code>Server error [&lt;error_code&gt;]: &lt;message&gt;</code> and exits. It also wraps
requests in a retry adapter (five attempts, backing off on <code>429</code>, <code>500</code>, <code>502</code>,
<code>503</code>, and <code>504</code>). This is a reasonable template for your own client's error
handling.</p>
+17 -5
View File
@@ -2646,12 +2646,12 @@ generally never touch this directly, but it explains behaviour you might observe
<tr>
<td>Idle session TTL</td>
<td><strong>300s</strong> (5 min) default</td>
<td>Refreshed on every request to the session</td>
<td>Refreshed on every request to the session and when a <code>titles</code> or <code>tracks</code> request ends. A remote session does not expire while a request works on it</td>
</tr>
<tr>
<td>Max concurrent sessions</td>
<td><strong>100</strong> default</td>
<td>Oldest (least recently used) is evicted when full</td>
<td>Oldest (least recently used) is evicted when full. A remote session that a request works on goes last</td>
</tr>
<tr>
<td>Auth/input timeout</td>
@@ -2827,6 +2827,9 @@ layer.</p>
<li><code>InputBridge.request_input(prompt, timeout=600)</code> blocks the sync auth thread on a
<code>threading.Event</code> until <code>submit_response()</code> or <code>cancel()</code> fires.</li>
<li>A timeout raises <code>TimeoutError</code> and marks the remote session <code>FAILED</code>.</li>
<li>A prompt after authentication (in <code>get_titles()</code>, <code>get_tracks()</code> or licensing) raises
<code>RuntimeError</code> at once. The client polls for prompts only during authentication, so
no answer can come.</li>
<li><code>AUTH_INPUT_TIMEOUT = 600.0</code> seconds. This is also the TTL granted to
<code>AUTHENTICATING</code> / <code>PENDING_INPUT</code> sessions in the store.</li>
</ul>
@@ -2956,9 +2959,18 @@ seconds left before this specific remote session expires.</p>
remote session API and a good template for any client.</p>
<ul>
<li><strong><code>RemoteClient.request</code></strong> sets <code>X-Secret-Key</code> and <code>User-Agent: unshackle/&lt;version&gt;</code>,
uses a 120s timeout for <code>POST</code> and 30s for <code>GET</code>/<code>DELETE</code>, and treats any
<code>status_code &gt;= 400</code> as fatal: it logs <code>Server error [&lt;error_code&gt;]: &lt;message&gt;</code>
and raises <code>SystemExit(1)</code>.</li>
uses the server's <code>timeout</code> from <code>remote_services</code> (default 120s) as the read timeout,
and treats any <code>status_code &gt;= 400</code> as fatal: it logs <code>Server error [&lt;error_code&gt;]: &lt;message&gt;</code>
and raises <code>SystemExit(1)</code>. A <code>200</code> body with <code>"status": "error"</code> is also fatal (see
the heartbeat below).</li>
<li><strong>Heartbeat.</strong> The <code>titles</code>, <code>tracks</code> and <code>license</code> routes send a newline every 30s while
the service works. The read timeout starts again at each byte, so a slow request stays
open for as long as the server works on it, and a reverse proxy does not close it as
idle. A route that answers within 30s sends the usual response. After 30s the status
is already <code>200</code>, so a failure after that time arrives as the usual error body with
status <code>200</code>. Your client must check <code>status</code> in the body. JSON parsers ignore the
leading newlines. The server does not gzip-compress a heartbeat response, because gzip
output cannot start before the body is ready.</li>
<li><strong>Retries.</strong> The download-side HTTP session mounts an adapter with
<code>Retry(total=5, backoff_factor=0.2, status_forcelist=[429, 500, 502, 503, 504])</code>.</li>
<li><strong>Flow.</strong> <code>authenticate()</code> → <code>create</code> (+ poll <code>prompt</code> every 2s up to a 600s
+6 -1
View File
@@ -2171,7 +2171,7 @@ to the normal file-based cookie path (<code>cookies/&lt;SERVICE&gt;.txt</code> o
<p>Definitions of remote unshackle service servers, used by the <code>--remote</code> mode. Each entry is
named by you (pick it with <code>--server</code>, or do not write that flag when you configure only one) and gives
the server's <code>url</code> (required), an optional <code>api_key</code>, an optional <code>auth_headers</code> list, an
optional <code>server_cdm</code> boolean, and an optional <code>services</code> sub-dict of per-service local
optional <code>server_cdm</code> boolean, an optional <code>timeout</code> in seconds, and an optional <code>services</code> sub-dict of per-service local
overrides such as <code>title_map</code>.</p>
<p>Leave <code>server_cdm</code> unset and the client follows the server: it uses the server CDM for each
service the API key has it on, and the local CDM for the others. <code>true</code> asks for the server CDM
@@ -2182,6 +2182,11 @@ first name. If the server answers <code>401</code>, it retries the same request
keeps the one that works for the rest of the HTTP session. Names you give keep your spelling and
are not repeated in the fallbacks, so unshackle tries
<code>auth_headers: ["Authorization", "x-secret-key"]</code> as <code>Authorization</code>, <code>x-secret-key</code>, <code>X-Api-Key</code>.</p>
<p><code>timeout</code> is the time in seconds that the client waits for data from the server. The
default is <code>120</code>. The server sends a heartbeat every 30 seconds while it gets titles, tracks
or licences, so a slow service does not cause a timeout. Increase <code>timeout</code> only when the
server runs an older version that sends no heartbeat. Give a number of seconds. With a
value below 30 the client can time out before the first heartbeat. <code>0</code> means the default.</p>
<p>In <code>--remote</code> mode unshackle turns the server's service list into synthetic CLI
commands that operate against it, falling back to the tags in that <code>services</code> sub-dict when
unshackle cannot fetch the list. Each synthetic command carries the server-side service's options and
File diff suppressed because one or more lines are too long
+38 -38
View File
@@ -2,154 +2,154 @@
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://docs.unshackle.dev/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/dev/creating-a-service/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/dev/service-architecture/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/dev/rest-api/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/dev/rest-api/authentication/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/dev/rest-api/dashboard/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/dev/rest-api/endpoints/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/dev/rest-api/errors/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/dev/rest-api/job-lifecycle/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/dev/rest-api/quickstart/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/dev/rest-api/remote-sessions/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/getting-started/configuration-file/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/getting-started/installation/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/getting-started/quickstart/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/guide/cli-reference/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/guide/downloading/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/guide/drm-and-cdm/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/guide/output-and-naming/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/guide/proxies-and-vpn/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/guide/subtitles/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/guide/troubleshooting/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/guide/vaults/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/reference/api/config/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/reference/api/drm/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/reference/api/service/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/reference/api/titles/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/reference/api/tracks/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/reference/configuration/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/reference/configuration/directories/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/reference/configuration/download/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/reference/configuration/drm/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/reference/configuration/example/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/reference/configuration/misc/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/reference/configuration/network/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/reference/configuration/output/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/reference/configuration/post-scripts/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/reference/configuration/services/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
<url>
<loc>https://docs.unshackle.dev/reference/configuration/vaults/</loc>
<lastmod>2026-09-23</lastmod>
<lastmod>2026-09-24</lastmod>
</url>
</urlset>
BIN
View File
Binary file not shown.