@@ -4,11 +4,12 @@ use actix_web::{web, HttpResponse};
4
4
use anyhow:: { bail, Context } ;
5
5
use biliapi:: Request ;
6
6
use danmu2ass:: { bilibili:: DanmakuElem , CanvasConfig , InputType } ;
7
+ use log:: info;
7
8
use serde:: Deserialize ;
8
9
use serde_json:: json;
9
10
10
11
#[ derive( Debug , Deserialize ) ]
11
- #[ serde( tag = "type" , content = "content" ) ]
12
+ #[ serde( tag = "type" , content = "content" , rename_all = "snake_case" ) ]
12
13
pub enum Source {
13
14
Xml { content : String , title : String } ,
14
15
Url { url : String } ,
@@ -21,20 +22,31 @@ pub struct ConvertRequest {
21
22
denylist : Option < HashSet < String > > ,
22
23
}
23
24
24
- #[ actix_web:: get( "/convert}" ) ]
25
25
async fn convert ( request : web:: Json < ConvertRequest > ) -> HttpResponse {
26
26
let req = request. into_inner ( ) ;
27
- match req. source {
27
+ let mut output = Vec :: < u8 > :: new ( ) ;
28
+ let title = match req. source {
28
29
Source :: Xml { content, title } => {
30
+ info ! ( "parsing {} bytes in xml" , content. len( ) ) ;
29
31
let parser = danmu2ass:: Parser :: new ( content. as_bytes ( ) ) ;
30
- let mut output = Vec :: < u8 > :: new ( ) ;
31
- let r = danmu2ass:: convert ( parser, title, & mut output, req. config , & req. denylist ) ;
32
+ let r = danmu2ass:: convert (
33
+ parser,
34
+ title. clone ( ) ,
35
+ & mut output,
36
+ req. config ,
37
+ & req. denylist ,
38
+ ) ;
32
39
if let Err ( e) = r {
33
40
return HttpResponse :: BadRequest ( ) . json ( json ! ( {
34
41
"errmsg" : format!( "{e:#?}" )
35
42
} ) ) ;
36
43
}
37
- HttpResponse :: Ok ( ) . content_type ( "text/plain" ) . body ( output)
44
+ let ass_title = title
45
+ . as_str ( )
46
+ . strip_suffix ( ".xml" )
47
+ . map ( ToString :: to_string)
48
+ . unwrap_or ( title) ;
49
+ ass_title
38
50
}
39
51
Source :: Url { url } => {
40
52
let input_type: InputType = url. parse ( ) . unwrap ( ) ;
@@ -47,10 +59,10 @@ async fn convert(request: web::Json<ConvertRequest>) -> HttpResponse {
47
59
} ) ) ;
48
60
}
49
61
} ;
50
- let mut output = Vec :: < u8 > :: new ( ) ;
62
+ log :: info! ( "download {} danmu, title={}" , danmu . len ( ) , title ) ;
51
63
let r = danmu2ass:: convert (
52
64
danmu. into_iter ( ) . map ( |i| Ok ( i. into ( ) ) ) ,
53
- title,
65
+ title. clone ( ) ,
54
66
& mut output,
55
67
req. config ,
56
68
& req. denylist ,
@@ -60,9 +72,16 @@ async fn convert(request: web::Json<ConvertRequest>) -> HttpResponse {
60
72
"errmsg" : format!( "{e:#?}" )
61
73
} ) ) ;
62
74
}
63
- HttpResponse :: Ok ( ) . content_type ( "text/plain" ) . body ( output )
75
+ title
64
76
}
65
- }
77
+ } ;
78
+ let title =
79
+ percent_encoding:: percent_encode ( title. as_bytes ( ) , percent_encoding:: NON_ALPHANUMERIC ) ;
80
+ let content_disposition = format ! ( "attachment; filename=\" {title}.ass\" " ) ;
81
+ HttpResponse :: Ok ( )
82
+ . append_header ( ( "Content-Type" , "text/plain; charset=utf-8" ) )
83
+ . append_header ( ( "Content-Disposition" , content_disposition) )
84
+ . body ( output)
66
85
}
67
86
68
87
async fn run_input_type ( input_type : InputType ) -> anyhow:: Result < ( String , Vec < DanmakuElem > ) > {
@@ -113,11 +132,26 @@ async fn run_input_type(input_type: InputType) -> anyhow::Result<(String, Vec<Da
113
132
}
114
133
}
115
134
135
+ fn files_service ( ) -> actix_files:: Files {
136
+ actix_files:: Files :: new ( "/" , "./static" )
137
+ . index_file ( "index.html" )
138
+ . prefer_utf8 ( true )
139
+ }
140
+
116
141
pub async fn run_server ( ) -> anyhow:: Result < ( ) > {
117
- let port = portpicker:: pick_unused_port ( ) . context ( "pick port failed" ) ?;
118
- let fut = actix_web:: HttpServer :: new ( || actix_web:: App :: new ( ) . service ( convert) )
119
- . bind ( ( "127.0.0.1" , port) ) ?
120
- . run ( ) ;
142
+ let port = if portpicker:: is_free ( 8081 ) {
143
+ 8081
144
+ } else {
145
+ portpicker:: pick_unused_port ( ) . context ( "pick port failed" ) ?
146
+ } ;
147
+ let fut = actix_web:: HttpServer :: new ( move || {
148
+ actix_web:: App :: new ( )
149
+ // .wrap(actix_cors::Cors::permissive())
150
+ . route ( "/convert" , web:: post ( ) . to ( convert) )
151
+ . default_service ( files_service ( ) )
152
+ } )
153
+ . bind ( ( "127.0.0.1" , port) ) ?
154
+ . run ( ) ;
121
155
let handle = tokio:: spawn ( fut) ;
122
156
// open
123
157
match open:: that ( format ! ( "http://127.0.0.1:{port}" ) ) {
0 commit comments