mirror of
https://github.com/ivabus/hlssimple
synced 2024-11-21 15:45:08 +03:00
Initial commit
This commit is contained in:
commit
acdf0d39f2
9 changed files with 176 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
.DS_Store
|
9
.rustfmt.toml
Normal file
9
.rustfmt.toml
Normal file
|
@ -0,0 +1,9 @@
|
|||
edition = "2021"
|
||||
hard_tabs = true
|
||||
merge_derives = true
|
||||
reorder_imports = true
|
||||
reorder_modules = true
|
||||
use_field_init_shorthand = true
|
||||
use_small_heuristics = "Off"
|
||||
wrap_comments = true
|
||||
comment_width = 80
|
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "hlssimple"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/ivabus/hlssimple"
|
||||
description = "HTTP server for hls streaming and nothing more"
|
||||
|
||||
|
||||
[dependencies]
|
||||
rocket = "0.5.0-rc.3"
|
||||
clap = { version = "4.3.4", features = [ "derive" ] }
|
||||
smurf = "0.2.0"
|
21
README.md
Normal file
21
README.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
# HLSsimple
|
||||
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
cargo install --git https://github.com/ivabus/hlssimple
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```shell
|
||||
hlssimple --stream-dir <STREAMS_DIR>
|
||||
```
|
||||
|
||||
Where `STREAMS_DIR` contains raw (>= 1) streams (.m3u8 file name will be used for index), or streams contained in subdirs (subdir name will be used to index).
|
||||
|
||||
## OBS Configuration
|
||||
|
||||
| All streams in one dir | Streams split by subdirs |
|
||||
|------------------------------------------|-------------------------------------------------------|
|
||||
| ![All in one](./img/obs_all_in_one.webp) | ![OBS Split streams by subdirs](./img/obs_split.webp) |
|
9
Rocket.toml
Normal file
9
Rocket.toml
Normal file
|
@ -0,0 +1,9 @@
|
|||
[default]
|
||||
address = "0.0.0.0"
|
||||
port = 50428
|
||||
keep_alive = 0
|
||||
ident = "hlssimple via Rocket"
|
||||
ip_header = false
|
||||
log_level = "normal"
|
||||
temp_dir = "/tmp"
|
||||
cli_colors = true
|
BIN
img/obs_all_in_one.webp
Normal file
BIN
img/obs_all_in_one.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 102 KiB |
BIN
img/obs_split.webp
Normal file
BIN
img/obs_split.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 103 KiB |
11
index.html
Normal file
11
index.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
<h1>Stream index</h1>
|
||||
|
||||
<h2>How to play?</h2>
|
||||
|
||||
<ul>
|
||||
<li>If you're using Safari-based browsers (on iOS, iPadOS or macOS) <a href=\"https://caniuse.com/http-live-streaming\">(browser support)</a> you can just click "Play"</li>
|
||||
<li>Also you can play this streams using VLCs "Open URL" and pasting link to .m3u8 file</li>
|
||||
</ul>
|
||||
|
||||
<br>
|
||||
|
111
src/main.rs
Normal file
111
src/main.rs
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2023 Ivan Bushchik
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
|
||||
use clap::Parser;
|
||||
use rocket::fs::FileServer;
|
||||
use rocket::response::content::RawHtml;
|
||||
use std::fs::read_dir;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
struct Args {
|
||||
#[arg(short, long)]
|
||||
streams_dir: String,
|
||||
}
|
||||
|
||||
#[get("/play/<page..>")]
|
||||
fn play(page: PathBuf) -> RawHtml<String> {
|
||||
RawHtml(format!(
|
||||
"<video controls>
|
||||
<source src=\"/{}\" type=\"application/x-mpegURL\">
|
||||
</video>",
|
||||
page.to_str().unwrap()
|
||||
))
|
||||
}
|
||||
|
||||
struct StreamURL {
|
||||
alias: String,
|
||||
url: String,
|
||||
}
|
||||
|
||||
#[get("/")]
|
||||
fn index() -> RawHtml<String> {
|
||||
let args = Args::parse();
|
||||
let dir = read_dir(args.streams_dir).unwrap();
|
||||
let mut res = match smurf::io::read_file_to_str(&PathBuf::from("./index.html")) {
|
||||
Some(s) => s,
|
||||
None => String::new(),
|
||||
};
|
||||
let mut m3u8: Vec<StreamURL> = vec![];
|
||||
for i in dir {
|
||||
let path = i.unwrap().path();
|
||||
if path.is_file() && path.file_name().unwrap().to_str().unwrap() != ".DS_Store" {
|
||||
if path.extension().unwrap().to_str().unwrap() == "m3u8" {
|
||||
let filename = path.file_name().unwrap().to_str().unwrap();
|
||||
m3u8.push(StreamURL {
|
||||
url: filename.to_string(),
|
||||
alias: filename.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
if path.is_dir() {
|
||||
let mut dir: Vec<String> = vec![];
|
||||
for i in read_dir(&path).unwrap() {
|
||||
dir.push(i.unwrap().file_name().to_str().unwrap().to_string())
|
||||
}
|
||||
for i in &dir {
|
||||
if i.contains(".m3u8") {
|
||||
m3u8.push(StreamURL {
|
||||
alias: path.file_name().unwrap().to_str().unwrap().to_string(),
|
||||
url: format!("{}/{}", path.file_name().unwrap().to_str().unwrap(), i),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m3u8.sort_by_key(|x| x.alias.clone());
|
||||
for i in m3u8 {
|
||||
res += &*format!(
|
||||
"<a href=\"{}\">{}</a> <a href=\"/play/{}\">Play</a> (copy link into your player)<br>",
|
||||
&i.url, &i.alias, &i.url
|
||||
);
|
||||
}
|
||||
RawHtml(res)
|
||||
}
|
||||
|
||||
#[rocket::main]
|
||||
async fn main() -> Result<(), rocket::Error> {
|
||||
let args = Args::parse();
|
||||
let _rocket = rocket::build()
|
||||
.mount("/", routes![play, index])
|
||||
.mount("/", FileServer::from(args.streams_dir))
|
||||
.launch()
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in a new issue