{"id":13906676,"url":"https://github.com/faryon93/hlswatch","last_synced_at":"2025-08-25T21:06:02.369Z","repository":{"id":57508041,"uuid":"83909635","full_name":"faryon93/hlswatch","owner":"faryon93","description":"keep track of hls viewer stats","archived":false,"fork":false,"pushed_at":"2020-01-19T01:18:20.000Z","size":2508,"stargazers_count":49,"open_issues_count":8,"forks_count":9,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-10T04:35:19.628Z","etag":null,"topics":["concurrent","hls","hlswatch","influxdb","nginx","rtmp","statistics","stream","viewers"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/faryon93.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-04T17:00:56.000Z","updated_at":"2024-07-15T02:50:06.000Z","dependencies_parsed_at":"2022-09-26T17:51:11.647Z","dependency_job_id":null,"html_url":"https://github.com/faryon93/hlswatch","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/faryon93/hlswatch","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faryon93%2Fhlswatch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faryon93%2Fhlswatch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faryon93%2Fhlswatch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faryon93%2Fhlswatch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/faryon93","download_url":"https://codeload.github.com/faryon93/hlswatch/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faryon93%2Fhlswatch/sbom","scorecard":{"id":393141,"data":{"date":"2025-08-11","repo":{"name":"github.com/faryon93/hlswatch","commit":"0fc5b3ea227c3e76c5251527d9222d0c75f1678d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.8,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Info: FSF or OSI recognized license: GNU General Public License v3.0: LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: containerImage not pinned by hash: Dockerfile:1","Warn: containerImage not pinned by hash: Dockerfile:15: pin your Docker image by updating alpine:latest to alpine:latest@sha256:4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1","Warn: goCommand not pinned by hash: Dockerfile:12-13","Info:   0 out of   2 containerImage dependencies pinned","Info:   0 out of   1 goCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-18T18:19:39.471Z","repository_id":57508041,"created_at":"2025-08-18T18:19:39.471Z","updated_at":"2025-08-18T18:19:39.471Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272131795,"owners_count":24878986,"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","status":"online","status_checked_at":"2025-08-25T02:00:12.092Z","response_time":1107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["concurrent","hls","hlswatch","influxdb","nginx","rtmp","statistics","stream","viewers"],"created_at":"2024-08-06T23:01:40.418Z","updated_at":"2025-08-25T21:06:02.344Z","avatar_url":"https://github.com/faryon93.png","language":"Go","funding_links":[],"categories":["HarmonyOS"],"sub_categories":["Windows Manager"],"readme":"# hlswatch - keep track of hls viewer stats\nhlswatch is a simple program to keep track of the concurrent viewer count of a [HLS](https://tools.ietf.org/html/draft-pantos-http-live-streaming-20) live stream. This piece of software is intended to be placed in front of a NGINX server with the [nginx-rtmp-module](https://github.com/arut/nginx-rtmp-module) installed and HLS encoding enabled.\nThe NGINX server is used as a transcoding instance to translate an incoming RTMP stream into HLS compatible video fragments. Delivering the fragments and playlists to the clients is handled by hlswatch.\n\nTo count the number of concurrent viewers hlswatch monitors the m3u8 playlist accesses per client. If the client does not issue a playlist reload in a certain amount of time it is considered as \"not watching anymore\".\n\nThe gathered data can be obtained in two different ways:\n\n1. The viewer counts are written to an [InfluxDB](https://www.influxdata.com/) database every second, if the the ```[influxdb]``` section is present in the config file. The tags ```node``` and ```stream``` are automatically populatet with the hostname and the stream name. The current count of concurrent viewers is stored in the value ```viewers```.\n\n2. A REST endpoint is exposed on the address/port configured in ```common.listen```. A JSON object can be accessed at ```/stats```, which contains the current viewer numbers for each stream.\n\n**Keep in mind that this piece of software hasn't been tested in production!**\n\n## Building\nThe Go application is built as part of the Docker image build process.\nIn order to build a fresh copy of *hlswatch* you just have to enter:\n\n    $: docker build -t faryon93/hlswatch .\n\n## Configuration\nPer default hlswatch uses ```/etc/hlswatch/hlswatch.conf``` as configuration file. If you want to change this path, just call hlswatch with your configuration file as the first argument.\n\n```\n[common]\nlisten = \"0.0.0.0:3000\"        # listen port/address for REST interface\nhls_path = \"/tmp/hls/\"         # path where nginx-rtmp stores the HLS fragments\nviewer_timeout = 15            # time in seconds when a viewer is considered not watching anymore\n\n[influx]\naddress = \"http://localhost:8086\"   # address of the influxdb server\ndatabase = \"hlswatch\"               # database name\nuser = \"hlswatch\"                   # database user\npassword = \"hlswatch\"               # database password\n```\n\nSome configuration parameters can be overriden by environment variables. See ```config/config.go``` for valid variable names. Note: Not all parameters can be replaced by environment variables.\n\n## NGINX Setup\nBecause this software is responsible for delivering all data to the client it is not necessary to serve the HLS fragments via nginx to the public. If you want all NGINX features like access control, compression, TLS Termination, ... you can reverse proxy incoming requests by NGINX to hlswatch.\nThis software relies on some configuration option the nginx-rtmp-module offers. The settings `hls_cleanup` and `hls_nested` need to be enabled:\n\n```\nrtmp {\n    server {\n        listen 1935;\n        chunk_size 4000;\n\n        application live {\n            live on;\n            hls on;\n            hls_fragment_naming system;\n            hls_fragment 5s;\n            hls_path /tmp/hls;\n            hls_nested on;\n        }\n    }\n}\n```\n\n## Tested Players\nThe application was tested with the following web players:\n\nPlayer                                     | Working |\n-------------------------------------------|---------|\n[clappr](https://github.com/clappr/clappr) |    ✔    |\n\n## Docker\nThis repository contains a Dockerfile, which builds a container which contains an NGINX webserver compiled with the nginx-rtmp-module.\nThe current version contained in the master branch is automatically pushed to [Docker Hub](https://hub.docker.com/r/faryon93/hlswatch/).\nSome configuration files to enable live streaming via RTMP and pass all HTTP requests to hlswatch is included by default.\nFor production use you should consider adding SSL termination in NGINX and secure the access to hlswatchs statistics page.\n\nRunning the container:\n```\n$: docker run --rm -t -i \\\n              --name nginx-hls \\\n              -p 1935:1935 \\\n              -p 80:80 \\\n              -e HLS_INFLUX_ADDR=http://localhost:8086 \\\n              -e HLS_INFLUX_DB=hlswatch \\\n              -e HLS_INFLUX_USER=hlswatch \\\n              -e HLS_INFLUX_PASSWORD=hlswatch \\\n              faryon93/hlswatch\n```\n\n## ToDo\n- Caching of m3u8 playlist and video fragments in RAM\n- Disable directory listing in hlswatch\n- Execute hlswatch as unprivileged user (proper process supervision)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffaryon93%2Fhlswatch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffaryon93%2Fhlswatch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffaryon93%2Fhlswatch/lists"}