-
Notifications
You must be signed in to change notification settings - Fork 5
/
danmaku2ass.cpp
238 lines (204 loc) · 6.67 KB
/
danmaku2ass.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <map>
#include <iostream>
#include <fstream>
#include <iso646.h>
#include "rapidxml/rapidxml.hpp"
#include "rapidxml/rapidxml_utils.hpp"
#include "AssClass.hpp"
#include "danmaku2ass.h"
#include "danmaku2ass.hpp"
using namespace std;
using namespace rapidxml;
/*
Get comment type
headline: the first line of comment file
Return:
1 - Acfun
2 - Bilibili
3 - Niconico
*/
int GetCommentType(string headline){
if(headline.find("\"commentList\":[") != std::string::npos){
return 1;
}else if(headline.find("xml version=\"1.0\" encoding=\"UTF-8\"?><i") != std::string::npos or
headline.find("xml version=\"1.0\" encoding=\"utf-8\"?><i") != std::string::npos or
headline.find("xml version=\"1.0\" encoding=\"Utf-8\"?>\n") != std::string::npos){
return 2;
}else if(headline.find("xml version=\"1.0\" encoding=\"UTF-8\"?><p") != std::string::npos or
headline.find("!-- BoonSutazioData=") != std::string::npos){
return 3;
}else{
return 0;
}
return 0;
}
bool CommentParser::Convert(int type){
if(!type){
std::ifstream input(in);
string headline;
getline(input,headline);
type = GetCommentType(headline);
input.close();
}
if(type == 2){
return _convertBilibili();
}else{
return false;
}
}
bool CommentParser::_convertBilibili(){
Ass *ass = new Ass;
ass->init(out);
ass->SetDuration(duration_marquee,duration_still);
ass->WriteHead(width, height, font, fontsize,alpha);
rapidxml::file<> xmlFile(in);
if(xmlFile.size() < 1){
return false;
}
rapidxml::xml_document<> doc;
xml_node<> *node;
try {
doc.parse<0>(xmlFile.data());
node = doc.first_node("i"); // Get comment main node
}catch(const rapidxml::parse_error& e){
std::cerr << "Parse error: " << e.what() << std::endl;
return false;
}
if(!node){
return false;
}
if(!node->first_node("d")){
return false;
}
for (xml_node<> *child = node->first_node("d"); child; child = child->next_sibling()) // Each comment
{
if(!child){
continue;
}
std::string v = child->value();
bool isBlocked = false;
for (auto i = blockWords.begin();i != blockWords.end(); i++ ){
if(v.find(*i) != std::string::npos){
isBlocked = true;
}
}
if(isBlocked){
continue;
}
const char *separator = ","; // Separator of comment properties
char *p;
/* Arg1 : Appear time
The time of comment appear.
*/
p = strtok(child->first_attribute("p")->value(), separator);
if(!p){ continue; }
float appear_time = atof(p);
/* Arg2 : Comment mode
123 - Scroll comment
4 - Bottom comment
5 - Top comment
6 - Reverse comment
7 - Positioned comment
8 - Javascript comment ( not convert )
*/
p = strtok(NULL, separator);
if(!p){ continue; }
int comment_mode = atoi(p);
/* Arg3 : Font size ( not needed )*/
p = strtok(NULL, separator);
if(!p){ continue; }
//int font_size = atoi(p);
/* Arg4 : Font color */
p = strtok(NULL, separator);
if(!p){ continue; }
int font_color = atoi(p);
/* Arg5 : Unix timestamp ( not needed ) */
/* Arg6 : comment pool ( not needed ) */
/* Arg7 : sender uid ( not needed ) */
/* Arg8 : database rowID ( not needed ) */
ass->AppendComment(appear_time, comment_mode, font_color, child->value());
}
ass->WriteToDisk(disallowModes);
return true;
}
/*
Convert comments to .ass subtitle
infile: comment file path
outfile: output file path
width: video width
height: video height
font: font name
alpha: comment alpha
duration_marquee:Duration of scrolling comment
duration_still:Duration of still comment
*/
void danmaku2ass(const char *infile,const char *outfile,int width,int height,const char *font,float fontsize,float alpha,float duration_marquee,float duration_still){
std::ifstream input(infile);
string headline;
getline(input,headline);
int type = GetCommentType(headline);
CommentParser *p = new CommentParser;
p->SetFile(infile, outfile);
p->SetRes(width, height);
p->SetFont(font, fontsize);
p->SetDuration(duration_marquee, duration_still);
p->SetAlpha(alpha);
if(type == 1){
//cout << "Avfun format detected ! Converting..." << endl;
cout << "Sorry , The format is not supported" << endl;
}else if(type == 2){
cout << "Bilibili format detected ! Converting..." << endl;
bool result = p->Convert(type);
if(result){
cout << "Convert succeed" << endl;
}else{
cout << "Convert failed" << endl;
}
}else if(type == 3){
//cout << "Niconico format detected ! Converting..." << endl;
cout << "Sorry , The format is not supported" << endl;
}else{
cout << "ERROR: Unable to get comment type" << endl;
}
input.close();
delete p;
}
#ifndef __danmaku2ass_native__NoMainFunc__
int main(int argc,char *argv[]){
cout << "Starting danmaku2ass native..." << endl;
clock_t begin = clock();
map<string,string> args;
int count;
for (count=0; count<argc; count++){
char *param = argv[count];
char *str = strchr(param,'='); // Get value for param
if(str){
int pos = (int)(str - param); // Get position of "="
char *keybuf = (char *)malloc(pos-1 * sizeof(char));
strncpy(keybuf, param + 1, (size_t)pos-1); // Get key for param
keybuf[pos-1] = '\0';
args[keybuf] = str+1;
}else{
continue;
}
}
danmaku2ass(
args["in"].c_str(), // Input file ( must be utf-8 )
args["out"].c_str(), // Output file
stoi(args["w"]), // Video width
stoi(args["h"]), // Video height
args["font"].c_str(), // Comment Font
stoi(args["fontsize"]), // Font Size
stof(args["alpha"]), // Comment Alpha
stof(args["dm"]), // Duration of scrolling comment
stof(args["ds"]) // Duration of still comment
);
clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
cout << "Exiting... Time taken:" << elapsed_secs << "s"<< endl;
return 0;
}
#endif