Skip to content

Commit dc87795

Browse files
committed
add watch
1 parent 23389d4 commit dc87795

File tree

5 files changed

+195
-6
lines changed

5 files changed

+195
-6
lines changed

src-tauri/src/lib.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ pub fn run() {
8282
get_epg_ids,
8383
on_start_check_epg,
8484
start_restream,
85-
stop_restream
85+
stop_restream,
86+
watch_self
8687
])
8788
.setup(|app| {
8889
app.manage(Mutex::new(AppState {
@@ -414,3 +415,8 @@ async fn stop_restream(state: State<'_, Mutex<AppState>>) -> Result<(), String>
414415
.await
415416
.map_err(map_err_frontend)
416417
}
418+
419+
#[tauri::command]
420+
async fn watch_self() -> Result<(), String> {
421+
restream::watch_self().await.map_err(map_err_frontend)
422+
}

src-tauri/src/restream.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use tokio::{
1515

1616
use crate::{
1717
log::log,
18-
sql,
18+
mpv, sql,
1919
types::{AppState, Channel},
2020
};
2121

@@ -127,3 +127,20 @@ async fn delete_old_segments(dir: &Path) -> Result<()> {
127127
fs::create_dir_all(dir).await?;
128128
Ok(())
129129
}
130+
131+
pub async fn watch_self() -> Result<()> {
132+
let channel = Channel {
133+
url: Some("http://127.0.0.1:3000/stream.m3u8".to_string()),
134+
name: "Local livestream".to_string(),
135+
favorite: false,
136+
group: None,
137+
group_id: None,
138+
id: Some(-1),
139+
image: None,
140+
media_type: crate::media_type::LIVESTREAM,
141+
series_id: None,
142+
source_id: None,
143+
stream_id: None,
144+
};
145+
mpv::play(channel, false).await
146+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
.notice {
2+
font-size: 0.9rem;
3+
color: lightgray;
4+
}
5+
6+
.box {
7+
background-color: black; /* Dark background similar to a code editor */
8+
padding: 10px; /* Add padding for readability */
9+
border-radius: 4px; /* Rounded corners (optional) */
10+
}
11+
12+
button .icon {
13+
height: 1.5rem;
14+
width: 1.5rem;
15+
transition: transform 0.3s ease;
16+
}
17+
18+
button:hover .icon {
19+
transform: scale(125%);
20+
}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,139 @@
11
<div class="modal-header">
2-
<h4 class="modal-title lbl">Re-streaming...</h4>
2+
<h4 class="modal-title lbl">Re-streaming: {{ channel?.name }}</h4>
33
</div>
44
<div class="modal-body">
5-
<p class="notice">Your re-stream server is active</p>
5+
<div *ngIf="!started">
6+
<p>
7+
If your IPTV service does not allow more than one connection, the re-streaming feature allows
8+
you to share any livestream with friends and family over LAN/WAN
9+
</p>
10+
<br />
11+
<p>
12+
Press start to launch the re-streaming service. Instructions to share your re-streamed
13+
livestream will appear below along with its status
14+
</p>
15+
</div>
16+
<div *ngIf="started" class="selectable box mt-3">
17+
<p>Running...</p>
18+
<br />
19+
<div class="row">
20+
<div class="col-5 col-lg-3 col-xl-2">LAN service address:</div>
21+
<div class="col">{{ address }}</div>
22+
</div>
23+
<div class="row">
24+
<div class="col-5 col-lg-3 col-xl-2">WAN service address:</div>
25+
<div class="col">{{ wanAddress }}</div>
26+
</div>
27+
</div>
28+
<div *ngIf="started">
29+
<br />
30+
<p>
31+
Press the share button (Share LAN or Share WAN) below to generate an .otv file for this
32+
service. You will be able to share this file with your friends so they can import it in Open
33+
TV and watch your re-streamed livestream
34+
</p>
35+
<br />
36+
<p>
37+
Your re-streaming service is always availaible from your LAN. On the other hand, WAN access
38+
will work if you open the appropriate port on your router (3000 by default)
39+
</p>
40+
<br />
41+
<p>To import an .otv file in Open TV:</p>
42+
<ol>
43+
<li>Create a new custom source (either from setup or settings)</li>
44+
<li>Go in settings</li>
45+
<li>Click on "import channel/group" button within the custom source</li>
46+
<li>Select the .otv file</li>
47+
</ol>
48+
</div>
649
</div>
750
<div class="modal-footer">
8-
<button [disabled]="loading" (click)="start()" class="btn btn-primary">Start</button>
9-
<button [disabled]="loading" (click)="stop()" class="btn btn-danger">Stop</button>
51+
<button *ngIf="!started" [disabled]="loading" (click)="start()" class="btn btn-primary">
52+
<span>Start</span>
53+
<svg
54+
class="icon ms-1"
55+
fill="currentColor"
56+
xmlns="http://www.w3.org/2000/svg"
57+
viewBox="0 0 24 24"
58+
>
59+
<path
60+
d="M10,16.5V7.5L16,12M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"
61+
/>
62+
</svg>
63+
</button>
64+
<button
65+
class="btn btn-success d-inline-flex align-items-center"
66+
(click)="watch()"
67+
[disabled]="loading"
68+
*ngIf="started"
69+
>
70+
<span>Watch</span>
71+
<svg
72+
class="icon ms-1"
73+
fill="currentColor"
74+
xmlns="http://www.w3.org/2000/svg"
75+
viewBox="0 0 24 24"
76+
>
77+
<path
78+
d="M11,6H13V13H11V6M9,20A1,1 0 0,1 8,21H5A1,1 0 0,1 4,20V15L6,6H10V13A1,1 0 0,1 9,14V20M10,5H7V3H10V5M15,20V14A1,1 0 0,1 14,13V6H18L20,15V20A1,1 0 0,1 19,21H16A1,1 0 0,1 15,20M14,5V3H17V5H14Z"
79+
/>
80+
</svg>
81+
</button>
82+
<button
83+
ngbTooltip="Sharing over LAN means sharing for your local network. The .otv file generated will
84+
point to your local IP"
85+
class="btn btn-primary d-inline-flex align-items-center"
86+
(click)="share()"
87+
*ngIf="started"
88+
>
89+
<span>Share LAN</span>
90+
<svg
91+
class="icon ms-1"
92+
fill="currentColor"
93+
xmlns="http://www.w3.org/2000/svg"
94+
viewBox="0 0 24 24"
95+
>
96+
<path
97+
d="M10,2C8.89,2 8,2.89 8,4V7C8,8.11 8.89,9 10,9H11V11H2V13H6V15H5C3.89,15 3,15.89 3,17V20C3,21.11 3.89,22 5,22H9C10.11,22 11,21.11 11,20V17C11,15.89 10.11,15 9,15H8V13H16V15H15C13.89,15 13,15.89 13,17V20C13,21.11 13.89,22 15,22H19C20.11,22 21,21.11 21,20V17C21,15.89 20.11,15 19,15H18V13H22V11H13V9H14C15.11,9 16,8.11 16,7V4C16,2.89 15.11,2 14,2H10M10,4H14V7H10V4M5,17H9V20H5V17M15,17H19V20H15V17Z"
98+
/>
99+
</svg>
100+
</button>
101+
<button
102+
ngbTooltip="Sharing over WAN means sharing for the internet. The .otv file generated will point
103+
to your public IP"
104+
class="btn btn-primary d-inline-flex align-items-center"
105+
(click)="share()"
106+
*ngIf="started"
107+
>
108+
<span>Share WAN</span>
109+
<svg
110+
class="icon ms-1"
111+
fill="currentColor"
112+
xmlns="http://www.w3.org/2000/svg"
113+
viewBox="0 0 24 24"
114+
>
115+
<path
116+
d="M12,2A8,8 0 0,0 4,10C4,14.03 7,17.42 11,17.93V19H10A1,1 0 0,0 9,20H2V22H9A1,1 0 0,0 10,23H14A1,1 0 0,0 15,22H22V20H15A1,1 0 0,0 14,19H13V17.93C17,17.43 20,14.03 20,10A8,8 0 0,0 12,2M12,4C12,4 12.74,5.28 13.26,7H10.74C11.26,5.28 12,4 12,4M9.77,4.43C9.5,4.93 9.09,5.84 8.74,7H6.81C7.5,5.84 8.5,4.93 9.77,4.43M14.23,4.44C15.5,4.94 16.5,5.84 17.19,7H15.26C14.91,5.84 14.5,4.93 14.23,4.44M6.09,9H8.32C8.28,9.33 8.25,9.66 8.25,10C8.25,10.34 8.28,10.67 8.32,11H6.09C6.03,10.67 6,10.34 6,10C6,9.66 6.03,9.33 6.09,9M10.32,9H13.68C13.72,9.33 13.75,9.66 13.75,10C13.75,10.34 13.72,10.67 13.68,11H10.32C10.28,10.67 10.25,10.34 10.25,10C10.25,9.66 10.28,9.33 10.32,9M15.68,9H17.91C17.97,9.33 18,9.66 18,10C18,10.34 17.97,10.67 17.91,11H15.68C15.72,10.67 15.75,10.34 15.75,10C15.75,9.66 15.72,9.33 15.68,9M6.81,13H8.74C9.09,14.16 9.5,15.07 9.77,15.56C8.5,15.06 7.5,14.16 6.81,13M10.74,13H13.26C12.74,14.72 12,16 12,16C12,16 11.26,14.72 10.74,13M15.26,13H17.19C16.5,14.16 15.5,15.07 14.23,15.57C14.5,15.07 14.91,14.16 15.26,13Z"
117+
/>
118+
</svg>
119+
</button>
120+
<button
121+
class="btn btn-danger d-inline-flex align-items-center"
122+
*ngIf="started"
123+
[disabled]="loading"
124+
(click)="stop()"
125+
>
126+
<span>Stop</span>
127+
<svg
128+
class="icon ms-1"
129+
fill="currentColor"
130+
xmlns="http://www.w3.org/2000/svg"
131+
viewBox="0 0 24 24"
132+
>
133+
<path
134+
d="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M9,9H15V15H9"
135+
/>
136+
</svg>
137+
</button>
138+
<button class="btn btn-secondary d-inline-flex align-items-center" *ngIf="!started">Close</button>
10139
</div>

src/app/restream-modal/restream-modal.component.ts

+17
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@ import { ErrorService } from "../error.service";
1111
export class RestreamModalComponent {
1212
channel?: Channel;
1313
loading = false;
14+
started = false;
15+
address = "http://192.168.2.10/stream.m3u8";
16+
wanAddress = "http://10.145.22.12/stream.m3u8";
1417
constructor(private error: ErrorService) {}
1518
async start() {
1619
this.loading = true;
1720
try {
1821
await invoke("start_restream", { channel: this.channel });
1922
this.error.success("Successfully started service");
23+
this.started = true;
2024
} catch (e) {
2125
this.error.handleError(e);
2226
}
@@ -28,9 +32,22 @@ export class RestreamModalComponent {
2832
try {
2933
await invoke("stop_restream");
3034
this.error.success("Successfully stopped service");
35+
this.started = false;
3136
} catch (e) {
3237
this.error.handleError(e);
3338
}
3439
this.loading = false;
3540
}
41+
42+
async watch() {
43+
this.loading = true;
44+
try {
45+
await invoke("watch_self");
46+
} catch (e) {
47+
this.error.handleError(e);
48+
}
49+
this.loading = false;
50+
}
51+
52+
share() {}
3653
}

0 commit comments

Comments
 (0)