{"id":13474408,"url":"https://github.com/peaBerberian/wasp-hls","last_synced_at":"2025-03-26T21:31:34.237Z","repository":{"id":88290998,"uuid":"496337068","full_name":"peaBerberian/wasp-hls","owner":"peaBerberian","description":"WebAssembly-based (Rust) \u0026 in-worker HLS Media Player for the web","archived":false,"fork":false,"pushed_at":"2024-09-01T19:08:52.000Z","size":6898,"stargazers_count":137,"open_issues_count":5,"forks_count":4,"subscribers_count":6,"default_branch":"main","last_synced_at":"2024-10-30T07:47:49.459Z","etag":null,"topics":["hls","mediasource","mediasource-extensions","mse","player-video","webassembly"],"latest_commit_sha":null,"homepage":"https://peaberberian.github.io/wasp-hls/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/peaBerberian.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-05-25T17:56:04.000Z","updated_at":"2024-10-30T05:42:27.000Z","dependencies_parsed_at":null,"dependency_job_id":"d4066dca-2c39-447e-8dc3-ef5a6400e171","html_url":"https://github.com/peaBerberian/wasp-hls","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peaBerberian%2Fwasp-hls","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peaBerberian%2Fwasp-hls/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peaBerberian%2Fwasp-hls/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peaBerberian%2Fwasp-hls/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/peaBerberian","download_url":"https://codeload.github.com/peaBerberian/wasp-hls/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245738656,"owners_count":20664324,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hls","mediasource","mediasource-extensions","mse","player-video","webassembly"],"created_at":"2024-07-31T16:01:12.132Z","updated_at":"2025-03-26T21:31:33.577Z","avatar_url":"https://github.com/peaBerberian.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","HarmonyOS"],"sub_categories":["Windows Manager"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg height=\"100px\" src=\"https://user-images.githubusercontent.com/8694124/231414483-eb38f21a-68bf-41b9-98f7-2c8012e2d52e.png#gh-light-mode-only\" alt=\"Wasp-hls's logo\"/\u003e\n  \u003cimg height=\"100px\" src=\"https://user-images.githubusercontent.com/8694124/231414514-9742e81b-bc4f-4af2-99be-35154c0281cc.png#gh-dark-mode-only\" alt=\"Wasp-hls's logo\"/\u003e\n  \u003cbr /\u003e\u003cbr /\u003e\n  \u003ca href=\"https://peaberberian.github.io/wasp-hls/doc/Getting_Started/Welcome.html\"\u003e🎓 \u003cb\u003eGetting Started\u003c/b\u003e\u003c/a\u003e\n  -\n  \u003ca href=\"https://peaberberian.github.io/wasp-hls/\"\u003e⏯ \u003cb\u003eDemo\u003c/b\u003e\u003c/a\u003e\n  -\n  \u003ca href=\"https://peaberberian.github.io/wasp-hls/doc/API/Overview.html\"\u003e📖 \u003cb\u003eAPI documentation\u003c/b\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nWasp-hls is an [HLS](https://en.wikipedia.org/wiki/HTTP_Live_Streaming) media\nplayer (the library, streaming engine part, not the UI/application part which has\nto be built on top of it) for the web which:\n\n1. Relies the most possible on [WebAssembly](https://webassembly.org/) (Written\n   in the [Rust](https://www.rust-lang.org/) language before being compiled).\n\n2. Runs mostly in a [Web Worker](https://en.wikipedia.org/wiki/Web_worker) (even\n   for media buffering when APIs are available), to reduce the influence an\n   heavy UI can have on playback (and in some situations vice-versa).\n\nNote that this is only a personal project as well as a proof of concept and it\nis still heavily in development.\n\n## What's this exactly? HLS?\n\n### Streaming protocols and HLS\n\nTo provide media contents at large scale to their customers, most streaming\nactors (Netflix, Amazon Prime Video, YouTube, Twitch, Canal+, Disney+ etc. you\ngot it), rely on the few same HTTP-based adaptive bitrate streaming protocols:\nmajoritarily [MPEG-DASH](https://en.wikipedia.org/wiki/Dynamic_Adaptive_Streaming_over_HTTP)\nand Apple's [HLS](https://en.wikipedia.org/wiki/HTTP_Live_Streaming) (some rely\non only one like Twitch with HLS, others may rely on both depending on the case).\n\nThose protocols all have similar concepts: all expose a central file listing the\ncharacteristics of the content (for example, the video qualities, audio tracks,\nthe available subtitles etc.) and allow a client to request the media through\nsmall chunks, each containing only the wanted quality and track for a specific\ntime period.\n\n![de18e941-81de-482f-843d-834a4dd3aa71](https://user-images.githubusercontent.com/8694124/229379027-443a68ee-b818-4fdf-b9fe-db64fd88b5d8.png)\n_Schema of how HLS basically works, found on Apple's Website which is the one\nbehind HLS_\n\nThis architecture allows to:\n\n- only load the wanted media data (thus not e.g. also loading all unwanted\n  audio tracks with it)\n- allows efficient seeking on the content, by allowing to load the content\n  non-sequentially (e.g. you can directly load the data corresponding to the end\n  of the content if you want to).\n- facilitate live streaming by continuously encoding those chunk and adding it\n  to the central file progressively\n- profit from all the goodies of relying on HTTP(S) for content distribution\n  (compatibility with the web, firewall traversal, lots of tools available etc.)\n\nFor HLS specifically, this so-called central file is called the \"Multivariant\nPlaylist\" (a.k.a. \"Master Playlist\") and is in the [`M3U8` file\nformat](https://en.wikipedia.org/wiki/M3U).\nHLS also has the concept of secondary \"Media Playlists\", also as `M3U8` files,\nwhich describe specific tracks and qualities.\n\n### The Media Source Extensions™\n\nTo allow the implementation of such adaptive streaming media players on the web\n(and thus with JavaScript), a W3C recommendation was written: the [Media Source\nExtensions™ recommendation](https://www.w3.org/TR/media-source/), generally just\nabbreviated to \"MSE\".\n\n[Basically](https://www.w3.org/TR/media-source/#introduction), it builds on top\nof the HTML5 `\u003cvideo\u003e` element, adding a new set of browser API accessible from\nJavaScript to create media buffers, called `SourceBuffer`s, and allowing to push\naforementioned small chunks of media data to it for later decoding.\n\n### The media player library\n\nThe role of an HLS media player library like this one is thus to load the\nMultivariant Playlist, detect which characteristics (bandwidth, quality,\ncodecs, preferred language, accessibility etc.) are wanted and to load the right\nmedia data at the right time, then communicating it to the browser through the\nMSE APIs so it can be decoded.\n\n![twitch-wasp](https://user-images.githubusercontent.com/8694124/229379280-c9d7d810-eb32-415c-bdb2-6888a6accd4e.png)\n_The Wasp-hls player reading a Multivariant playlist from Twitch. You can see\non the top right the requests performed - mostly of media segments, and some\nlogs on the bottom right. You can also see a cog logo before the requests' url\nindicating that they are all performed in a WebWorker._\n\nThis may look relatively simple at first, but there's a lot of potential\noptimizations to make and special cases to handle which make quasi-mandatory\nthe need to develop separately the media streaming library (the part\n\"understanding\" the streaming protocol and pushing chunks) and the application\n(the part relying on the library and implementing an UI and the business logic\non top).\n\nMost people generally mean the latter when they talk about a \"player\", here,\nI'm \"only\" implementing the former and the application has to be developped\nseparately.\n\nThe [demo page](https://peaberberian.github.io/wasp-hls/) do also implement a UI\npart, but this is just to showcase the library and is not actually what's\nexposed by this package, only the library is (though you can copy the demo's\ncode if you want to).\n\n### What's WebWorker and WebAssembly doing with all that?\n\nAmongst the main characteristics of this player is that it relies on a\nWebWorker, to run concurrently with the application, and WebAssembly, to do so\noptimally.\nIt thus allows to have a theoretically efficient media player, allowing to\navoid stalling in the content if the UI do some heavy lifting and vice-versa.\n\nThis is even more important when playing what is called \"low-latency contents\"\n(contents with a small-ish latency between the recording and the watch-ing, in\nthe few seconds range) which have amongst its characteristics the fact that only\nvery small data buffers are constructed - allowing to play closer to live but\nmore exposed to rebuffering risk if the segment loading pipeline takes more\ntime than expected).\n\nPlaying low-latency contents is one of the main goal of this project. On that\nmatter as an amusing note, playing low-latency contents through a media player\nwith a WebWorker + WebAssembly combination is exactly what Twitch is doing,\nthough their players isn't open-source. This one is (it's also able to play\nTwitch contents if you succeed to work-around their CORS policy, only not with\nlow-latency for now)!\n\nEven without taking into account low-latency contents, I consider WebAssembly to\nbe particularly adapted for an adaptive media player:\n\n- Such software generally handle large objects (not only talking about media\n  segments here). The relatively few controls JavaScript offers in terms of\n  memory management can be problematic (I've seen GC-pressure related issues\n  on another player I work on for example).\n\n  With WebAssembly and a source language with enough control over memory\n  management, GC-linked issues disappear (because no GC :p!) and the\n  application's memory usage is much more explicit and controlled, which is\n  usually what we want.\n\n- Even if there's a lot of input/output and thus the need to interact with\n  JavaScript, the performance profile is completely different than your usual\n  JS front-end application: very few DOM access here, a lot of time is spent\n  on parsing/transmuxing and other logic that can be completely implemented in\n  WebAssembly.\n\n### Generating an HLS content\n\nBecause this is just the player part, the HLS content has to be prepared -\nthrough what we call the packaging step - separately by using what's called a\n\"packager\".\n\nFor example the [shaka-packager](https://github.com/shaka-project/shaka-packager)\nis a relatively easy to use packager. With it and [FFmpeg](https://ffmpeg.org/),\nyou are armed with the right tools to produce HLS contents.\n\n## Why starting this project?\n\nI'm currently working as the lead developper of another, featureful adaptive\nmedia player library, the open-source [RxPlayer](https://github.com/canalplus/rx-player)\nso this is not something totally out of the blue.\n\nThe reasons why I started this project are mainly:\n\n- to see how IO-heavy logic (like we have here with many requests, media\n  segments streaming, playback observation, network metrics etc.) using web\n  APIs only exposed to JavaScript could be conjugated with WebAssembly and\n  Rust.\n\n- to experiment with a big-enough WebAssembly and Web Worker-based library:\n  how should it interact with applications written in JavaScript?\n\n- to learn more about the HLS streaming protocol, for which the RxPlayer does\n  not provide first class support (yet?)\n\n- to see how I would write a complex beast like a Media player if restarting\n  from scratch (though the situation is very different here, due to the\n  difference in the language used).\n\n- to see if there's any real performance and/or memory related advantage (or\n  disadvantage) in relying on WebAssembly for the core logic of a media\n  player, in various situations (multiple players on the same page, large 4k\n  segments, web workers, mse-in-worker).\n\n- to play with a Web Worker-based media player, and find out its influence\n  in terms of API definition, synchronization difficulties, performance issues\n  etc.\n\n- to work on and improve my Rust skills\n\n## What's done\n\nIt already has a lot of features but there's still some left work:\n\nType of contents:\n\n- [x] Play HLS VoD contents\n- [x] Play HLS live contents _(for now require presence of\n      `EXT-X-PROGRAM-DATE-TIME` tag in media playlist)_\n- [ ] Proper support of HLS low-latency contents.\n      _Priority: average_\n\nWorker-related features:\n\n- [x] Load content-related resources and run main logic loop in worker\n- [x] Use MSE-in-Worker when available\n- [x] Rely on main thread for MSE when MSE-in-Worker is not available\n\nAdaptive BitRate:\n\n- [x] Choose variant based on throughtput-based estimates\n- [x] Allow application to list and select its own variant (quality) and know\n      the current one\n- [x] Automatically filter out codecs not supported by the current environment.\n- [x] Urgent/non-urgent quality switches (Some quality switches lead to request\n      for segments of the previous quality to be immediately interrupted, others\n      await them before actually switching).\n- [x] Fast-switching (Push on top of already-loaded segments if they prove to be\n      of higher quality - and are sufficiently far from playback to prevent\n      rebuffering).\n- [x] Smart-switching (I just made-up the name here :D, but basically it's for\n      the opposite situation than the one in which fast-switching is active:\n      don't re-load segments who're already loaded or being pushed with a higher\n      quality).\n- [ ] Also choose variant based on buffer-based estimates.\n      _Priority: average_\n- [ ] Logic to detect sudden large fall in bandwidth before the end of a current\n      request.\n      _Priority: average_\n\nRequest Scheduling:\n\n- [x] Lazy Media Playlist downloading (only fetch and refresh them once they are\n      needed)\n- [x] Media Playlist refreshing for live contents\n- [x] Buffer goal implementation (as in: stop loading segments once enough to\n      fill the buffer up to a certain - configurable - point are loaded)\n- [x] Parallel audio and video segment loading\n- [x] Priorization between audio and video segment requests (to e.g. stop\n      doing audio segment requests when video ones become urgent).\n- [x] Retry of failed requests with an exponential backoff.\n- [x] Perform range requests for segments if needed\n- [ ] Parallel initialization segment and first media segment loading.\n      _Priority: average_\n\nMedia demuxing:\n\n- [x] Media Segment Format: MPEG-2 Transport Streams\n- [x] Media Segment Format: Fragmented MPEG-4\n- [x] Media Segment Format: Packed Audio AAC with ADTS framing\n- [x] Transmux MPEG-2 Transport Streams to fmp4 on platforms not supporting the\n      former like mostChrome or Firefox (through JS for now, Rust implementation\n      pending).\n- [ ] WebAssembly-based mpeg2-ts transmuxer.\n      _Priority: average_\n- [ ] Media Segment Format: Packed Audio MP3\n      _Priority: low_\n- [ ] Media Segment Format: Packed Audio AC-3\n      _Priority: low_\n- [ ] Media Segment Format: Packed Audio EAC-3\n      _Priority: low_\n- [ ] Media Segment Format: WebVTT (subtitles not handled for now)\n      _Priority: low_\n- [ ] Media Segment Format: IMSC Subtitles (subtitles not handled for now)\n      _Priority: low_\n\nMSE API and buffer handling:\n\n- [x] End of stream support (as in: actually end when playback reaches the end!)\n- [x] Multiple simultaneous type of buffers support (for now only audio and\n      video, through MSE `SourceBuffer`s)\n- [x] One and multiple initialization segments handling per rendition\n- [x] Lazy buffer memory management: Don't manually remove old buffers' media\n      data if the browser thinks it's fine. Many players clean it up\n      progressively as it also simplifies the logic (e.g. browser GC detection\n      might become unneeded) but I like the idea of keeping it to e.g. allow\n      seek-back without rebuffering if the current device allows it.\n- [x] Detect browser Garbage Collection of buffered media and re-load GCed\n      segments if they are needed again.\n- [x] Discontinuity handling: Automatically skip \"holes\" in the buffer where\n      it is known that no segment will be pushed to fill them.\n- [ ] Freezing handling: Detect when the browser is not making progress in the\n      content despite having media data to play and try to unstuck it.\n      _Priority: average_\n- [ ] Proper handling of `QuotaExceededError` after pushing segments (when low\n      on memory).\n      This is generally not needed as the browser should already handle some kind of\n      garbage collection but some platforms still may have issues when memory is\n      constrained.\n      _Priority: low_\n\nTracks:\n\n- [x] Provide API to set an audio track\n- [ ] Provide API to set a video track\n      _Priority: low_\n- [ ] Allow text track selection and support at least one text track format\n      (TTML IMSC1 or webVTT) - through a JS library first?\n      _Priority: low_\n\nMiscellaneous:\n\n- [x] Error API\n- [x] Export embedded versions of the WebAssembly and Worker files to facilitate\n      application's development code.\n- [x] Initial position API\n- [ ] Delta playlist handling.\n      _Priority: low_\n- [ ] Content Steering handling.\n      _Priority: low_\n- [ ] Support content decryption.\n      _Priority: very low_\n\nPlaylist tags specifically considered (unchecked ones are mainly just ignored,\nmost of them are not needed for playback):\n\n- [x] EXT-X-ENDLIST: Parsed to know if a playlist needs to be refreshed or\n      not, but also to detect if we're playing an unfinished live content to\n      play close to the live edge by default.\n- [x] EXTINF: Only the indicated duration of a segment is considered, not\n      the title for which there's no use for now. Both integer and float\n      durations should be handled.\n- [x] EXT-X-PROGRAM-DATE-TIME: Used to determine the starting position of\n      segments as stored by the player - which may be different than the actual\n      media time once the corresponding segment is pushed.\n      The units/scale indicated by this tag will be preferred over the real\n      media time in the player APIs.\n- [x] EXT-X-BYTERANGE: Used for range requests\n- [x] EXT-X-PLAYLIST-TYPE: Used To know if a Playlist may be refreshed\n- [x] EXT-X-TARGETDURATION: Useful for heuristics for playlist refresh\n- [x] EXT-X-GAP: Those segments are just skipped, no variant switch or\n      anything like that.\n- [x] EXT-X-START: Used to determine a default start time in the content.\n- EXT-X-MAP:\n  - [x] URI: Used to fetch the initialization segment if one is present\n  - [x] BYTERANGE: To perform a range request for the initialization segment\n- EXT-X-MEDIA:\n  - [x] TYPE: Both AUDIO and VIDEO are handled. SUBTITLES and CLOSED-CAPTIONS\n        are just ignored for now.\n  - [x] URI\n  - [x] GROUP-ID\n  - [x] DEFAULT\n  - [x] AUTOSELECT\n  - [x] LANGUAGE: In audio track selection API\n  - [x] ASSOC-LANGUAGE: In audio track selection API\n  - [x] NAME: In audio track selection API\n  - [ ] CHANNELS: Not so hard to implement, but I've been too lazy to parse that\n        specific format from the Multivariant Playlist for now\n  - [ ] CHARACTERISTICS: Soon...\n  - [ ] FORCED: As the SUBTITLES TYPE is not handled yet, we don't have to use\n        this one\n  - [ ] INSTREAM-ID: As the CLOSED-CAPTIONS TYPE is not handled yet, we don't\n        have to use this one.\n  - [ ] STABLE-RENDITION-ID: Not really needed for now (only for content steering?)\n- EXT-X-STREAM-INF:\n  - [x] BANDWIDTH: Used to select the right variant in function of the\n        bandwidth\n  - [x] CODECS: Used for checking support (and filtering out if that's not the\n        case, and for initializing buffers with the right info).\n  - [x] AUDIO\n  - [x] VIDEO: As no video track selection API exist yet, only the most\n        prioritized video media playlist is considered\n  - [x] RESOLUTION: Used to describe variant in variant selection API\n  - [x] FRAME-RATE: Used to describe variant in variant selection API\n  - [x] SCORE: Considered both to select a variant and to determine if a quality\n        is better when \"fast-switching\".\n  - [ ] STABLE-VARIANT-ID: Not really needed for now (only for content steering?)\n  - [ ] AVERAGE-BANDWIDTH: Not used yet. I don't know if it's useful yet for us.\n  - [ ] SUPPLEMENTAL-CODECS: In our web use case, I'm not sure if this is only\n        useful for track selection API or if filtering also needs to be done based\n        on this.\n  - [ ] SUBTITLES: No subtitles support for now\n  - [ ] CLOSED-CAPTIONS: that one is just ignored for now\n  - [ ] PATHWAY-ID: Content Steering not handled yet\n  - [ ] HDCP-LEVEL: DRM are not handled for now\n  - [ ] ALLOWED-CPC: DRM are not handled for now\n- [ ] EXT-X-VERSION: Not specifically considered for now, most differences\n      handled until now had compatible behaviors from version to version\n- [ ] EXT-X-INDEPENDENT-SEGMENTS: Might needs to be considered once we're\n      doing some manual cleaning?\n- [ ] EXT-X-DEFINE: Seems rare enough, so may be supported if the time is\n      taken...\n- [ ] EXT-X-MEDIA-SEQUENCE: Not sure of what this allows. To check...\n- [ ] EXT-X-I-FRAMES-ONLY: To handle one day, perhaps (very low priority)\n- [ ] EXT-X-PART: low-latency related\n- [ ] EXT-X-PART-INF: low-latency related\n- [ ] EXT-X-SERVER-CONTROL: low-latency related?\n- [ ] EXT-X-BITRATE\n- [ ] EXT-X-DATERANGE: Might be used for an event emitting API?\n- [ ] EXT-X-SKIP\n- [ ] EXT-X-PRELOAD-HINT\n- [ ] EXT-X-RENDITION-REPORT\n- [ ] EXT-X-I-FRAME-STREAM-INF\n- [ ] EXT-X-SESSION-DATA\n- [ ] EXT-X-SESSION-KEY\n- [ ] EXT-X-CONTENT-STEERING\n- [ ] EXT-X-KEY: decryption and related tags are very low priority\n- [ ] EXT-X-DISCONTINUITY: I'm under the impression in our scenario that it\n      only is useful to increment discontinuity sequences, which we have no\n      need for...\n- [ ] EXT-X-DISCONTINUITY-SEQUENCE: I don't think we need this, at least I\n      didn't encounter a case for it now that isn't handled by other tags.\n\n## Setup\n\nIf you want to contribute or build the Wasp-hls locally, you will need to have\n[nodejs](https://nodejs.org/) and [rust](https://www.rust-lang.org/tools/install)\ninstalled.\n\nThen you need to install node dependencies by calling in your shell:\n\n```sh\n# Install all node dependencies (needs npm, generally installed with nodejs)\nnpm install\n```\n\nYou also need to add the rust wasm32 target and some rust dependencies:\n\n```sh\n# Add wasm32 target (needs rustup that you most likely took with rust)\nrustup target add wasm32-unknown-unknown\n\n# Add wasm-bindgen CLI (needs cargo, generally installed with rust)\ncargo install wasm-bindgen-cli\n\n# Optionally, you may also need clippy, for checking Rust code mistakes\nrustup component add clippy\n```\n\n## Build\n\nThe building of the Wasp-hls player may be performed by module, if you just\nupdated one area of the code (the Rust code for example), or as a whole.\n\n### The Rust (WebAssembly) code\n\nTo build only the Rust code in `src/rs-core/` to its destination WebAssembly\nfile (`build/wasp_hls_bg.wasm`), you can run any of the following commands:\n\n```sh\n# Build in debug mode, which leads to a bigger file and slower code, but is\n# more useful and quicker to build when developping\nnpm run build:wasm\n\n# Build in release mode, which is the actual delivered result\nnpm run build:wasm:release\n```\n\n### The TypeScript Worker code\n\nTo build only the Worker code in `src/ts-worker` to its destination JavaScript\nfile (`build/worker.js`), you can run any of the following commands:\n\n```sh\n# Build in debug mode, which leads to a bigger file though much easier to debug\nnpm run build:worker\n\n# Build in release mode, which is the actual delivered minified result\nnpm run build:worker:release\n```\n\n### The Main (API) code\n\nTo build only the code running in the main thread present in `src/ts-main` to\nits destination JavaScript file (`build/main.js`), you can run any of the\nfollowing commands:\n\n```sh\n# Build in debug mode, which leads to a bigger file though much easier to debug\nnpm run build:main\n\n# Build in release mode, which is the actual delivered minified result\nnpm run build:main:release\n```\n\n### The Demo\n\nTo build only the demo application showcasing the Wasp-hls player, whose code\nis present in the (`demo/`) directory, to its destination JavaScript file\n(`build/demo.js`), you can run any of the following commands:\n\n```sh\n# Build in debug mode, which leads to a bigger file though much easier to debug\nnpm run build:demo\n\n# Build in debug mode, with a \"watcher\" rebuilding each time one of its files\n# changes\nnpm run build:demo:watch\n\n# Build in release mode, which is the actual delivered minified result\nnpm run build:demo:release\n```\n\nThen to perform your tests, you generally want to serve the demo. You can do so\nwith:\n\n```sh\nnpm run serve\n```\n\n### Combinations\n\nIf you just want to build the whole Wasp-hls player code, without the demo, you\nmay call:\n\n```sh\nnpm run build:all\n```\n\nIf you want to build all that code AND the demo:\n\n```sh\nnpm run build:all \u0026\u0026 npm run build:demo\n```\n\nThough what you most likely want to do here is build the full code used by\nthe demo to perform your tests, here just write:\n\n```sh\nnpm run build:all:demo\n```\n\nThat last script bypass the generation of the `build/main.js` file, as the demo\nfile (`build/demo.js`) already includes the content of that file anyway.\n\nTo build everything in release mode, for an actual release or for tests in\nproduction conditions, write:\n\n```sh\n# WebAssembly + Worker + Main in release mode\nnpm run build:release\n\n# If you also want the demo in release mode\nnpm run build:demo:release\n```\n\n### The Documentation\n\nThe documentation, written in `doc/` may also be built to its final directory\n(`build/doc`), through the following command:\n\n```sh\nnpm run doc\n```\n\nIt may then be served, so it can be read on a web browser, through:\n\n```sh\nnpm run serve\n```\n\nAnd then requesting the `/doc` path.\n\n## Update the code\n\nYou're welcome to read the code which should be hopefully documented enough and\nreadable enough to dive into. The source code of the player is in the `src`\ndirectory, if you would prefer to work on the demo, it's in the `demo`\ndirectory, as for the documentation, it's in the `doc` directory.\n\n## Check the code\n\nTo check the TypeScript types of TypeScript files and their code style with\nthe `eslint` package, you can run:\n\n```sh\n# Check all TypeScript files in the project\nnpm run check\n\n# OR, check only the Worker code\nnpm run check:worker\n\n# OR, check only the Main code\nnpm run check:main\n\n# OR, check only the Demo code\nnpm run check:demo\n```\n\nTo check the Rust code, with clippy, you can run:\n\n```sh\n# Check all Rust files in the project\nnpm run clippy\n```\n\nYou also might want to format automatically the code before commiting:\n\n```sh\n# Format all TypeScript, JavaScript, Markdown and HTML files in the project\nnpm run fmtt\n\n# Format all Rust code\nnpm run fmtr\n\n# Do both\nnpm run fmt\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FpeaBerberian%2Fwasp-hls","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FpeaBerberian%2Fwasp-hls","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FpeaBerberian%2Fwasp-hls/lists"}