{"id":13908028,"url":"https://github.com/leandromoreira/resty-bakery","last_synced_at":"2025-07-30T19:17:08.003Z","repository":{"id":141425725,"uuid":"293943120","full_name":"leandromoreira/resty-bakery","owner":"leandromoreira","description":"An Nginx+Lua library to modify media manifests like HLS and MPEG Dash, acting like a proxy.","archived":false,"fork":false,"pushed_at":"2022-10-20T17:17:36.000Z","size":14702,"stargazers_count":21,"open_issues_count":0,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-01-13T22:50:18.111Z","etag":null,"topics":["filtering","hls","lua","manipulator","modify","mpeg-dash","nginx","proxy","resty"],"latest_commit_sha":null,"homepage":"https://github.com/leandromoreira/resty-bakery","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leandromoreira.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2020-09-08T22:40:06.000Z","updated_at":"2022-11-22T21:36:46.000Z","dependencies_parsed_at":"2024-01-22T00:03:08.443Z","dependency_job_id":null,"html_url":"https://github.com/leandromoreira/resty-bakery","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leandromoreira%2Fresty-bakery","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leandromoreira%2Fresty-bakery/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leandromoreira%2Fresty-bakery/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leandromoreira%2Fresty-bakery/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leandromoreira","download_url":"https://codeload.github.com/leandromoreira/resty-bakery/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235208946,"owners_count":18953003,"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":["filtering","hls","lua","manipulator","modify","mpeg-dash","nginx","proxy","resty"],"created_at":"2024-08-06T23:02:25.295Z","updated_at":"2025-01-23T00:33:06.087Z","avatar_url":"https://github.com/leandromoreira.png","language":"Lua","funding_links":[],"categories":["HarmonyOS"],"sub_categories":["Windows Manager"],"readme":"[![Build Status](https://travis-ci.org/leandromoreira/resty-bakery.svg?branch=master)](https://travis-ci.org/leandromoreira/resty-bakery) [![license](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)\n\n# Resty-Bakery [WIP]\n\nIt's a Nginx+Lua library, strongly inspired by [the CBS Bakery](https://github.com/cbsinteractive/bakery), to modify media manifests on-the-fly, like [HLS](https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-07) and [MPEG Dash](https://en.wikipedia.org/wiki/Dynamic_Adaptive_Streaming_over_HTTP). It acts as a proxy between (or in) the `frontend` and your `origin`.\n\nThis is very useful due to the fact that some [devices can't play with a higher bitrate, multiple codecs, multiple frame rate](https://github.com/leandromoreira/http-video-streaming-troubleshooting), and so on.\n\n# Getting started\n\n```bash\n# run the nginx\ndocker run --rm -it -p 8080:8080 leandromoreira/resty-bakery\n\n# fetch unfiltered manifest\ncurl \"http://localhost:8080/media/generic_master.m3u8\"\n\n# fetch renditions (variants) with bandwidth \u003e= 800000 and with frame rate = 60 or 60/1\ncurl \"http://localhost:8080/media/b(800000)fps(60,60:1)/generic_master.m3u8\"\n```\n\n# Filters\n\n* [**Bandwidth**](https://github.com/cbsinteractive/bakery/blob/master/docs/filters/bandwidth.md) (/path/to/media/f/`b(min,max)`/manifes.m3u8) - filters based on uri path following the format `b(min bandwidth, max bandwidth)`.\n* [**Framerate**](https://github.com/cbsinteractive/bakery/blob/master/docs/filters/frame-rate.md) (/path/to/media/f/`fps(30,30000:1001)`/manifes.m3u8) - filters out based on uri path following the format `b(list of frame rates)`.\n\n# Nginx usage example\n\n```nginx\n# Let's suppose our origin hosts media at /media/\u003cmanifest\u003e.\u003cextension\u003e\n# So what we need to do is to set up a location to act like a proxy\n# Also, let's say we're going to use /media/\u003cfilters\u003e/\u003cmanifest\u003e.\u003cextension\u003e to pass the filters\n#  ex: /media/b(1500000)/playlist.m3u8\n    location /media {\n        proxy_pass http://origin;\n\n        # we need to keep the original uri with its state, since we're going to rewrite\n        # from /media/\u003cfilters\u003e/\u003cmanifest\u003e.\u003cextension\u003e to /media/\u003cmanifest\u003e.\u003cextension\u003e\n        set_by_lua_block $original_uri { return ngx.var.uri }\n\n        # when the Lua code may change the length of the response body,\n        # then it is required to always clear out the Content-Length\n        header_filter_by_lua_block { ngx.header.content_length = nil }\n\n        # rewriting to the proper origin uri, effectively removing the filters\n        rewrite_by_lua_block {\n          local uri = ngx.re.sub(ngx.var.uri, \"^/media/(.*)/(.*)$\", \"/media/$2\")\n          ngx.req.set_uri(uri)\n        }\n\n        # applying the filters (after the proxy/upstream has replied)\n        # this is where the magic happens\n        body_filter_by_lua_block {\n          local modified_manifest = bakery.filter(ngx.var.original_uri, ngx.arg[1])\n          ngx.arg[1] = modified_manifest\n          ngx.arg[2] = true\n        }\n    }\n```\n\n# Test locally\n\n```bash\nmake run\n\n# open another tab\n\n# unmodified manifest\ncurl -v \"http://localhost:8080/media/ffmpeg_master.m3u8\"\ncurl -v \"http://localhost:8080/media/ffmpeg_dash.mpd\"\n\n# filters out renditions with bandwidth \u003c 1500000\ncurl -v \"http://localhost:8080/media/b(1500000)/ffmpeg_master.m3u8\"\ncurl -v \"http://localhost:8080/media/b(1500000)/ffmpeg_dash.mpd\"\n\n# filters out renditions with bandwidth \u003e 1500000\ncurl -v \"http://localhost:8080/media/b(0,1500000)/ffmpeg_master.m3u8\"\ncurl -v \"http://localhost:8080/media/b(0,1500000)/ffmpeg_dash.mpd\"\n\n# filters bandwidth \u003e 800000 and excludes frame rate 60\ncurl \"http://localhost:8080/media/b(800000)fps(60)/generic_master.m3u8\"\ncurl \"http://localhost:8080/media/b(800000)fps(60,60:1)/generic_dash.mpd\"\n\n\n# PS: there is an mmedia location just to provide manifests without\n# data transfer them in chunked encoding mechanism\n# this example was done due some CTV that can't handle chunked transfer encoding\n```\n\n# Tests\n\n```bash\nmake test\n```\n\n# Lint\n\n```bash\nmake lint\n```\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleandromoreira%2Fresty-bakery","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleandromoreira%2Fresty-bakery","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleandromoreira%2Fresty-bakery/lists"}