@@ -35,27 +35,44 @@ static HTTP_REFERRER_REGEX: LazyLock<Regex> =
35
35
static HTTP_USER_AGENT_REGEX : LazyLock < Regex > =
36
36
LazyLock :: new ( || Regex :: new ( r#"http-user-agent=(?P<user_agent>.+)"# ) . unwrap ( ) ) ;
37
37
38
+ struct M3UProcessing {
39
+ channel_line : Option < String > ,
40
+ channel_headers : Option < ChannelHttpHeaders > ,
41
+ channel_headers_set : bool ,
42
+ last_non_empty_line : Option < String > ,
43
+ groups : HashMap < String , i64 > ,
44
+ source_id : i64 ,
45
+ use_tvg_id : Option < bool > ,
46
+ line_count : usize ,
47
+ }
48
+
38
49
pub fn read_m3u8 ( mut source : Source , wipe : bool ) -> Result < ( ) > {
39
50
let path = match source. source_type {
40
51
source_type:: M3U_LINK => get_tmp_path ( ) ,
41
52
_ => source. url . clone ( ) . context ( "no file path found" ) ?,
42
53
} ;
43
54
let file = File :: open ( path) . context ( "Failed to open m3u8 file" ) ?;
44
55
let reader = BufReader :: new ( file) ;
45
- let mut lines = reader. lines ( ) . enumerate ( ) . peekable ( ) ;
46
- let mut groups: HashMap < String , i64 > = HashMap :: new ( ) ;
56
+ let mut lines = reader. lines ( ) . enumerate ( ) ;
47
57
let mut sql = sql:: get_conn ( ) ?;
48
58
let tx = sql. transaction ( ) ?;
49
59
if wipe {
50
60
sql:: wipe ( & tx, source. id . context ( "no source id" ) ?) ?;
51
61
} else {
52
62
source. id = Some ( sql:: create_or_find_source_by_name ( & tx, & source) ?) ;
53
63
}
54
- let mut channel_line: Option < String > = None ;
55
- let mut channel_headers: Option < ChannelHttpHeaders > = None ;
56
- let mut channel_headers_set: bool = false ;
57
- let mut last_non_empty_line: Option < String > = None ;
64
+ let mut processing = M3UProcessing {
65
+ channel_headers : None ,
66
+ channel_headers_set : false ,
67
+ channel_line : None ,
68
+ groups : HashMap :: new ( ) ,
69
+ last_non_empty_line : None ,
70
+ source_id : source. id . context ( "no source id" ) ?,
71
+ use_tvg_id : source. use_tvg_id ,
72
+ line_count : 0 ,
73
+ } ;
58
74
while let Some ( ( c1, l1) ) = lines. next ( ) {
75
+ processing. line_count = c1;
59
76
let l1 = match l1. with_context ( || format ! ( "Failed to process line {c1}" ) ) {
60
77
Ok ( r) => r,
61
78
Err ( e) => {
@@ -64,48 +81,57 @@ pub fn read_m3u8(mut source: Source, wipe: bool) -> Result<()> {
64
81
}
65
82
} ;
66
83
let l1_upper = l1. to_uppercase ( ) ;
67
- let reached_eof = lines. peek ( ) . is_none ( ) ;
68
- if l1_upper. starts_with ( "#EXTINF" ) || reached_eof {
69
- if reached_eof && last_non_empty_line. is_none ( ) && !l1. trim ( ) . is_empty ( ) {
70
- last_non_empty_line = Some ( l1. clone ( ) ) ;
71
- }
72
- if let Some ( channel) = channel_line {
73
- if !channel_headers_set {
74
- channel_headers = None ;
75
- }
76
- commit_channel (
77
- channel,
78
- last_non_empty_line. take ( ) ,
79
- & mut groups,
80
- channel_headers. take ( ) ,
81
- source. id . context ( "missing source id" ) ?,
82
- source. use_tvg_id ,
83
- & tx,
84
- )
85
- . with_context ( || format ! ( "Failed to process channel ending at line {c1}" ) )
86
- . unwrap_or_else ( |e| {
87
- log:: log ( format ! ( "{:?}" , e) ) ;
88
- } ) ;
89
- }
90
- channel_line = Some ( l1) ;
91
- channel_headers_set = false ;
84
+ if l1_upper. starts_with ( "#EXTINF" ) {
85
+ try_commit_channel ( & mut processing, & tx) ;
86
+ processing. channel_line = Some ( l1) ;
87
+ processing. channel_headers_set = false ;
92
88
} else if l1_upper. starts_with ( "#EXTVLCOPT" ) {
93
- if channel_headers. is_none ( ) {
94
- channel_headers = Some ( ChannelHttpHeaders {
89
+ if processing . channel_headers . is_none ( ) {
90
+ processing . channel_headers = Some ( ChannelHttpHeaders {
95
91
..Default :: default ( )
96
92
} ) ;
97
93
}
98
- if set_http_headers ( & l1, channel_headers. as_mut ( ) . context ( "no headers" ) ?) {
99
- channel_headers_set = true ;
94
+ if set_http_headers (
95
+ & l1,
96
+ processing. channel_headers . as_mut ( ) . context ( "no headers" ) ?,
97
+ ) {
98
+ processing. channel_headers_set = true ;
100
99
}
101
100
} else if !l1. trim ( ) . is_empty ( ) {
102
- last_non_empty_line = Some ( l1) ;
101
+ processing . last_non_empty_line = Some ( l1) ;
103
102
}
104
103
}
104
+ try_commit_channel ( & mut processing, & tx) ;
105
105
tx. commit ( ) ?;
106
106
Ok ( ( ) )
107
107
}
108
108
109
+ fn try_commit_channel ( processing : & mut M3UProcessing , tx : & Transaction ) {
110
+ if let Some ( channel) = processing. channel_line . take ( ) {
111
+ if !processing. channel_headers_set {
112
+ processing. channel_headers = None ;
113
+ }
114
+ commit_channel (
115
+ channel,
116
+ processing. last_non_empty_line . take ( ) ,
117
+ & mut processing. groups ,
118
+ processing. channel_headers . take ( ) ,
119
+ processing. source_id ,
120
+ processing. use_tvg_id ,
121
+ & tx,
122
+ )
123
+ . with_context ( || {
124
+ format ! (
125
+ "Failed to process channel ending at line {}" ,
126
+ processing. line_count
127
+ )
128
+ } )
129
+ . unwrap_or_else ( |e| {
130
+ log:: log ( format ! ( "{:?}" , e) ) ;
131
+ } ) ;
132
+ }
133
+ }
134
+
109
135
fn commit_channel (
110
136
channel_line : String ,
111
137
last_line : Option < String > ,
0 commit comments