├── res
├── 00.jpg
├── 01.jpg
├── 02.jpg
├── tv.gif
├── icon.png
├── next.png
├── pause.png
├── play.png
├── sound.png
├── stop.png
├── previous.png
├── version.png
├── INFO
├── THANKS
├── Res.qrc
└── DATA
├── BiliLocal.ico
├── README.md
├── .gitignore
├── src
├── Jump.h
├── Editor.h
├── Shield.h
├── Plugin.h
├── Local.h
├── Post.h
├── Graphic.h
├── Info.h
├── Menu.h
├── Search.h
├── Jump.cpp
├── Plugin.cpp
├── Render.h
├── APlayer.h
├── List.h
├── Danmaku.h
├── Interface.h
├── Shield.cpp
├── Load.h
├── Utils.h
├── Config.h
├── Local.cpp
├── Post.cpp
├── Utils.cpp
├── Info.cpp
├── Graphic.cpp
├── List.cpp
├── Danmaku.cpp
├── Menu.cpp
├── Search.cpp
├── Editor.cpp
└── APlayer.cpp
└── BiliLocal.pro
/res/00.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esterTion/BiliLocal/HEAD/res/00.jpg
--------------------------------------------------------------------------------
/res/01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esterTion/BiliLocal/HEAD/res/01.jpg
--------------------------------------------------------------------------------
/res/02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esterTion/BiliLocal/HEAD/res/02.jpg
--------------------------------------------------------------------------------
/res/tv.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esterTion/BiliLocal/HEAD/res/tv.gif
--------------------------------------------------------------------------------
/BiliLocal.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esterTion/BiliLocal/HEAD/BiliLocal.ico
--------------------------------------------------------------------------------
/res/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esterTion/BiliLocal/HEAD/res/icon.png
--------------------------------------------------------------------------------
/res/next.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esterTion/BiliLocal/HEAD/res/next.png
--------------------------------------------------------------------------------
/res/pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esterTion/BiliLocal/HEAD/res/pause.png
--------------------------------------------------------------------------------
/res/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esterTion/BiliLocal/HEAD/res/play.png
--------------------------------------------------------------------------------
/res/sound.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esterTion/BiliLocal/HEAD/res/sound.png
--------------------------------------------------------------------------------
/res/stop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esterTion/BiliLocal/HEAD/res/stop.png
--------------------------------------------------------------------------------
/res/previous.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esterTion/BiliLocal/HEAD/res/previous.png
--------------------------------------------------------------------------------
/res/version.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esterTion/BiliLocal/HEAD/res/version.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | BiliLocal
2 | =========
3 |
4 | Add danmaku to local videos
5 |
6 | 
7 |
8 | 
9 |
10 | 
11 |
--------------------------------------------------------------------------------
/res/INFO:
--------------------------------------------------------------------------------
1 | {
2 | "Version": "0.4.2",
3 | "String": "[2015/2/18]\nVer_0.4.2\n增加纯弹幕透明模式\n增加A站番剧/C站支持\n大量问题修复",
4 | "Url": "http://tieba.baidu.com/p/3591706098"
5 | }
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.o
3 | *.user
4 | *.sh
5 | *.qm
6 | *.sln
7 | *.sdf
8 | *.suo
9 | *.vcxproj
10 | *.rc
11 | *.filters
12 | *.opensdf
13 | *.psd
14 | *.bak
15 | bin
16 | android
--------------------------------------------------------------------------------
/res/THANKS:
--------------------------------------------------------------------------------
1 | 感谢以下人员对BiliLocal做出的贡献
2 |
3 | Chaserhkj:
4 | 搜索窗口
5 | 界面结构调整
6 |
7 | 那么开始零崎吧(zhengdanwei):
8 | Mac OS版本编译
9 | 弹幕发送功能
10 |
11 | 云娘_PAPA本命:
12 | 测试
13 | 使用说明
14 |
15 | hungkie(samlls):
16 | 阻止屏幕变暗或关闭
17 |
18 | BiliLocal使用了以下库和插件
19 |
20 | VLC - Copyright (C) 1998-2013 VLC authors and VideoLAN
21 | FFmpeg - Copyright (C) 2000-2013 the FFmpeg developers
22 | Qt5 - Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
23 | OpenSSL - Copyright (C) 1998-2013 The OpenSSL Project.
--------------------------------------------------------------------------------
/res/Res.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | tv.gif
4 | pause.png
5 | play.png
6 | stop.png
7 | version.png
8 | icon.png
9 | sound.png
10 | next.png
11 | previous.png
12 |
13 |
14 | COPYING
15 | THANKS
16 | DATA
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/Jump.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Jump.h
6 | * Time: 2013/04/22
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #ifndef JUMP_H
28 | #define JUMP_H
29 |
30 | #include
31 | #include
32 |
33 | class Jump:public QWidget
34 | {
35 | Q_OBJECT
36 | public:
37 | Jump(QWidget *parent);
38 |
39 | private:
40 | QLineEdit * fileL;
41 | QPushButton * jumpB;
42 | };
43 |
44 | #endif // JUMP_H
45 |
--------------------------------------------------------------------------------
/src/Editor.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Editor.h
6 | * Time: 2013/06/30
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #ifndef EDITOR_H
28 | #define EDITOR_H
29 |
30 | #include
31 | #include
32 | #include
33 | #include
34 |
35 | class Editor:public QDialog
36 | {
37 | Q_OBJECT
38 | public:
39 | static void exec(QWidget *parent=0);
40 |
41 | private:
42 | QWidget *list;
43 | QWidget *pool;
44 | explicit Editor(QWidget *parent=0);
45 | };
46 |
47 | #endif // EDITOR_H
48 |
--------------------------------------------------------------------------------
/src/Shield.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Shield.h
6 | * Time: 2013/05/20
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #ifndef SHIELD_H
28 | #define SHIELD_H
29 |
30 | #include
31 |
32 | class Comment;
33 |
34 | class Shield
35 | {
36 | public:
37 | enum {Top,Bottom,Slide,Reverse,Guest,Advanced,Color,Whole};
38 | static bool shieldG[8];
39 | static QSet shieldS;
40 | static QList shieldR;
41 | static void load();
42 | static void save();
43 | static bool isBlocked(const Comment &comment);
44 | };
45 |
46 | #endif // SHIELD_H
47 |
--------------------------------------------------------------------------------
/src/Plugin.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Plugin.h
6 | * Time: 2013/04/23
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #ifndef PLUGIN_H
28 | #define PLUGIN_H
29 |
30 | #include
31 | #include
32 |
33 | class Plugin
34 | {
35 | public:
36 | typedef void (*RegistPtr)(const QHash &);
37 | typedef void (*ConfigPtr)(QWidget *);
38 | typedef QString (*StringPtr)(QString);
39 |
40 | static QList plugins;
41 | static void loadPlugins();
42 |
43 | Plugin(QString path);
44 | bool loaded();
45 | void regist(const QHash &);
46 | void config(QWidget *);
47 | QString string(QString query);
48 |
49 | private:
50 | RegistPtr m_regist;
51 | ConfigPtr m_config;
52 | StringPtr m_string;
53 | };
54 |
55 | #endif // PLUGIN_H
56 |
--------------------------------------------------------------------------------
/src/Local.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Local.h
6 | * Time: 2014/05/10
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #ifndef LOCAL_H
28 | #define LOCAL_H
29 |
30 | #include
31 | #include
32 |
33 | #define lApp (static_cast(QCoreApplication::instance()))
34 |
35 | class Local:public QApplication
36 | {
37 | Q_OBJECT
38 | public:
39 | Local(int &argc,char **argv);
40 |
41 | static Local *instance()
42 | {
43 | return lApp;
44 | }
45 |
46 | QWidget *mainWidget()
47 | {
48 | return qobject_cast(objects["Interface"]);
49 | }
50 |
51 | static QHash objects;
52 |
53 | public slots:
54 | QString suggestion(int code);
55 | void exit(int code=0);
56 |
57 | void synchronize(quintptr func)
58 | {
59 | ((void (*)())func)();
60 | }
61 | };
62 |
63 | #endif // LOCAL_H
64 |
--------------------------------------------------------------------------------
/res/DATA:
--------------------------------------------------------------------------------
1 | {
2 | "AcFunChannel": {
3 | "1": "动画",
4 | "100": "纪录片",
5 | "101": "演唱·乐器",
6 | "102": "宅舞",
7 | "103": "Vocaloid",
8 | "104": "ACG音乐",
9 | "105": "流行音乐",
10 | "106": "动画短片",
11 | "107": "MAD·AMV",
12 | "108": "MMD·3D",
13 | "109": "动画合集",
14 | "110": "文章综合",
15 | "42": "图库",
16 | "58": "音乐",
17 | "59": "游戏",
18 | "60": "娱乐",
19 | "63": "文章",
20 | "67": "新番连载",
21 | "68": "影视",
22 | "69": "体育",
23 | "70": "科技",
24 | "71": "Flash游戏",
25 | "72": "Mugen",
26 | "73": "工作·情感",
27 | "74": "动漫文化",
28 | "75": "漫画·小说",
29 | "76": "页游资料",
30 | "77": "1区",
31 | "78": "21区",
32 | "79": "31区",
33 | "80": "41区",
34 | "81": "文章里区(不审)",
35 | "82": "视频里区(不审)",
36 | "83": "游戏集锦",
37 | "84": "实况解说",
38 | "85": "英雄联盟",
39 | "86": "生活娱乐",
40 | "87": "鬼畜调教",
41 | "88": "萌宠",
42 | "89": "美食",
43 | "90": "科普",
44 | "91": "数码",
45 | "92": "军事",
46 | "93": "惊奇体育",
47 | "94": "足球",
48 | "95": "篮球",
49 | "96": "电影",
50 | "97": "剧集",
51 | "98": "综艺",
52 | "99": "特摄·霹雳"
53 | },
54 | "AcPlayChannel": {
55 | "1": "TV剧集",
56 | "2": "TV特别篇",
57 | "3": "OVA",
58 | "4": "剧场版",
59 | "5": "MV",
60 | "6": "网络放送",
61 | "7": "其他",
62 | "99": "未知"
63 | },
64 | "Logo": {
65 | "DirectX": "https://upload.wikimedia.org/wikipedia/commons/1/11/DirectX_logo.png",
66 | "FFmpeg": "http://www.ffmpeg.org/ffmpeg-logo.png",
67 | "OpenGL": "https://www.khronos.org/assets/uploads/ceimg/made/assets/uploads/apis/OpenGL-ES_300_199_75.png",
68 | "VLC": "http://images.videolan.org/images/logoOrange.png"
69 | },
70 | "Version": "0.4.2"
71 | }
72 |
--------------------------------------------------------------------------------
/src/Post.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Post.h
6 | * Time: 2013/05/23
7 | * Author: zhengdanwei
8 | * Contributor: Lysine
9 | *
10 | * Lysine is a student majoring in Software Engineering
11 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
12 | *
13 | * This program is free software: you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation, either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * This program is distributed in the hope that it will be useful,
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | * GNU General Public License for more details.
22 |
23 | * You should have received a copy of the GNU General Public License
24 | * along with this program. If not, see .
25 | *
26 | =========================================================================*/
27 |
28 | #ifndef POST_H
29 | #define POST_H
30 |
31 | #include
32 | #include
33 | #include
34 | #include "Utils.h"
35 |
36 | class Post:public QWidget
37 | {
38 | Q_OBJECT
39 | public:
40 | Post(QWidget *parent);
41 |
42 | private:
43 | QAction * commentA;
44 | QLineEdit * commentL;
45 | QComboBox * commentS;
46 | QComboBox * commentM;
47 | QPushButton * commentC;
48 | QPushButton * commentB;
49 | QNetworkAccessManager *manager;
50 | static Post *ins;
51 |
52 | Comment getComment();
53 | QList getRecords();
54 |
55 | signals:
56 | void posted(const Comment *);
57 |
58 | public slots:
59 | QColor getColor();
60 | void setColor(QColor);
61 | void postComment();
62 | bool isValid();
63 | void setVisible(bool);
64 | };
65 |
66 | #endif // POST_H
67 |
--------------------------------------------------------------------------------
/src/Graphic.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Graphic.h
6 | * Time: 2013/10/19
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #ifndef GRAPHIC_H
28 | #define GRAPHIC_H
29 |
30 | #include
31 | #include
32 | #include "Utils.h"
33 |
34 | class Graphic
35 | {
36 | public:
37 | virtual bool move(qint64 time)=0;
38 | virtual void draw(QPainter *painter)=0;
39 | virtual uint intersects(Graphic *other)=0;
40 | virtual QRectF ¤tRect(){return rect;}
41 | virtual ~Graphic(){}
42 |
43 | inline int getMode(){return source?source->mode:0;}
44 |
45 | inline bool isEnabled(){return enabled;}
46 | inline void setEnabled(bool _enabled){enabled=_enabled;}
47 |
48 | inline quint64 getIndex(){return index;}
49 | void setIndex();
50 |
51 | inline const Comment *getSource(){return source;}
52 | inline void setSource(const Comment *_source){source=_source;}
53 |
54 | static Graphic *create(const Comment &comment);
55 |
56 | protected:
57 | bool enabled;
58 | QRectF rect;
59 | quint64 index;
60 | const Comment *source;
61 | Graphic():enabled(false),source(NULL){}
62 | };
63 |
64 | #endif // GRAPHIC_H
65 |
--------------------------------------------------------------------------------
/src/Info.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Info.h
6 | * Time: 2013/04/05
7 | * Author: Lysine
8 | * Contributor: Chaserhkj
9 | *
10 | * Lysine is a student majoring in Software Engineering
11 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
12 | *
13 | * This program is free software: you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation, either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * This program is distributed in the hope that it will be useful,
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | * GNU General Public License for more details.
22 |
23 | * You should have received a copy of the GNU General Public License
24 | * along with this program. If not, see .
25 | *
26 | =========================================================================*/
27 |
28 | #ifndef INFO_H
29 | #define INFO_H
30 |
31 | #include
32 | #include
33 |
34 | class Info:public QWidget
35 | {
36 | Q_OBJECT
37 | public:
38 | explicit Info(QWidget *parent=0);
39 | bool isShown(){return isPoped;}
40 | bool preferStay(){return isStay;}
41 |
42 | private:
43 | bool isStay;
44 | bool isPoped;
45 | bool updating;
46 | qint64 duration;
47 |
48 | QLabel *duraT;
49 | QLabel *timeT;
50 | QLabel *volmT;
51 | QLabel *plfmT;
52 | QSlider *timeS;
53 | QSlider *volmS;
54 | QLineEdit *plfmL;
55 | QTableView *danmV;
56 | QPushButton *playB;
57 | QPushButton *stopB;
58 | QAction *playA;
59 | QAction *stopA;
60 | QIcon playI,stopI,pausI;
61 | QPropertyAnimation *animation;
62 | void resizeEvent(QResizeEvent *e);
63 | void setTime(qint64 _time);
64 | void setDuration(qint64 _duration);
65 |
66 | public slots:
67 | void pop();
68 | void push(bool force=false);
69 | void terminate();
70 | void resizeHeader();
71 |
72 | };
73 |
74 | #endif // INFO_H
75 |
--------------------------------------------------------------------------------
/BiliLocal.pro:
--------------------------------------------------------------------------------
1 | QT += \
2 | core \
3 | gui \
4 | network \
5 | widgets
6 |
7 | TARGET = BiliLocal
8 |
9 | TEMPLATE = app
10 |
11 | CONFIG += c++11
12 |
13 | INCLUDEPATH += \
14 | C:/msys64/usr/local/include
15 |
16 | LIBS += \
17 | -LC:/msys64/usr/local/lib
18 |
19 | SOURCES += \
20 | src/APlayer.cpp \
21 | src/Config.cpp \
22 | src/Danmaku.cpp \
23 | src/Graphic.cpp \
24 | src/List.cpp \
25 | src/Load.cpp \
26 | src/Local.cpp \
27 | src/Render.cpp \
28 | src/Shield.cpp \
29 | src/Utils.cpp \
30 | src/Interface.cpp \
31 | src/Menu.cpp \
32 | src/Info.cpp \
33 | src/Editor.cpp \
34 | src/Post.cpp \
35 | src/Jump.cpp \
36 | src/Search.cpp \
37 | src/Plugin.cpp
38 |
39 | HEADERS += \
40 | src/APlayer.h \
41 | src/Config.h \
42 | src/Danmaku.h \
43 | src/Graphic.h \
44 | src/List.h \
45 | src/Load.h \
46 | src/Local.h \
47 | src/Render.h \
48 | src/Shield.h \
49 | src/Utils.h \
50 | src/Interface.h \
51 | src/Menu.h \
52 | src/Info.h \
53 | src/Editor.h \
54 | src/Post.h \
55 | src/Jump.h \
56 | src/Search.h \
57 | src/Plugin.h
58 |
59 | RESOURCES += \
60 | res/Res.qrc
61 |
62 | TRANSLATIONS += \
63 | res/zh_CN.ts \
64 | res/zh_TW.ts
65 |
66 | linux{
67 | DEFINES += \
68 | BACKEND_VLC
69 |
70 | DEFINES += \
71 | RENDER_RASTER \
72 | RENDER_OPENGL
73 | }
74 |
75 | win32{
76 | RC_ICONS = BiliLocal.ico
77 |
78 | DEFINES += \
79 | BACKEND_VLC \
80 | BACKEND_QMM \
81 | BACKEND_NIL
82 |
83 | DEFINES += \
84 | RENDER_RASTER \
85 | RENDER_OPENGL \
86 | RENDER_DETACH
87 | }
88 |
89 | macx{
90 | DEFINES += \
91 | BACKEND_VLC
92 |
93 | DEFINES += \
94 | RENDER_OPENGL
95 | }
96 |
97 | contains(DEFINES, BACKEND_QMM){
98 | QT += \
99 | multimedia
100 | }
101 |
102 | contains(DEFINES, BACKEND_VLC){
103 | LIBS += \
104 | -lvlc \
105 | -lvlccore
106 | }
107 |
108 | contains(DEFINES, RENDER_RASTER){
109 | LIBS += \
110 | -lswscale \
111 | -lavutil
112 | }
113 |
--------------------------------------------------------------------------------
/src/Menu.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Menu.h
6 | * Time: 2013/04/05
7 | * Author: Lysine
8 | * Contributor: Chaserhkj
9 | *
10 | * Lysine is a student majoring in Software Engineering
11 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
12 | *
13 | * This program is free software: you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation, either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * This program is distributed in the hope that it will be useful,
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | * GNU General Public License for more details.
22 |
23 | * You should have received a copy of the GNU General Public License
24 | * along with this program. If not, see .
25 | *
26 | =========================================================================*/
27 |
28 | #ifndef MENU_H
29 | #define MENU_H
30 |
31 | #include
32 | #include
33 |
34 | class Menu:public QWidget
35 | {
36 | Q_OBJECT
37 | public:
38 | explicit Menu(QWidget *parent=0);
39 | bool isShown(){return isPoped;}
40 | bool preferStay(){return isStay||!danmC->popup()->isHidden();}
41 |
42 | private:
43 | bool isStay;
44 | bool isPoped;
45 | QLineEdit *fileL;
46 | QLineEdit *danmL;
47 | QLineEdit *sechL;
48 | QCompleter *fileC;
49 | QCompleter *danmC;
50 | QPushButton *fileB;
51 | QPushButton *danmB;
52 | QPushButton *sechB;
53 | QAction *fileA;
54 | QAction *danmA;
55 | QAction *sechA;
56 | QLabel *alphaT;
57 | QSlider *alphaS;
58 | QLabel *powerT;
59 | QLineEdit *powerL;
60 | QLabel *localT;
61 | QCheckBox *localC;
62 | QLabel *subT;
63 | QCheckBox *subC;
64 | QLabel *loopT;
65 | QCheckBox *loopC;
66 | QPropertyAnimation *animation;
67 | void resizeEvent(QResizeEvent *e);
68 | bool eventFilter(QObject *o,QEvent *e);
69 |
70 | public slots:
71 | void pop();
72 | void push(bool force=false);
73 | void terminate();
74 |
75 | };
76 |
77 | #endif // MENU_H
78 |
--------------------------------------------------------------------------------
/src/Search.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Search.h
6 | * Time: 2013/04/18
7 | * Author: Chaserhkj
8 | * Contributor: Lysine
9 | *
10 | * Lysine is a student majoring in Software Engineering
11 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
12 | *
13 | * This program is free software: you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation, either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * This program is distributed in the hope that it will be useful,
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | * GNU General Public License for more details.
22 |
23 | * You should have received a copy of the GNU General Public License
24 | * along with this program. If not, see .
25 | *
26 | =========================================================================*/
27 |
28 | #ifndef SEARCH_H
29 | #define SEARCH_H
30 |
31 | #include
32 | #include
33 | #include
34 |
35 | class Search:public QDialog
36 | {
37 | Q_OBJECT
38 | public:
39 | explicit Search(QWidget *parent=0);
40 | inline QString getKey(){return key;}
41 | inline QString getAid(){return aid;}
42 |
43 | private:
44 | QLabel *statusL;
45 | QLabel *pageT;
46 | QLabel *pageL;
47 | QLineEdit *keywE;
48 | QLineEdit *pageE;
49 | QComboBox *orderC;
50 | QComboBox *sitesC;
51 | QPushButton *okB;
52 | QPushButton *ccB;
53 | QPushButton *searchB;
54 | QPushButton *pageUpB;
55 | QPushButton *pageDnB;
56 | QPushButton *pageGoB;
57 | QTreeWidget *resultW;
58 | QNetworkAccessManager *manager;
59 | QSet remain;
60 |
61 | QString key;
62 | QString aid;
63 |
64 | int pageNum;
65 | int pageCur;
66 | bool isWaiting;
67 |
68 | void getData(int pageNum);
69 | QList getOrder(int site);
70 |
71 | public slots:
72 | void setText(QString text);
73 | void setSite();
74 | void startSearch();
75 | void clearSearch();
76 | void accept();
77 |
78 | };
79 |
80 | #endif // SEARCH_H
81 |
--------------------------------------------------------------------------------
/src/Jump.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Jump.cpp
6 | * Time: 2013/04/22
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #include "Jump.h"
28 | #include "APlayer.h"
29 | #include "List.h"
30 | #include "Local.h"
31 |
32 | Jump::Jump(QWidget *parent):
33 | QWidget(parent)
34 | {
35 | setFixedSize(parent->minimumWidth(),25);
36 | setObjectName("Jump");
37 |
38 | auto layout=new QHBoxLayout(this);
39 | layout->setMargin(0);layout->setSpacing(0);
40 |
41 | fileL=new QLineEdit(this);
42 | fileL->setReadOnly(true);
43 | fileL->setFocusPolicy(Qt::NoFocus);
44 | layout->addWidget(fileL);
45 |
46 | jumpB=new QPushButton(this);
47 | jumpB->setFixedWidth(55);
48 | connect(jumpB,&QPushButton::clicked,[this](){
49 | QStandardItem *c=List::instance()->getCurrent();
50 | APlayer::instance()->setTime(c->data(List::TimeRole).toDouble());
51 | hide();
52 | });
53 | layout->addWidget(jumpB);
54 |
55 | connect(APlayer::instance(),&APlayer::begin,[this](){
56 | QStandardItem *c=List::instance()->getCurrent();
57 | if(!c){
58 | return;
59 | }
60 | qint64 t=c->data(List::TimeRole).toDouble()/1000;
61 | if (t<=0){
62 | return;
63 | }
64 | fileL->setText(c->text());
65 | QString time("%1:%2");
66 | time=time.arg(t/60,2,10,QChar('0'));
67 | time=time.arg(t%60,2,10,QChar('0'));
68 | jumpB->setText(time);
69 | show();
70 | });
71 | hide();
72 | }
73 |
--------------------------------------------------------------------------------
/src/Plugin.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Plugin.cpp
6 | * Time: 2013/04/23
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #include "Plugin.h"
28 | #include "Local.h"
29 | #include "Config.h"
30 |
31 | QList Plugin::plugins;
32 |
33 | Plugin::Plugin(QString path)
34 | {
35 | m_regist=(RegistPtr)QLibrary::resolve(path,"regist");
36 | m_config=(ConfigPtr)QLibrary::resolve(path,"config");
37 | m_string=(StringPtr)QLibrary::resolve(path,"string");
38 | }
39 |
40 | bool Plugin::loaded()
41 | {
42 | return m_regist&&m_config&&m_string;
43 | }
44 |
45 | void Plugin::regist(const QHash &objects)
46 | {
47 | if (m_regist)
48 | m_regist(objects);
49 | }
50 |
51 | void Plugin::config(QWidget *parent)
52 | {
53 | if (m_config)
54 | m_config(parent);
55 | }
56 |
57 | QString Plugin::string(QString query)
58 | {
59 | return m_string(query);
60 | }
61 |
62 | void Plugin::loadPlugins()
63 | {
64 | QFileInfoList list = QDir("./plugins/bililocal/").entryInfoList();
65 | for(const QFileInfo &info:list){
66 | if(info.isFile()&&QLibrary::isLibrary(info.fileName())){
67 | Plugin lib(info.absoluteFilePath());
68 | if(lib.loaded()){
69 | if(Config::getValue("/Plugin/"+lib.string("Name"),true)){
70 | lib.regist(Local::objects);
71 | }
72 | else{
73 | lib.m_config=nullptr;
74 | lib.m_regist=nullptr;
75 | }
76 | plugins.append(lib);
77 | }
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Render.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Render.h
6 | * Time: 2013/12/27
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #ifndef RENDER_H
28 | #define RENDER_H
29 |
30 | #include
31 | #include
32 | #include
33 |
34 | class RenderPrivate;
35 |
36 | class Render:public QObject
37 | {
38 | Q_OBJECT
39 | public:
40 | class ICache
41 | {
42 | public:
43 | virtual void draw(QPainter *,QRectF)=0;
44 | virtual ~ICache()=default;
45 | };
46 |
47 | virtual ~Render();
48 | static Render *instance();
49 |
50 | protected:
51 | static Render *ins;
52 | RenderPrivate *const d_ptr;
53 | Q_DECLARE_PRIVATE(Render)
54 |
55 | Render(RenderPrivate *data,QObject *parent=0);
56 |
57 | signals:
58 | void refreshRateChanged(int);
59 |
60 | public slots:
61 | virtual QList getBuffer();
62 | virtual void releaseBuffer();
63 | virtual void setBuffer(QString &chroma,QSize size,QList *bufferSize=0);
64 | virtual ICache *getCache(const QImage &)=0;
65 |
66 | void setBackground(QString path);
67 | void setMusic(bool music);
68 | void setDisplayTime(double t);
69 | void setVideoAspectRatio(double ratio);
70 | void setPixelAspectRatio(double ratio);
71 | virtual quintptr getHandle()=0;
72 | virtual void resize(QSize size)=0;
73 | virtual void setRefreshRate(int rate,bool soft=false);
74 | virtual QSize getBufferSize()=0;
75 | virtual QSize getActualSize()=0;
76 | virtual QSize getPreferredSize();
77 | virtual void draw(QRect rect=QRect())=0;
78 | };
79 |
80 | #endif // RENDER_H
81 |
--------------------------------------------------------------------------------
/src/APlayer.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: APlayer.h
6 | * Time: 2013/03/18
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #ifndef APLAYER_H
28 | #define APLAYER_H
29 |
30 | #include
31 | #include
32 |
33 | class APlayer:public QObject
34 | {
35 | Q_OBJECT
36 | public:
37 | enum State
38 | {
39 | Stop,
40 | Play,
41 | Pause,
42 | Loop
43 | };
44 |
45 | enum Error
46 | {
47 | UnknownError,
48 | ResourceError,
49 | FormatError,
50 | NetworkError,
51 | AccessDeniedError,
52 | ServiceMissingError
53 | };
54 |
55 | virtual QList getTracks(int type)=0;
56 | static APlayer *instance();
57 |
58 | protected:
59 | static APlayer *ins;
60 | APlayer(QObject *parent=0):QObject(parent){}
61 |
62 | signals:
63 | void errorOccurred(int);
64 | void begin();
65 | void reach(bool);
66 | void decode();
67 | void jumped(qint64);
68 | void timeChanged(qint64);
69 | void stateChanged(int);
70 | void mediaChanged(QString);
71 | void volumeChanged(int);
72 |
73 | public slots:
74 | virtual void play()=0;
75 | virtual void stop(bool manually=true)=0;
76 | virtual int getState()=0;
77 |
78 | virtual void setTime(qint64 _time)=0;
79 | virtual qint64 getTime()=0;
80 |
81 | virtual void setMedia(QString _file,bool manually=true)=0;
82 | virtual QString getMedia()=0;
83 |
84 | virtual qint64 getDuration()=0;
85 | virtual void addSubtitle(QString _file)=0;
86 |
87 | virtual void setVolume(int _volume)=0;
88 | virtual int getVolume()=0;
89 |
90 | virtual void event(int type)=0;
91 | };
92 |
93 | #endif // APLAYER_H
94 |
--------------------------------------------------------------------------------
/src/List.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: List.h
6 | * Time: 2014/11/19
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #ifndef LIST_H
28 | #define LIST_H
29 |
30 | #include
31 | #include
32 |
33 | class List:public QStandardItemModel
34 | {
35 | Q_OBJECT
36 | public:
37 | enum Role
38 | {
39 | FileRole=Qt::UserRole,
40 | CodeRole,
41 | TimeRole,
42 | DateRole
43 | };
44 |
45 | enum Danm
46 | {
47 | Records,
48 | Inherit,
49 | Surmise
50 | };
51 |
52 | ~List();
53 | void saveList();
54 | static List *instance();
55 | QStringList mimeTypes() const;
56 | QMimeData *mimeData(const QModelIndexList &) const;
57 | bool dropMimeData(const QMimeData *,Qt::DropAction,int,int,const QModelIndex &p);
58 |
59 | private:
60 | QStandardItem *cur;
61 | qint64 time;
62 | QList icons;
63 | static List *ins;
64 | List(QObject *parent);
65 | void setRelated(const QModelIndexList &indexes,int reason);
66 |
67 | public slots:
68 | QString defaultPath(int type);
69 | QStandardItem *getCurrent(){return cur;}
70 | QStandardItem *itemFromFile(QString file,bool create=false);
71 | bool finished();
72 | void appendMedia(QString file);
73 | void updateCurrent();
74 | void split(const QModelIndex &index);
75 | void split(const QModelIndexList &indexes);
76 | void waste(const QModelIndex &index);
77 | void waste(const QModelIndexList &indexes);
78 | void merge(const QModelIndexList &indexes);
79 | void group(const QModelIndexList &indexes);
80 | void jumpToLast();
81 | void jumpToNext();
82 | bool jumpToIndex(const QModelIndex &index,bool manually=true);
83 | };
84 |
85 | #endif // LIST_H
86 |
--------------------------------------------------------------------------------
/src/Danmaku.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Danmaku.h
6 | * Time: 2013/03/18
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #ifndef DANMAKU_H
28 | #define DANMAKU_H
29 |
30 | #include
31 | #include
32 | #include "Utils.h"
33 |
34 | class Graphic;
35 |
36 | class Danmaku:public QAbstractItemModel
37 | {
38 | Q_OBJECT
39 | public:
40 | ~Danmaku();
41 | QList &getPool(){return pool;}
42 | void draw(QPainter *painter,qint64 move);
43 | QVariant data(const QModelIndex &index,int role) const;
44 | int rowCount(const QModelIndex &parent=QModelIndex()) const;
45 | int columnCount(const QModelIndex &parent=QModelIndex()) const;
46 | QModelIndex parent(const QModelIndex &) const;
47 | QModelIndex index(int row,int colum,const QModelIndex &parent=QModelIndex()) const;
48 | QVariant headerData(int section,Qt::Orientation orientation,int role) const;
49 | static Danmaku *instance();
50 |
51 | private:
52 | int cur;
53 | qint64 time;
54 | QList pool;
55 | QList danmaku;
56 | QList current;
57 | mutable QReadWriteLock lock;
58 | static Danmaku *ins;
59 |
60 | Danmaku(QObject *parent=0);
61 | void setTime(qint64 _time);
62 |
63 | signals:
64 | void alphaChanged(int);
65 | void unrecognizedComment(const Comment *);
66 |
67 | public slots:
68 | void setAlpha(int _alpha);
69 | void resetTime();
70 | void clearPool();
71 | void appendToPool(const Record *record);
72 | void appendToPool(QString source,const Comment *comment);
73 | void clearCurrent(bool soft=false);
74 | void insertToCurrent(Graphic *graphic,int index=-1);
75 | const Comment *commentAt(QPoint point) const;
76 | void parse(int flag=0);
77 | void delayAll(qint64 _time);
78 | void jumpToTime(qint64 _time);
79 | void saveToFile(QString file);
80 | };
81 |
82 | #endif // DANMAKU_H
83 |
--------------------------------------------------------------------------------
/src/Interface.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Interface.h
6 | * Time: 2013/03/18
7 | * Author: Lysine
8 | * Contributor: Chaserhkj
9 | *
10 | * Lysine is a student majoring in Software Engineering
11 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
12 | *
13 | * This program is free software: you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation, either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * This program is distributed in the hope that it will be useful,
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | * GNU General Public License for more details.
22 |
23 | * You should have received a copy of the GNU General Public License
24 | * along with this program. If not, see .
25 | *
26 | =========================================================================*/
27 |
28 | #ifndef INTERFACE_H
29 | #define INTERFACE_H
30 |
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | class Render;
37 | class Menu;
38 | class Info;
39 | class Jump;
40 | class Post;
41 | class List;
42 | class Load;
43 | class APlayer;
44 | class Danmaku;
45 | class Message;
46 |
47 | class Interface:public QWidget
48 | {
49 | Q_OBJECT
50 | public:
51 | explicit Interface(QWidget *parent=0);
52 |
53 | private:
54 | QTimer *timer;
55 | QTimer *delay;
56 |
57 | QAction *quitA;
58 | QAction *fullA;
59 | QAction *confA;
60 | QAction *toggA;
61 | QAction *listA;
62 | QAction *postA;
63 | QMenu *rat;
64 | QMenu *sca;
65 |
66 | Render *render;
67 | Menu *menu;
68 | Info *info;
69 | Jump *jump;
70 | Post *post;
71 | List *list;
72 | Load *load;
73 | APlayer *aplayer;
74 | Danmaku *danmaku;
75 | Message *message;
76 |
77 | QPoint sta;
78 | QPoint wgd;
79 | QByteArray geo;
80 |
81 | bool showprg;
82 | bool sliding;
83 |
84 | void closeEvent(QCloseEvent *e);
85 | void dragEnterEvent(QDragEnterEvent *e);
86 | void dropEvent(QDropEvent *e);
87 | void mouseDoubleClickEvent(QMouseEvent *e);
88 | void mouseMoveEvent(QMouseEvent *e);
89 | void mousePressEvent(QMouseEvent *e);
90 | void mouseReleaseEvent(QMouseEvent *e);
91 | void resizeEvent(QResizeEvent *e);
92 |
93 | signals:
94 | void windowFlagsChanged(QFlags);
95 |
96 | public slots:
97 | void tryLocal(QString p);
98 | void tryLocal(QStringList p);
99 | void setWindowFlags();
100 |
101 | private slots:
102 | void checkForUpdate();
103 | void setCenter(QSize s,bool f);
104 | void showContextMenu(QPoint p);
105 | };
106 |
107 | #endif // INTERFACE_H
108 |
--------------------------------------------------------------------------------
/src/Shield.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Shield.cpp
6 | * Time: 2013/05/20
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #include "Shield.h"
28 | #include "Utils.h"
29 | #include "Config.h"
30 |
31 | bool Shield::shieldG[8];
32 | QSet Shield::shieldS;
33 | QList Shield::shieldR;
34 |
35 | void Shield::load()
36 | {
37 | QJsonArray s=Config::getValue("/Shield/Sender");
38 | QJsonArray r=Config::getValue("/Shield/Regexp");
39 | for(const QJsonValue &item:s){
40 | shieldS.insert(item.toString());
41 | }
42 | for(const QJsonValue &item:r){
43 | shieldR.append(QRegularExpression(item.toString()));
44 | }
45 | int group=Config::getValue("/Shield/Group",0);
46 | for(int i=7;i>=0;--i){
47 | shieldG[i]=group&1;
48 | group=group>>1;
49 | }
50 | }
51 |
52 | void Shield::save()
53 | {
54 | QJsonArray s,r;
55 | for(auto &item:shieldS){
56 | s.append(item);
57 | }
58 | Config::setValue("/Shield/Sender",s);
59 | for(auto &item:shieldR){
60 | r.append(item.pattern());
61 | }
62 | Config::setValue("/Shield/Regexp",r);
63 | int g=0;
64 | for(int i=0;i<8;++i){
65 | g=(g<<1)+shieldG[i];
66 | }
67 | Config::setValue("/Shield/Group",g);
68 | }
69 |
70 | bool Shield::isBlocked(const Comment &comment)
71 | {
72 | if(shieldG[Whole]
73 | ||(comment.mode==1&&shieldG[Slide])
74 | ||(comment.mode==4&&shieldG[Bottom])
75 | ||(comment.mode==5&&shieldG[Top])
76 | ||(comment.mode==6&&shieldG[Reverse])
77 | ||(shieldG[Advanced]&&(comment.mode==7||comment.mode==8))
78 | ||(comment.color!=0xFFFFFF&&shieldG[Color])){
79 | return true;
80 | }
81 | if(shieldG[Guest]){
82 | if(comment.sender.length()==14&&comment.sender[3]=='k'){
83 | return true;
84 | }
85 | if(comment.sender.startsWith('D',Qt::CaseInsensitive)){
86 | return true;
87 | }
88 | if(comment.sender=="0"){
89 | return true;
90 | }
91 | }
92 | if(shieldS.contains(comment.sender)){
93 | return true;
94 | }
95 | for(const QRegularExpression &r:shieldR){
96 | if(r.match(comment.string).hasMatch()){
97 | return true;
98 | }
99 | }
100 | return false;
101 | }
102 |
--------------------------------------------------------------------------------
/src/Load.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Load.h
6 | * Time: 2014/04/22
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #ifndef LOAD_H
28 | #define LOAD_H
29 |
30 | #include
31 | #include
32 | #include
33 | #include
34 |
35 | class Record;
36 |
37 | class Load:public QObject
38 | {
39 | Q_OBJECT
40 | public:
41 | enum State
42 | {
43 | None=0,
44 | Page=381,
45 | Part=407,
46 | Code=379,
47 | File=384,
48 | };
49 |
50 | enum Role
51 | {
52 | UrlRole=Qt::UserRole,
53 | StrRole,
54 | NxtRole
55 | };
56 |
57 | struct Proc
58 | {
59 | std::function regular;
60 | int priority;
61 | std::function process;
62 | };
63 |
64 | struct Task
65 | {
66 | QString code;
67 | QNetworkRequest request;
68 | int state;
69 | const Proc *processer;
70 | qint64 delay;
71 | Task():state(None),processer(nullptr),delay(0){}
72 | };
73 |
74 | Task codeToTask(QString code);
75 | static Load *instance();
76 |
77 | private:
78 | QStandardItemModel *model;
79 | QList pool;
80 | QNetworkAccessManager *manager;
81 | QQueue queue;
82 | QSet remain;
83 | static Load *ins;
84 | Load(QObject *parent=0);
85 |
86 | signals:
87 | void stateChanged(int state);
88 | void errorOccured(int state);
89 | void progressChanged(double progress);
90 |
91 | public slots:
92 | void addProc(const Proc *proc);
93 | const Proc *getProc(QString code);
94 |
95 | void fixCode(QString &);
96 | bool canLoad(QString);
97 | bool canFull(const Record *);
98 | bool canHist(const Record *);
99 |
100 | void loadDanmaku(QString);
101 | void loadDanmaku(const QModelIndex &index=QModelIndex());
102 | void fullDanmaku(const Record *);
103 | void loadHistory(const Record *,QDate);
104 | void dumpDanmaku(const QByteArray &data,int site,Record *r);
105 | void dumpDanmaku(const QByteArray &data,int site,bool full);
106 |
107 | QStandardItemModel *getModel();
108 | int size(){return queue.size();}
109 | void dequeue();
110 | bool enqueue(const Task &);
111 | Task*getHead();
112 | void forward();
113 | void forward(QNetworkRequest);
114 | void forward(QNetworkRequest,int);
115 | };
116 |
117 | #endif // LOAD_H
118 |
--------------------------------------------------------------------------------
/src/Utils.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Utils.h
6 | * Time: 2013/05/10
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #ifndef UTILS_H
28 | #define UTILS_H
29 |
30 | #include
31 | #include
32 | #include
33 |
34 | class Comment
35 | {
36 | public:
37 | int mode;
38 | int font;
39 | int color;
40 | qint64 time;
41 | qint64 date;
42 | QString sender;
43 | QString string;
44 | bool blocked;
45 | Comment()
46 | {
47 | mode=font=color=time=date=0;
48 | blocked=false;
49 | }
50 | inline bool operator <(const Comment &o) const
51 | {
52 | return time danmaku;
85 | Record()
86 | {
87 | full=false;
88 | delay=limit=0;
89 | }
90 | };
91 |
92 | namespace Utils
93 | {
94 | enum Site
95 | {
96 | Unknown,
97 | Bilibili,
98 | AcFun,
99 | Tudou,
100 | Letv,
101 | AcPlay,
102 | AcfunLocalizer,
103 | Niconico,
104 | TuCao
105 | };
106 |
107 | enum Type
108 | {
109 | Video=1,
110 | Audio=2,
111 | Subtitle=4,
112 | Danmaku=8
113 | };
114 |
115 | Site parseSite(QString url);
116 | void setCenter(QWidget *widget);
117 | void setGround(QWidget *widget,QColor color);
118 | QString defaultFont(bool monospace=false);
119 | QString customUrl(Site site);
120 | QString decodeXml(QString string,bool fast=false);
121 | QStringList getRenderModules();
122 | QStringList getDecodeModules();
123 | QStringList getSuffix(int type,QString format="");
124 | double evaluate(QString expression);
125 | }
126 |
127 | #endif // UTILS_H
128 |
--------------------------------------------------------------------------------
/src/Config.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Config.h
6 | * Time: 2013/06/17
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #ifndef CONFIG_H
28 | #define CONFIG_H
29 |
30 | #include
31 | #include
32 | #include
33 |
34 | namespace{
35 | template
36 | TypeName fromJsonValue(QJsonValue v)
37 | {
38 | QVariant t=v.toVariant();
39 | if(!t.canConvert()){
40 | throw("type missmatch");
41 | }
42 | return t.value();
43 | }
44 |
45 | template<>
46 | QVariant fromJsonValue(QJsonValue v)
47 | {
48 | return v.toVariant();
49 | }
50 |
51 | template<>
52 | QJsonArray fromJsonValue(QJsonValue v)
53 | {
54 | if (QJsonValue::Array!=v.type()){
55 | throw("type missmatch");
56 | }
57 | return v.toArray();
58 | }
59 |
60 | template<>
61 | QJsonObject fromJsonValue(QJsonValue v)
62 | {
63 | if (QJsonValue::Object!=v.type()){
64 | throw("type missmatch");
65 | }
66 | return v.toObject();
67 | }
68 |
69 | template
70 | QJsonValue toJsonValue(TypeName v)
71 | {
72 | return QJsonValue(v);
73 | }
74 |
75 | template<>
76 | QJsonValue toJsonValue(QVariant v)
77 | {
78 | return QJsonValue::fromVariant(v);
79 | }
80 | }
81 |
82 | class Config:public QObject
83 | {
84 | Q_OBJECT
85 | public:
86 | explicit Config(QObject *parent=0);
87 |
88 | template
89 | static T getValue(QString key,T def=T())
90 | {
91 | QStringList tree=key.split('/',QString::SkipEmptyParts);
92 | QString last=tree.takeLast();
93 | QJsonObject cur=config;
94 | QList path;
95 | for(const QString &k:tree){
96 | path.append(cur);
97 | cur=cur.value(k).toObject();
98 | }
99 | if (cur.contains(last)){
100 | try{
101 | return fromJsonValue(cur.value(last));
102 | }
103 | catch(...){}
104 | }
105 | QJsonValue val=toJsonValue(def);
106 | if(!val.isNull()){
107 | cur[last]=val;
108 | while(!path.isEmpty()){
109 | QJsonObject pre=path.takeLast();
110 | pre[tree.takeLast()]=cur;
111 | cur=pre;
112 | }
113 | config=cur;
114 | }
115 | return def;
116 | }
117 |
118 | template
119 | static void setValue(QString key,T set)
120 | {
121 | QStringList tree=key.split('/',QString::SkipEmptyParts);
122 | QString last=tree.takeLast();
123 | QJsonObject cur=config;
124 | QList path;
125 | for(const QString &k:tree){
126 | path.append(cur);
127 | cur=cur.value(k).toObject();
128 | }
129 | cur[last]=toJsonValue(set);
130 | while(!path.isEmpty()){
131 | QJsonObject pre=path.takeLast();
132 | pre[tree.takeLast()]=cur;
133 | cur=pre;
134 | }
135 | config=cur;
136 | }
137 |
138 | static Config *instance();
139 |
140 | private:
141 | static Config *ins;
142 | static QJsonObject config;
143 |
144 | public slots:
145 | static void exec(QWidget *parent=0,int index=0);
146 | static void load();
147 | static void save();
148 | static void setManager(QNetworkAccessManager *manager);
149 | void setVariant(QString key,QVariant val);
150 | QVariant getVariant(QString key,QVariant val=QVariant());
151 | };
152 |
153 | #endif // CONFIG_H
154 |
--------------------------------------------------------------------------------
/src/Local.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Local.cpp
6 | * Time: 2013/03/18
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #include "Local.h"
28 | #include "APlayer.h"
29 | #include "Config.h"
30 | #include "Danmaku.h"
31 | #include "Interface.h"
32 | #include "List.h"
33 | #include "Load.h"
34 | #include "Plugin.h"
35 | #include "Render.h"
36 | #include "Shield.h"
37 | #include "Utils.h"
38 |
39 | QHash Local::objects;
40 |
41 | Local::Local(int &argc,char **argv):
42 | QApplication(argc,argv)
43 | {
44 | QDir::setCurrent(applicationDirPath());
45 | setPalette(setStyle("Fusion")->standardPalette());
46 | setAttribute(Qt::AA_UseOpenGLES);
47 | thread()->setPriority(QThread::TimeCriticalPriority);
48 | Config::load();
49 | Shield::load();
50 | qsrand(QTime::currentTime().msec());
51 | }
52 |
53 | void Local::exit(int code)
54 | {
55 | delete List::instance();
56 | delete Load::instance();
57 | Shield::save();
58 | Config::save();
59 | delete APlayer::instance();
60 | delete Danmaku::instance();
61 | QApplication::exit(code);
62 | }
63 |
64 | QString Local::suggestion(int code)
65 | {
66 | switch (code){
67 | case 3:
68 | case 4:
69 | return tr("check your network connection");
70 | case 203:
71 | case 403:
72 | case -8:
73 | return tr("access denied, try login");
74 | default:
75 | return QString();
76 | }
77 | }
78 |
79 | namespace
80 | {
81 | void setDefaultFont()
82 | {
83 | QString def=Utils::defaultFont();
84 | QFontInfo i(qApp->font());
85 | if(!QFontDatabase().families().contains(def)){
86 | def=i.family();
87 | }
88 | double p=i.pointSizeF();
89 | QFont f;
90 | f.setFamily(Config::getValue("/Interface/Font/Family",def));
91 | f.setPointSizeF(Config::getValue("/Interface/Font/Size",p));
92 | qApp->setFont(f);
93 | }
94 |
95 | void loadTranslator()
96 | {
97 | QString locale=Config::getValue("/Interface/Locale",QLocale::system().name());
98 | QFileInfoList list;
99 | list+=QDir("./locale/"+locale).entryInfoList();
100 | list+=QFileInfo("./locale/"+locale+".qm");
101 | locale.resize(2);
102 | list+=QDir("./locale/"+locale).entryInfoList();
103 | list+=QFileInfo("./locale/"+locale+".qm");
104 | for(QFileInfo info:list){
105 | if(!info.isFile()){
106 | continue;
107 | }
108 | QTranslator *trans=new QTranslator(qApp);
109 | if(trans->load(info.absoluteFilePath())){
110 | qApp->installTranslator(trans);
111 | }
112 | else{
113 | delete trans;
114 | }
115 | }
116 | }
117 |
118 | void setToolTipBase()
119 | {
120 | QPalette tip=qApp->palette();
121 | tip.setColor(QPalette::Inactive,QPalette::ToolTipBase,Qt::white);
122 | qApp->setPalette(tip);
123 | QToolTip::setPalette(tip);
124 | }
125 | }
126 |
127 | int main(int argc,char *argv[])
128 | {
129 | Local a(argc,argv);
130 | int single;
131 | if((single=Config::getValue("/Interface/Single",1))){
132 | QLocalSocket socket;
133 | socket.connectToServer("BiliLocalInstance");
134 | if (socket.waitForConnected()){
135 | QDataStream s(&socket);
136 | s<listen("BiliLocalInstance");
154 | QObject::connect(server,&QLocalServer::newConnection,[&](){
155 | QLocalSocket *r=server->nextPendingConnection();
156 | r->waitForReadyRead();
157 | QDataStream s(r);
158 | QStringList args;
159 | s>>args;
160 | delete r;
161 | w.tryLocal(args);
162 | });
163 | }
164 | int r;
165 | if((r=a.exec())==12450){
166 | if(server){
167 | delete server;
168 | }
169 | QProcess::startDetached(a.applicationFilePath(),QStringList());
170 | return 0;
171 | }
172 | else{
173 | return r;
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/src/Post.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Post.cpp
6 | * Time: 2013/05/23
7 | * Author: zhengdanwei
8 | * Contributor: Lysine
9 | *
10 | * Lysine is a student majoring in Software Engineering
11 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
12 | *
13 | * This program is free software: you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation, either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * This program is distributed in the hope that it will be useful,
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | * GNU General Public License for more details.
22 |
23 | * You should have received a copy of the GNU General Public License
24 | * along with this program. If not, see .
25 | *
26 | =========================================================================*/
27 |
28 | #include "Post.h"
29 | #include "APlayer.h"
30 | #include "Config.h"
31 | #include "Danmaku.h"
32 | #include "Graphic.h"
33 | #include "Local.h"
34 |
35 | Post::Post(QWidget *parent):
36 | QWidget(parent)
37 | {
38 | setFixedSize(parent->minimumWidth(),25);
39 | setObjectName("Post");
40 | manager=new QNetworkAccessManager(this);
41 | Config::setManager(manager);
42 | auto layout=new QHBoxLayout(this);
43 | layout->setMargin(0);
44 | layout->setSpacing(0);
45 | commentM=new QComboBox(this);
46 | commentM->addItems({tr("Top"),tr("Slide"),tr("Bottom")});
47 | commentM->setCurrentIndex(1);
48 | commentM->setFixedWidth(commentM->sizeHint().width());
49 | layout->addWidget(commentM);
50 | commentC=new QPushButton(this);
51 | commentC->setFixedWidth(25);
52 | setColor(Qt::white);
53 | connect(commentC,&QPushButton::clicked,[this](){
54 | QColor color=QColorDialog::getColor(getColor(),lApp->mainWidget());
55 | if(color.isValid()){
56 | setColor(color);
57 | }
58 | });
59 | layout->addWidget(commentC);
60 | commentL=new QLineEdit(this);
61 | commentL->setFocus();
62 | layout->addWidget(commentL);
63 | commentS=new QComboBox(this);
64 | layout->addWidget(commentS);
65 | commentB=new QPushButton(tr("Post"),this);
66 | commentB->setDefault(true);
67 | commentB->setFixedWidth(55);
68 | commentB->setToolTip(tr("DA☆ZE!"));
69 | layout->addWidget(commentB);
70 | commentA=new QAction(this);
71 | commentA->setShortcut(QKeySequence("Ctrl+Enter"));
72 | connect(commentB,&QPushButton::clicked,commentA,&QAction::trigger);
73 | connect(commentL,&QLineEdit::returnPressed,commentA,&QAction::trigger);
74 | connect(commentA,&QAction::triggered,[this](){
75 | if(!commentL->text().isEmpty()){
76 | postComment();
77 | commentL->clear();
78 | hide();
79 | }
80 | });
81 | connect(Danmaku::instance(),&Danmaku::modelReset,[this](){
82 | commentS->clear();
83 | int w=0;
84 | for(const Record *r:getRecords()){
85 | commentS->addItem(r->string,(quintptr)r);
86 | w=qMax(w,commentS->fontMetrics().width(r->string));
87 | }
88 | commentS->setVisible(commentS->count()>=2);
89 | commentS->setFixedWidth(w+30);
90 | });
91 | hide();
92 | }
93 |
94 | static int mode(int i)
95 | {
96 | switch(i){
97 | case 0:
98 | return 5;
99 | case 1:
100 | return 1;
101 | case 2:
102 | return 4;
103 | default:
104 | return 0;
105 | }
106 | }
107 |
108 | Comment Post::getComment()
109 | {
110 | Comment c;
111 | c.mode=mode(commentM->currentIndex());
112 | c.font=25;
113 | c.time=qMax(0,APlayer::instance()->getTime());
114 | c.color=getColor().rgb()&0xFFFFFF;
115 | c.string=commentL->text();
116 | return c;
117 | }
118 |
119 | QList Post::getRecords()
120 | {
121 | QList list;
122 | for(const Record &r:Danmaku::instance()->getPool()){
123 | int s=Utils::parseSite(r.source);
124 | if(s==Utils::Bilibili||s==Utils::AcPlay){
125 | list.append(&r);
126 | }
127 | }
128 | return list;
129 | }
130 |
131 | QColor Post::getColor()
132 | {
133 | QString sheet=commentC->styleSheet();
134 | return QColor(sheet.mid(sheet.indexOf('#')));
135 | }
136 |
137 | void Post::setColor(QColor color)
138 | {
139 | commentC->setStyleSheet(QString("background-color:%1").arg(color.name()));
140 | }
141 |
142 | void Post::postComment()
143 | {
144 | const Record *r=(const Record *)commentS->currentData().value();
145 | QNetworkRequest request;
146 | QByteArray data;
147 | const Comment &c=getComment();
148 | switch(Utils::parseSite(r->source)){
149 | case Utils::Bilibili:
150 | {
151 | QString api("http://interface.%1/dmpost");
152 | api=api.arg(Utils::customUrl(Utils::Bilibili));
153 | request.setUrl(api);
154 | request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");
155 | QUrlQuery params;
156 | params.addQueryItem("cid",QFileInfo(r->source).baseName());
157 | params.addQueryItem("date",QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"));
158 | params.addQueryItem("pool","0");
159 | params.addQueryItem("playTime",QString::number((c.time-r->delay)/1000.0,'f',4));
160 | params.addQueryItem("color",QString::number(c.color));
161 | params.addQueryItem("fontsize",QString::number(c.font));
162 | params.addQueryItem("message",c.string);
163 | params.addQueryItem("rnd",QString::number(qrand()));
164 | params.addQueryItem("mode",QString::number(c.mode));
165 | data=QUrl::toPercentEncoding(params.query(QUrl::FullyEncoded),"%=&","-.~_");
166 | break;
167 | }
168 | case Utils::AcPlay:
169 | {
170 | QString api("http://api.%1/api/v1/comment/%2");
171 | api=api.arg(Utils::customUrl(Utils::AcPlay));
172 | api=api.arg(QFileInfo(r->source).baseName());
173 | request.setUrl(api);
174 | request.setHeader(QNetworkRequest::ContentTypeHeader,"application/json");
175 | QJsonObject params;
176 | params["Token"]=0;
177 | params["Time"]=(c.time-r->delay)/1000.0;
178 | params["Mode"]=c.mode;
179 | params["Color"]=c.color;
180 | params["TimeStamp"]=QDateTime::currentMSecsSinceEpoch();
181 | params["Pool"]=0;
182 | params["UId"]=0;
183 | params["CId"]=0;
184 | params["Message"]=c.string;
185 | data=QJsonDocument(params).toJson();
186 | break;
187 | }
188 | default:
189 | break;
190 | }
191 | Danmaku::instance()->appendToPool(r->source,&c);
192 | QNetworkReply *reply=manager->post(request,data);
193 | connect(reply,&QNetworkReply::finished,[=](){
194 | int error=reply->error();
195 | if (error==QNetworkReply::NoError){
196 | switch(Utils::parseSite(reply->url().url()))
197 | {
198 | case Utils::Bilibili:
199 | {
200 | error=qMin(QString(reply->readAll()).toInt(),QNetworkReply::NoError);
201 | break;
202 | }
203 | case Utils::AcPlay:
204 | {
205 | QJsonObject o=QJsonDocument::fromJson(reply->readAll()).object();
206 | error=o["Success"].toBool()?QNetworkReply::NoError:QNetworkReply::UnknownNetworkError;
207 | break;
208 | }
209 | default:
210 | break;
211 | }
212 | }
213 | if(error!=QNetworkReply::NoError){
214 | QString info=tr("Network error occurred, error code: %1").arg(error);
215 | QString sugg=Local::instance()->suggestion(error);
216 | QMessageBox::warning(lApp->mainWidget(),tr("Network Error"),sugg.isEmpty()?info:(info+'\n'+sugg));
217 | }
218 | else{
219 | emit posted(&c);
220 | }
221 | reply->deleteLater();
222 | });
223 | }
224 |
225 | bool Post::isValid()
226 | {
227 | return !getRecords().isEmpty();
228 | }
229 |
230 | void Post::setVisible(bool visible)
231 | {
232 | QWidget::setVisible(visible);
233 | QWidget *fw=visible?commentL:lApp->mainWidget();
234 | fw->setFocus();
235 | }
--------------------------------------------------------------------------------
/src/Utils.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Utils.cpp
6 | * Time: 2013/05/10
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #include "Utils.h"
28 | #include "Config.h"
29 | #include
30 |
31 | Utils::Site Utils::parseSite(QString url)
32 | {
33 | url=url.toLower();
34 | if(-1!=url.indexOf("letv")){
35 | return Letv;
36 | }
37 | if(-1!=url.indexOf("tudou")){
38 | return Tudou;
39 | }
40 | if(-1!=url.indexOf("bilibili")){
41 | return Bilibili;
42 | }
43 | if(-1!=url.indexOf("acfun")){
44 | return AcFun;
45 | }
46 | if(-1!=url.indexOf("acplay")){
47 | return AcPlay;
48 | }
49 | if(-1!=url.indexOf("tucao")){
50 | return TuCao;
51 | }
52 | return Unknown;
53 | }
54 |
55 | void Utils::setCenter(QWidget *widget)
56 | {
57 | QRect rect=widget->geometry();
58 | QWidget *parent=widget->parentWidget();
59 | if(parent==NULL){
60 | rect.moveCenter(QApplication::desktop()->screenGeometry(widget).center());
61 | }
62 | else{
63 | if(widget->isWindow()){
64 | QPoint center=parent->geometry().center();
65 | if((parent->windowFlags()&Qt::CustomizeWindowHint)){
66 | center.ry()+=widget->style()->pixelMetric(QStyle::PM_TitleBarHeight)/2;
67 | }
68 | rect.moveCenter(center);
69 | }
70 | else{
71 | rect.moveCenter(parent->rect().center());
72 | }
73 | }
74 | widget->setGeometry(rect);
75 | }
76 |
77 | void Utils::setGround(QWidget *widget,QColor color)
78 | {
79 | widget->setAutoFillBackground(true);
80 | QPalette palette=widget->palette();
81 | palette.setColor(QPalette::Window,color);
82 | widget->setPalette(palette);
83 | }
84 |
85 | namespace{
86 | template
87 | class SStack
88 | {
89 | public:
90 | inline T &top()
91 | {
92 | if(isEmpty()){
93 | throw("token mismatch");
94 | }
95 | return stk.top();
96 | }
97 |
98 | inline T pop()
99 | {
100 | if(isEmpty()){
101 | throw("token mismatch");
102 | }
103 | return stk.pop();
104 | }
105 |
106 | inline void push(const T &i)
107 | {
108 | stk.push(i);
109 | }
110 |
111 | inline bool isEmpty()
112 | {
113 | return stk.isEmpty();
114 | }
115 |
116 | private:
117 | QStack stk;
118 | };
119 | }
120 |
121 | double Utils::evaluate(QString exp)
122 | {
123 | auto priority=[](QChar o){
124 | switch(o.unicode())
125 | {
126 | case '(':
127 | return 1;
128 | case '+':
129 | case '-':
130 | return 2;
131 | case '*':
132 | case '/':
133 | return 3;
134 | case '+'+128:
135 | case '-'+128:
136 | return 4;
137 | default:
138 | return 0;
139 | }
140 | };
141 | exp=exp.trimmed();
142 | try{
143 | QString pst;
144 | SStack opt;
145 | int i=0;
146 | opt.push('#');
147 | while(i num;
187 | i=0;
188 | while(pst[i]!='#'){
189 | if(pst[i].isDigit()||pst[i]=='.'){
190 | double n=0;
191 | while(pst[i].isDigit()){
192 | n=n*10+pst[i++].toLatin1()-'0';
193 | }
194 | if(pst[i]=='.'){
195 | ++i;
196 | double d=1;
197 | while(pst[i].isDigit()){
198 | n+=(d/=10)*(pst[i++].toLatin1()-'0');
199 | }
200 | }
201 | num.push(n);
202 | }
203 | else{
204 | switch(pst[i].unicode()){
205 | case '+'+128:
206 | num.push(+num.pop());
207 | break;
208 | case '-'+128:
209 | num.push(-num.pop());
210 | break;
211 | case '+':
212 | {
213 | double r=num.pop(),l=num.pop();
214 | num.push(l+r);
215 | break;
216 | }
217 | case '-':
218 | {
219 | double r=num.pop(),l=num.pop();
220 | num.push(l-r);
221 | break;
222 | }
223 | case '*':
224 | {
225 | double r=num.pop(),l=num.pop();
226 | num.push(l*r);
227 | break;
228 | }
229 | case '/':
230 | {
231 | double r=num.pop(),l=num.pop();
232 | num.push(l/r);
233 | break;
234 | }
235 | }
236 | i++;
237 | }
238 | }
239 | return num.top();
240 | }
241 | catch(...){
242 | return 0;
243 | }
244 | }
245 |
246 | QString Utils::defaultFont(bool monospace)
247 | {
248 | if(monospace){
249 | #ifdef Q_OS_LINUX
250 | return QStringLiteral("文泉驿等宽正黑");
251 | #endif
252 | #ifdef Q_OS_WIN32
253 | return QStringLiteral("黑体");
254 | #endif
255 | #ifdef Q_OS_MAC
256 | return QStringLiteral("华文黑体");
257 | #endif
258 | }
259 | else{
260 | #ifdef Q_OS_LINUX
261 | return QStringLiteral("文泉驿正黑");
262 | #endif
263 | #ifdef Q_OS_WIN32
264 | return QStringLiteral("微软雅黑");
265 | #endif
266 | #ifdef Q_OS_MAC
267 | return QStringLiteral("华文黑体");
268 | #endif
269 | }
270 | }
271 |
272 | QString Utils::customUrl(Site site)
273 | {
274 | QString name;
275 | switch (site){
276 | case AcFun:
277 | name="acfun";
278 | break;
279 | case Bilibili:
280 | name="bili";
281 | break;
282 | case AcPlay:
283 | name="acplay";
284 | break;
285 | case Tudou:
286 | name="tudou";
287 | break;
288 | case Niconico:
289 | name="nico";
290 | break;
291 | case TuCao:
292 | name="tucao";
293 | break;
294 | default:
295 | return QString();
296 | }
297 | QStringList urls,defs;
298 | defs<<"acfun.tv"<<"bilibili.com"<<"acplay.net"<<"tucao.tv";
299 | urls=Config::getValue("/Network/Url",defs.join(';')).split(';',QString::SkipEmptyParts);
300 | for (QString iter:urls+defs){
301 | if (iter.toLower().indexOf(name)!=-1){
302 | return iter;
303 | }
304 | }
305 | return QString();
306 | }
307 |
308 | QString Utils::decodeXml(QString string,bool fast)
309 | {
310 | if(!fast){
311 | QTextDocument text;
312 | text.setHtml(string);
313 | return text.toPlainText();
314 | }
315 | QString fixed;
316 | fixed.reserve(string.length());
317 | int i=0,l=string.length();
318 | for(i=0;i=' '||c=='\n'){
321 | bool f=true;
322 | switch(c.unicode()){
323 | case '&':
324 | if(l-i>=4){
325 | switch(string[i+1].unicode()){
326 | case 'l':
327 | if(string[i+2]=='t'&&string[i+3]==';'){
328 | fixed+='<';
329 | f=false;
330 | i+=3;
331 | }
332 | break;
333 | case 'g':
334 | if(string[i+2]=='t'&&string[i+3]==';'){
335 | fixed+='>';
336 | f=false;
337 | i+=3;
338 | }
339 | break;
340 | case 'a':
341 | if(l-i>=5&&string[i+2]=='m'&&string[i+3]=='p'&&string[i+4]==';'){
342 | fixed+='&';
343 | f=false;
344 | i+=4;
345 | }
346 | break;
347 | case 'q':
348 | if(l-i>=6&&string[i+2]=='u'&&string[i+3]=='o'&&string[i+4]=='t'&&string[i+5]==';'){
349 | fixed+='\"';
350 | f=false;
351 | i+=5;
352 | }
353 | break;
354 | }
355 | }
356 | break;
357 | case '/' :
358 | case '\\':
359 | if(l-i>=2){
360 | switch(string[i+1].unicode()){
361 | case 'n':
362 | fixed+='\n';
363 | f=false;
364 | i+=1;
365 | break;
366 | case 't':
367 | fixed+='\t';
368 | f=false;
369 | i+=1;
370 | break;
371 | case '\"':
372 | fixed+='\"';
373 | f=false;
374 | i+=1;
375 | break;
376 | }
377 | }
378 | break;
379 | }
380 | if(f){
381 | fixed+=c;
382 | }
383 | }
384 | }
385 | return fixed;
386 | }
387 |
388 | QStringList Utils::getRenderModules()
389 | {
390 | QStringList modules;
391 | #ifdef RENDER_OPENGL
392 | modules<<"OpenGL";
393 | #endif
394 | #ifdef RENDER_RASTER
395 | modules<<"Raster";
396 | #endif
397 | #ifdef RENDER_DETACH
398 | modules<<"Detach";
399 | #endif
400 | return modules;
401 | }
402 |
403 | QStringList Utils::getDecodeModules()
404 | {
405 | QStringList modules;
406 | #ifdef BACKEND_VLC
407 | modules<<"VLC";
408 | #endif
409 | #ifdef BACKEND_QMM
410 | modules<<"QMM";
411 | #endif
412 | #ifdef BACKEND_NIL
413 | modules<<"NIL";
414 | #endif
415 | return modules;
416 | }
417 |
418 | QStringList Utils::getSuffix(int type,QString format)
419 | {
420 | QStringList set;
421 | if(type&Video){
422 | set<<"3g2"<<"3gp"<<"3gp2"<<"3gpp"<<"amv"<<"asf"<<"avi"<<"divx"<<"drc"<<"dv"<<
423 | "f4v"<<"flv"<<"gvi"<<"gxf"<<"hlv"<<"iso"<<"letv"<<
424 | "m1v"<<"m2t"<<"m2ts"<<"m2v"<<"m4v"<<"mkv"<<"mov"<<
425 | "mp2"<<"mp2v"<<"mp4"<<"mp4v"<<"mpe"<<"mpeg"<<"mpeg1"<<
426 | "mpeg2"<<"mpeg4"<<"mpg"<<"mpv2"<<"mts"<<"mtv"<<"mxf"<<"mxg"<<"nsv"<<"nuv"<<
427 | "ogg"<<"ogm"<<"ogv"<<"ogx"<<"ps"<<
428 | "rec"<<"rm"<<"rmvb"<<"tod"<<"ts"<<"tts"<<"vob"<<"vro"<<
429 | "webm"<<"wm"<<"wmv"<<"wtv"<<"xesc";
430 | }
431 | if(type&Audio){
432 | int size=set.size();
433 | set<<"3ga"<<"669"<<"a52"<<"aac"<<"ac3"<<"adt"<<"adts"<<"aif"<<"aifc"<<"aiff"<<
434 | "amr"<<"aob"<<"ape"<<"awb"<<"caf"<<"dts"<<"flac"<<"it"<<"kar"<<
435 | "m4a"<<"m4p"<<"m5p"<<"mka"<<"mlp"<<"mod"<<"mp1"<<"mp2"<<"mp3"<<"mpa"<<"mpc"<<"mpga"<<
436 | "oga"<<"ogg"<<"oma"<<"opus"<<"qcp"<<"ra"<<"rmi"<<"s3m"<<"spx"<<"thd"<<"tta"<<
437 | "voc"<<"vqf"<<"w64"<<"wav"<<"wma"<<"wv"<<"xa"<<"xm";
438 | std::inplace_merge(set.begin(),set.begin()+size,set.end());
439 | }
440 | if(type&Subtitle){
441 | int size=set.size();
442 | set<<"aqt"<<"ass"<<"cdg"<<"dks"<<"idx"<<"jss"<<"mks"<<"mpl2"<<"pjs"<<"psb"<<"rt"<<
443 | "smi"<<"smil"<<"srt"<<"ssa"<<"stl"<<"sub"<<"txt"<<"usf"<<"utf";
444 | std::inplace_merge(set.begin(),set.begin()+size,set.end());
445 | }
446 | if(type&Danmaku){
447 | int size=set.size();
448 | set<<"json"<<"xml";
449 | std::inplace_merge(set.begin(),set.begin()+size,set.end());
450 | }
451 | if(!format.isEmpty()){
452 | for(QString &iter:set){
453 | iter=format.arg(iter);
454 | }
455 | }
456 | return set;
457 | }
458 |
--------------------------------------------------------------------------------
/src/Info.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Info.cpp
6 | * Time: 2013/04/05
7 | * Author: Lysine
8 | * Contributor: Chaserhkj
9 | *
10 | * Lysine is a student majoring in Software Engineering
11 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
12 | *
13 | * This program is free software: you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation, either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * This program is distributed in the hope that it will be useful,
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | * GNU General Public License for more details.
22 |
23 | * You should have received a copy of the GNU General Public License
24 | * along with this program. If not, see .
25 | *
26 | =========================================================================*/
27 |
28 | #include "Info.h"
29 | #include "APlayer.h"
30 | #include "Config.h"
31 | #include "Danmaku.h"
32 | #include "Editor.h"
33 | #include "List.h"
34 | #include "Load.h"
35 | #include "Local.h"
36 | #include "Shield.h"
37 | #include "Utils.h"
38 |
39 | namespace
40 | {
41 | class MTableView:public QTableView
42 | {
43 | public:
44 | MTableView(QWidget *parent=0):
45 | QTableView(parent)
46 | {
47 | }
48 |
49 | void currentChanged(const QModelIndex &c,
50 | const QModelIndex &p)
51 | {
52 | QTableView::currentChanged(c,p);
53 | selectionModel()->setCurrentIndex(QModelIndex(),QItemSelectionModel::NoUpdate);
54 | }
55 | };
56 |
57 | }
58 |
59 | Info::Info(QWidget *parent):
60 | QWidget(parent)
61 | {
62 | setObjectName("Info");
63 | isStay=isPoped=updating=false;
64 | Utils::setGround(this,Qt::white);
65 | duration=-1;
66 | animation=new QPropertyAnimation(this,"pos",this);
67 | animation->setDuration(200);
68 | animation->setEasingCurve(QEasingCurve::OutCubic);
69 | timeT=new QLabel(tr("Time"),this);
70 | volmT=new QLabel(tr("Volume"),this);
71 | timeS=new QSlider(this);
72 | volmS=new QSlider(this);
73 | timeS->setOrientation(Qt::Horizontal);
74 | volmS->setOrientation(Qt::Horizontal);
75 | timeS->setRange(0,0);
76 | volmS->setRange(0,100);
77 | timeS->setValue(0);
78 | volmS->setValue(Config::getValue("/Playing/Volume",50));
79 | timeS->setTracking(false);
80 | connect(timeS,&QSlider::valueChanged,[this](int _time){
81 | if(duration!=-1&&!updating){
82 | APlayer::instance()->setTime(duration*_time/400);
83 | }
84 | });
85 | connect(volmS,&QSlider::sliderMoved,[this](int _volm){
86 | QPoint p;
87 | p.setX(QCursor::pos().x());
88 | p.setY(volmS->mapToGlobal(volmS->rect().center()).y());
89 | QToolTip::showText(p,QString::number(_volm));
90 | });
91 | connect(volmS,&QSlider::valueChanged,[this](int _volm){
92 | if(!updating){
93 | APlayer::instance()->setVolume(_volm);
94 | }
95 | });
96 | playB=new QPushButton(this);
97 | stopB=new QPushButton(this);
98 | playI=QIcon::fromTheme("media-playback-start",QIcon(":/Picture/play.png"));
99 | stopI=QIcon::fromTheme("media-playback-stop",QIcon(":/Picture/stop.png"));
100 | pausI=QIcon::fromTheme("media-playback-pause",QIcon(":/Picture/pause.png"));
101 | playB->setIcon(playI);
102 | stopB->setIcon(stopI);
103 | playA=new QAction(playI,tr("Play"),this);
104 | stopA=new QAction(stopI,tr("Stop"),this);
105 | playA->setObjectName("Play");
106 | stopA->setObjectName("Stop");
107 | QList playS;
108 | playS<setShortcuts(playS);
113 | stopA->setShortcut(Config::getValue("/Shortcut/Stop",QString()));
114 | addAction(playA);
115 | addAction(stopA);
116 | connect(playA,SIGNAL(triggered()),APlayer::instance(),SLOT(play()));
117 | connect(stopA,SIGNAL(triggered()),APlayer::instance(),SLOT(stop()));
118 | connect(playB,&QPushButton::clicked,playA,&QAction::trigger);
119 | connect(stopB,&QPushButton::clicked,stopA,&QAction::trigger);
120 | duraT=new QLabel(this);
121 | duraT->setAlignment(Qt::AlignRight|Qt::AlignBottom);
122 | duraT->setText("00:00/00:00");
123 | danmV=new MTableView(this);
124 | danmV->setWordWrap(false);
125 | danmV->setSelectionBehavior(QAbstractItemView::SelectRows);
126 | danmV->setSelectionMode(QAbstractItemView::ExtendedSelection);
127 | danmV->verticalHeader()->hide();
128 | danmV->setAlternatingRowColors(true);
129 | danmV->setContextMenuPolicy(Qt::CustomContextMenu);
130 | danmV->setModel(Danmaku::instance());
131 | QHeaderView *header;
132 | header=danmV->horizontalHeader();
133 | header->setSectionResizeMode(0,QHeaderView::Fixed);
134 | header->setSectionResizeMode(1,QHeaderView::Stretch);
135 | header->setHighlightSections(false);
136 | resizeHeader();
137 | header=danmV->verticalHeader();
138 | header->setDefaultSectionSize(22.5*logicalDpiY()/72);
139 | connect(Danmaku::instance(),&Danmaku::layoutChanged,this,&Info::resizeHeader);
140 | connect(danmV,&QTableView::doubleClicked,[this](QModelIndex index){
141 | APlayer::instance()->setTime(((Comment *)(index.data(Qt::UserRole).value()))->time);
142 | });
143 |
144 | QAction *saveA=new QAction(tr("Save Danmaku to File"),this);
145 | saveA->setObjectName("Save");
146 | saveA->setShortcut(Config::getValue("/Shortcut/Save",QString()));
147 | saveA->setEnabled(false);
148 | connect(saveA,&QAction::triggered,[](){
149 | QFileDialog save(lApp->mainWidget(),tr("Save File"));
150 | save.setAcceptMode(QFileDialog::AcceptSave);
151 | QFileInfo info(APlayer::instance()->getMedia());
152 | if(info.isFile()){
153 | save.setDirectory(info.absolutePath());
154 | save.selectFile(info.completeBaseName());
155 | }
156 | else{
157 | save.setDirectory(List::instance()->defaultPath(Utils::Danmaku));
158 | }
159 | save.setDefaultSuffix("json");
160 | QStringList type;
161 | type<saveToFile(file.first());
170 | }
171 | }
172 | });
173 | danmV->addAction(saveA);
174 |
175 | QAction *fullA=new QAction(tr("Full Danmaku"),this);
176 | fullA->setObjectName("Char");
177 | fullA->setShortcut(Config::getValue("/Shortcut/Char",QString()));
178 | fullA->setEnabled(false);
179 | connect(fullA,&QAction::triggered,[](){
180 | Load *load=Load::instance();
181 | for(const Record &r:Danmaku::instance()->getPool()){
182 | if (load->canFull(&r)){
183 | load->fullDanmaku(&r);
184 | }
185 | }
186 | });
187 | danmV->addAction(fullA);
188 |
189 | connect(Danmaku::instance(),&Danmaku::modelReset,[=](){
190 | const QList &pool=Danmaku::instance()->getPool();
191 | fullA->setEnabled(false);
192 | for(const Record &r:pool){
193 | if (Load::instance()->canFull(&r)){
194 | fullA->setEnabled(true);
195 | break;
196 | }
197 | }
198 | saveA->setEnabled(!pool.isEmpty());
199 | });
200 |
201 | connect(danmV,&QTableView::customContextMenuRequested,[=](QPoint p){
202 | QMenu menu(this);
203 | QListselected;
204 | for(const QModelIndex &index:danmV->selectionModel()->selectedRows()){
205 | selected.append((Comment *)index.data(Qt::UserRole).value());
206 | }
207 | if(!selected.isEmpty()){
208 | connect(menu.addAction(tr("Copy Danmaku")),&QAction::triggered,[&](){
209 | QStringList list;
210 | for(const Comment *c:selected){
211 | list.append(c->string);
212 | }
213 | qApp->clipboard()->setText(list.join('\n'));
214 | });
215 | connect(menu.addAction(tr("Eliminate The Sender")),&QAction::triggered,[&](){
216 | for(const Comment *c:selected){
217 | QString sender=c->sender;
218 | if(!sender.isEmpty()){
219 | Shield::shieldS.insert(sender);
220 | }
221 | }
222 | Danmaku::instance()->parse(0x2);
223 | });
224 | bool flag=false;
225 | for(const Comment *c:selected){
226 | if(Shield::shieldS.contains(c->sender)){
227 | flag=true;
228 | break;
229 | }
230 | }
231 | if(flag){
232 | connect(menu.addAction(tr("Recover The Sender")),&QAction::triggered,[&](){
233 | for(const Comment *c:selected){
234 | Shield::shieldS.remove(c->sender);
235 | }
236 | Danmaku::instance()->parse(0x2);
237 | });
238 | }
239 | menu.addSeparator();
240 | }
241 | menu.addAction(fullA);
242 | connect(menu.addAction(tr("Edit Blocking List")),&QAction::triggered,[this](){
243 | Config::exec(lApp->mainWidget(),3);
244 | });
245 | connect(menu.addAction(tr("Edit Danmaku Pool" )),&QAction::triggered,[this](){
246 | Editor::exec(lApp->mainWidget());
247 | });
248 | connect(menu.addAction(tr("Clear Danmaku Pool")),&QAction::triggered,Danmaku::instance(),&Danmaku::clearPool);
249 | menu.addAction(saveA);
250 | isStay=1;
251 | menu.exec(danmV->viewport()->mapToGlobal(p));
252 | isStay=0;
253 | });
254 |
255 | animation=new QPropertyAnimation(this,"pos",this);
256 | animation->setDuration(200);
257 | animation->setEasingCurve(QEasingCurve::OutCubic);
258 | connect(animation,&QPropertyAnimation::finished,[this](){
259 | if(!isPoped){
260 | hide();
261 | lApp->mainWidget()->setFocus();
262 | }
263 | });
264 |
265 | connect(APlayer::instance(),&APlayer::timeChanged,this,&Info::setTime);
266 | connect(APlayer::instance(),&APlayer::volumeChanged,[this](int volume){
267 | updating=1;
268 | volmS->setValue(volume);
269 | updating=0;
270 | });
271 | connect(APlayer::instance(),&APlayer::begin,[this](){
272 | setDuration(APlayer::instance()->getDuration());
273 | });
274 | connect(APlayer::instance(),&APlayer::reach,[this](){
275 | setDuration(-1);
276 | });
277 | connect(APlayer::instance(),&APlayer::stateChanged,[this](int state){
278 | bool playing=state==APlayer::Play;
279 | playB->setIcon(playing?pausI:playI);
280 | playA->setIcon(playing?pausI:playI);
281 | playA->setText(playing?tr("Pause"):tr("Play"));
282 | });
283 | hide();
284 | }
285 |
286 | void Info::pop()
287 | {
288 | if(!isPoped&&animation->state()==QAbstractAnimation::Stopped){
289 | show();
290 | animation->setStartValue(pos());
291 | animation->setEndValue(pos()-QPoint(width(),0));
292 | animation->start();
293 | isPoped=true;
294 | }
295 | }
296 |
297 | void Info::push(bool force)
298 | {
299 | if(isPoped&&animation->state()==QAbstractAnimation::Stopped&&(!preferStay()||force)){
300 | if(force){
301 | isStay=false;
302 | }
303 | animation->setStartValue(pos());
304 | animation->setEndValue(pos()+QPoint(width(),0));
305 | animation->start();
306 | isPoped=false;
307 | }
308 | }
309 |
310 | void Info::terminate()
311 | {
312 | if(animation->state()!=QAbstractAnimation::Stopped){
313 | animation->setCurrentTime(animation->totalDuration());
314 | }
315 | }
316 |
317 | void Info::resizeEvent(QResizeEvent *e)
318 | {
319 | int w=e->size().width(),h=e->size().height();
320 | double f=font().pointSizeF();
321 | int x=logicalDpiX()*f/72,y=logicalDpiY()*f/72;
322 | playB->setGeometry(QRect(0.83*x,1.25*y, 2.08*x, 2.08*y));
323 | stopB->setGeometry(QRect(3.33*x,1.25*y, 2.08*x, 2.08*y));
324 | duraT->setGeometry(QRect(5.83*x,1.25*y, w-6.67*x,2.08*y));
325 | timeT->setGeometry(QRect(0.83*x,4.17*y, w-1.67*x,2.08*y));
326 | timeS->setGeometry(QRect(0.83*x,6.25*y, w-1.67*x,1.25*y));
327 | volmT->setGeometry(QRect(0.83*x,8.33*y, w-1.67*x,2.08*y));
328 | volmS->setGeometry(QRect(0.83*x,10.42*y,w-1.67*x,1.25*y));
329 | danmV->setGeometry(QRect(0.83*x,14.17*y,w-1.67*x,h-15.00*y));
330 | QWidget::resizeEvent(e);
331 | }
332 |
333 | void Info::resizeHeader()
334 | {
335 | Danmaku *d=Danmaku::instance();
336 | QStringList list;
337 | list.append(d->headerData(0,Qt::Horizontal,Qt::DisplayRole).toString());
338 | int c=d->rowCount()-1,i;
339 | for(i=0;i<=c;++i){
340 | if(d->data(d->index(i,0),Qt::ForegroundRole).value()!=Qt::red){
341 | list.append(d->data(d->index(i,0),Qt::DisplayRole).toString());
342 | break;
343 | }
344 | }
345 | for(i=c;i>=0;--i){
346 | if(d->data(d->index(i,0),Qt::ForegroundRole).value()!=Qt::red){
347 | list.append(d->data(d->index(i,0),Qt::DisplayRole).toString());
348 | break;
349 | }
350 | }
351 | int m=0;
352 | for(QString item:list){
353 | m=qMax(m,danmV->fontMetrics().width(item)+8);
354 | }
355 | danmV->horizontalHeader()->resizeSection(0,m);
356 | }
357 |
358 | void Info::setTime(qint64 _time)
359 | {
360 | if(!timeS->isSliderDown()){
361 | updating=1;
362 | timeS->setValue(_time*400/duration);
363 | updating=0;
364 | }
365 | int c=_time/1000;
366 | int s=duration/1000;
367 | auto to=[](int num){
368 | QString res=QString::number(num);
369 | res.prepend(QString(2-res.length(),'0'));
370 | return res;
371 | };
372 | QString t;
373 | t+=to(c/60)+':'+to(c%60);
374 | t+='/';
375 | t+=to(s/60)+':'+to(s%60);
376 | duraT->setText(t);
377 | }
378 |
379 | void Info::setDuration(qint64 _duration)
380 | {
381 | if(_duration>0){
382 | duration=_duration;
383 | timeS->setRange(0,400);
384 | }
385 | else{
386 | duration=-1;
387 | timeS->setValue(0);
388 | timeS->setRange(0,0);
389 | duraT->setText("00:00/00:00");
390 | }
391 | }
392 |
--------------------------------------------------------------------------------
/src/Graphic.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Graphic.cpp
6 | * Time: 2013/10/19
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #include "Graphic.h"
28 | #include "Config.h"
29 | #include "Render.h"
30 |
31 | class Plain:public Graphic
32 | {
33 | public:
34 | virtual void draw(QPainter *painter);
35 |
36 | protected:
37 | explicit Plain(const Comment &comment);
38 | ~Plain(){delete cache;}
39 | Render::ICache *cache;
40 | };
41 |
42 | class Mode1:public Plain
43 | {
44 | public:
45 | Mode1(const Comment &comment);
46 | bool move(qint64 time);
47 | uint intersects(Graphic *other);
48 |
49 | private:
50 | double speed;
51 | };
52 |
53 | class Mode4:public Plain
54 | {
55 | public:
56 | Mode4(const Comment &comment);
57 | bool move(qint64 time);
58 | uint intersects(Graphic *other);
59 |
60 | private:
61 | double life;
62 | };
63 |
64 | class Mode5:public Plain
65 | {
66 | public:
67 | Mode5(const Comment &comment);
68 | bool move(qint64 time);
69 | uint intersects(Graphic *other);
70 |
71 | private:
72 | double life;
73 | };
74 |
75 | class Mode6:public Plain
76 | {
77 | public:
78 | Mode6(const Comment &comment);
79 | bool move(qint64 time);
80 | uint intersects(Graphic *other);
81 |
82 | private:
83 | double speed;
84 | };
85 |
86 | class Mode7:public Graphic
87 | {
88 | public:
89 | Mode7(const Comment &comment);
90 | bool move(qint64 time);
91 | void draw(QPainter *painter);
92 | uint intersects(Graphic *){return 0;}
93 |
94 | private:
95 | QPointF bPos;
96 | QPointF ePos;
97 | double bAlpha;
98 | double eAlpha;
99 | double zRotate;
100 | double yRotate;
101 | QImage cache;
102 | double wait;
103 | double stay;
104 | double life;
105 | double time;
106 | };
107 |
108 | namespace
109 | {
110 | QFont getFont(int pixelSize,QString family=Config::getValue("/Danmaku/Font",QFont().family()))
111 | {
112 | QFont font;
113 | font.setBold(Config::getValue("/Danmaku/Effect",5)%2);
114 | font.setFamily(family);
115 | font.setPixelSize(pixelSize);
116 | return font;
117 | }
118 |
119 | QSize getSize(QString string,QFont font)
120 | {
121 | QStringList lines=string.split('\n');
122 | for(QString &line:lines){
123 | QChar h=' ',f(0x3000);
124 | int hc=line.count(h),fc=line.count(f);
125 | line.remove(h).prepend(QString(hc,h));
126 | line.remove(f).prepend(QString(fc,f));
127 | }
128 | return QFontMetrics(font).size(0,lines.join('\n'))+QSize(4,4);
129 | }
130 |
131 | QSizeF getPlayer(qint64 date)
132 | {
133 | return date<=1384099200?QSizeF(545,388):QSizeF(862,568);
134 | }
135 |
136 | double getScale(int mode,qint64 date,QSize size)
137 | {
138 | int m=Config::getValue("/Danmaku/Scale/Fitted",0x1);
139 | if(mode==7&&(m&0x1)==0){
140 | return 0;
141 | }
142 | if(mode<=6&&(m&0x2)==0){
143 | return Config::getValue("/Danmaku/Scale/Factor",1.0);
144 | }
145 | QSizeF player=getPlayer(date);
146 | return qMin(size.width()/player.width(),size.height()/player.height());
147 | }
148 | }
149 |
150 | void qt_blurImage(QPainter *p,QImage &blurImage,qreal radius,
151 | bool quality,bool alphaOnly,int transposed);
152 |
153 | namespace
154 | {
155 | QImage getCache(QString string,
156 | int color,
157 | QFont font,
158 | QSize size,
159 | bool frame,
160 | int effect=Config::getValue("/Danmaku/Effect",5)/2,
161 | int opacity=Config::getValue("/Danmaku/Alpha",100))
162 | {
163 | QPainter painter;
164 | QColor base(color),edge=qGray(color)<30?Qt::white:Qt::black;
165 | QImage src(size,QImage::Format_ARGB32_Premultiplied);
166 | src.fill(Qt::transparent);
167 | painter.begin(&src);
168 | painter.setPen(base);
169 | painter.setFont(font);
170 | painter.drawText(src.rect().adjusted(2,2,-2,-2),string);
171 | painter.end();
172 | QImage fst(size,QImage::Format_ARGB32_Premultiplied);
173 | fst.fill(Qt::transparent);
174 | if(effect==2){
175 | QImage blr=src;
176 | painter.begin(&fst);
177 | painter.save();
178 | qt_blurImage(&painter,blr,4,false,true,0);
179 | painter.restore();
180 | painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
181 | painter.fillRect(src.rect(),edge);
182 | painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
183 | painter.drawImage(0,0,src);
184 | painter.end();
185 | QImage sec(size,QImage::Format_ARGB32_Premultiplied);
186 | sec.fill(Qt::transparent);
187 | painter.begin(&sec);
188 | blr=fst;
189 | painter.save();
190 | qt_blurImage(&painter,blr,4,false,true,0);
191 | painter.restore();
192 | painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
193 | painter.fillRect(sec.rect(),edge);
194 | painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
195 | painter.drawImage(0,0,fst);
196 | painter.end();
197 | fst=sec;
198 | }
199 | else{
200 | QImage edg=src;
201 | painter.begin(&edg);
202 | painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
203 | painter.fillRect(edg.rect(),edge);
204 | painter.end();
205 | painter.begin(&fst);
206 | switch(effect){
207 | case 0:
208 | painter.drawImage(+1,0,edg);
209 | painter.drawImage(-1,0,edg);
210 | painter.drawImage(0,+1,edg);
211 | painter.drawImage(0,-1,edg);
212 | break;
213 | case 1:
214 | painter.drawImage(1,1,edg);
215 | break;
216 | }
217 | painter.drawImage(0,0,src);
218 | painter.end();
219 | }
220 | if(frame){
221 | painter.begin(&fst);
222 | painter.setPen(QColor(100,255,255));
223 | painter.setBrush(Qt::NoBrush);
224 | painter.drawRect(fst.rect().adjusted(0,0,-1,-1));
225 | painter.end();
226 | }
227 | if(opacity!=100){
228 | QImage sec(size,QImage::Format_ARGB32_Premultiplied);
229 | sec.fill(Qt::transparent);
230 | painter.begin(&sec);
231 | painter.setOpacity(opacity/100.0);
232 | painter.drawImage(QPoint(0,0),fst);
233 | painter.end();
234 | fst=sec;
235 | }
236 | return fst;
237 | }
238 |
239 | double getOverlap(double ff,double fs,double sf,double ss)
240 | {
241 | if(sf<=ff&&ss>=fs){
242 | return fs-ff;
243 | }
244 | if(sf>=ff&&sf<=fs){
245 | return qMin(fs-sf,ss-sf);
246 | }
247 | if(ss<=fs&&ss>=ff){
248 | return qMin(ss-ff,ss-sf);
249 | }
250 | return 0;
251 | }
252 | }
253 |
254 | Graphic *Graphic::create(const Comment &comment)
255 | {
256 | Graphic *graphic=nullptr;
257 | switch(comment.mode){
258 | case 1:
259 | graphic=new Mode1(comment);
260 | break;
261 | case 4:
262 | graphic=new Mode4(comment);
263 | break;
264 | case 5:
265 | graphic=new Mode5(comment);
266 | break;
267 | case 6:
268 | graphic=new Mode6(comment);
269 | break;
270 | case 7:
271 | graphic=new Mode7(comment);
272 | break;
273 | }
274 | if (graphic&&!graphic->isEnabled()){
275 | delete graphic;
276 | return nullptr;
277 | }
278 | else{
279 | return graphic;
280 | }
281 | }
282 |
283 | void Graphic::setIndex()
284 | {
285 | static quint64 globalIndex;
286 | index=globalIndex++;
287 | }
288 |
289 | Plain::Plain(const Comment &comment)
290 | {
291 | QSize size=Render::instance()->getActualSize();
292 | source=&comment;
293 | QFont font=getFont(comment.font*getScale(comment.mode,comment.date,size));
294 | QSize need=getSize(comment.string,font);
295 | rect.setSize(need);
296 | cache=Render::instance()->getCache(getCache(comment.string,comment.color,font,need,comment.isLocal()));
297 | }
298 |
299 | void Plain::draw(QPainter *painter)
300 | {
301 | if(enabled){
302 | cache->draw(painter,rect);
303 | }
304 | }
305 |
306 | Mode1::Mode1(const Comment &comment):
307 | Plain(comment)
308 | {
309 | if(comment.mode!=1){
310 | return;
311 | }
312 | QSize size=Render::instance()->getActualSize();
313 | QString expression=Config::getValue("/Danmaku/Speed","125+%{width}/5");
314 | expression.replace("%{width}",QString::number(rect.width()),Qt::CaseInsensitive);
315 | if((speed=Utils::evaluate(expression))==0){
316 | return;
317 | }
318 | rect.moveTopLeft(QPointF(size.width(),0));
319 | enabled=true;
320 | }
321 |
322 | bool Mode1::move(qint64 time)
323 | {
324 | if(enabled){
325 | rect.moveLeft(rect.left()-speed*time/1000.0);
326 | }
327 | return rect.right()>=0;
328 | }
329 |
330 | uint Mode1::intersects(Graphic *other)
331 | {
332 | if(other->getMode()!=1){
333 | return 0;
334 | }
335 | const Mode1 &f=*dynamic_cast(other);
336 | const Mode1 &s=*this;
337 | int h;
338 | if((h=getOverlap(f.rect.top(),f.rect.bottom(),s.rect.top(),s.rect.bottom()))==0){
339 | return 0;
340 | }
341 | int w=0;
342 | if(f.rect.intersects(s.rect)){
343 | if(f.speed>s.speed){
344 | w=getOverlap(f.rect.left(),f.rect.right(),s.rect.left(),s.rect.right());
345 | }
346 | else{
347 | w=qMin(f.rect.width(),s.rect.width());
348 | }
349 | }
350 | else{
351 | double o=f.rect.right()-f.speed*s.rect.left()/s.speed;
352 | w=o>0?qMin(qMin(f.rect.width(),s.rect.width()),o):0;
353 | }
354 | return h*w;
355 | }
356 |
357 | Mode4::Mode4(const Comment &comment):
358 | Plain(comment)
359 | {
360 | if(comment.mode!=4){
361 | return;
362 | }
363 | QSize size=Render::instance()->getActualSize();
364 | QString expression=Config::getValue("/Danmaku/Life","5");
365 | expression.replace("%{width}",QString::number(rect.width()),Qt::CaseInsensitive);
366 | if((life=Utils::evaluate(expression))==0){
367 | return;
368 | }
369 | rect.moveCenter(QPointF(size.width()/2.0,0));
370 | rect.moveBottom(size.height()*(Config::getValue("/Danmaku/Protect",false)?0.85:1));
371 | enabled=true;
372 | }
373 |
374 | bool Mode4::move(qint64 time)
375 | {
376 | if(enabled){
377 | life-=time/1000.0;
378 | }
379 | return life>0;
380 | }
381 |
382 | uint Mode4::intersects(Graphic *other)
383 | {
384 | if(other->getMode()!=4){
385 | return 0;
386 | }
387 | const Mode4 &f=*this;
388 | const Mode4 &s=*dynamic_cast(other);
389 | return getOverlap(f.rect.top(),f.rect.bottom(),s.rect.top(),s.rect.bottom())*qMin(f.rect.width(),s.rect.width());
390 | }
391 |
392 | Mode5::Mode5(const Comment &comment):
393 | Plain(comment)
394 | {
395 | if(comment.mode!=5){
396 | return;
397 | }
398 | QSize size=Render::instance()->getActualSize();
399 | QSizeF bound=rect.size();
400 | QString expression=Config::getValue("/Danmaku/Life","5");
401 | expression.replace("%{width}",QString::number(bound.width()),Qt::CaseInsensitive);
402 | if((life=Utils::evaluate(expression))==0){
403 | return;
404 | }
405 | rect.moveCenter(QPointF(size.width()/2.0,0));
406 | rect.moveTop(0);
407 | enabled=true;
408 | }
409 |
410 | bool Mode5::move(qint64 time)
411 | {
412 | if(enabled){
413 | life-=time/1000.0;
414 | }
415 | return life>0;
416 | }
417 |
418 | uint Mode5::intersects(Graphic *other)
419 | {
420 | if(other->getMode()!=5){
421 | return 0;
422 | }
423 | const Mode5 &f=*this;
424 | const Mode5 &s=*dynamic_cast(other);
425 | return getOverlap(f.rect.top(),f.rect.bottom(),s.rect.top(),s.rect.bottom())*qMin(f.rect.width(),s.rect.width());
426 | }
427 |
428 | Mode6::Mode6(const Comment &comment):
429 | Plain(comment)
430 | {
431 | if(comment.mode!=6){
432 | return;
433 | }
434 | QString expression=Config::getValue("/Danmaku/Speed","125+%{width}/5");
435 | expression.replace("%{width}",QString::number(rect.width()),Qt::CaseInsensitive);
436 | if((speed=Utils::evaluate(expression))==0){
437 | return;
438 | }
439 | rect.moveTopLeft(QPointF(-rect.width(),0));
440 | enabled=true;
441 | }
442 |
443 | bool Mode6::move(qint64 time)
444 | {
445 | QSize size=Render::instance()->getActualSize();
446 | if(enabled){
447 | rect.moveLeft(rect.left()+speed*time/1000.0);
448 | }
449 | return rect.left()<=size.width();
450 | }
451 |
452 | uint Mode6::intersects(Graphic *other)
453 | {
454 | if(other->getMode()!=6){
455 | return 0;
456 | }
457 | const Mode6 &f=*dynamic_cast(other);
458 | const Mode6 &s=*this;
459 | int h;
460 | if((h=getOverlap(f.rect.top(),f.rect.bottom(),s.rect.top(),s.rect.bottom()))==0){
461 | return 0;
462 | }
463 | int w=0;
464 | if(f.rect.intersects(s.rect)){
465 | if(f.speed>s.speed){
466 | w=getOverlap(f.rect.left(),f.rect.right(),s.rect.left(),s.rect.right());
467 | }
468 | else{
469 | w=qMin(f.rect.width(),s.rect.width());
470 | }
471 | }
472 | else{
473 | double o=f.rect.left()-f.speed*s.rect.right()/s.speed;
474 | w=o>0?qMin(qMin(f.rect.width(),s.rect.width()),o):0;
475 | }
476 | return h*w;
477 | }
478 |
479 | Mode7::Mode7(const Comment &comment)
480 | {
481 | if(comment.mode!=7){
482 | return;
483 | }
484 | QJsonArray data=QJsonDocument::fromJson(comment.string.toUtf8()).array();
485 | int l;
486 | if((l=data.size())<5){
487 | return;
488 | }
489 | QSize size=Render::instance()->getActualSize();
490 | auto getDouble=[&data](int i){return data.at(i).toVariant().toDouble();};
491 | double scale=getScale(comment.mode,comment.date,size);
492 | bPos=QPointF(getDouble(0),getDouble(1));
493 | ePos=l<8?bPos:QPointF(getDouble(7),getDouble(8));
494 | int w=size.width(),h=size.height();
495 | if(bPos.x()<1&&bPos.y()<1&&ePos.x()<1&&ePos.y()<1){
496 | bPos.rx()*=w;
497 | ePos.rx()*=w;
498 | bPos.ry()*=h;
499 | ePos.ry()*=h;
500 | scale=1;
501 | }
502 | else if(scale==0){
503 | scale=1;
504 | }
505 | else{
506 | QSizeF player=getPlayer(comment.date);
507 | QPoint offset=QPoint((w-player.width()*scale)/2,(h-player.height()*scale)/2);
508 | bPos=bPos*scale+offset;
509 | ePos=ePos*scale+offset;
510 | }
511 | QStringList alpha=data[2].toString().split('-');
512 | bAlpha=alpha[0].toDouble();
513 | eAlpha=alpha[1].toDouble();
514 | life=getDouble(3);
515 | QJsonValue v=l<12?QJsonValue(true):data[11];
516 | int effect=(v.isString()?v.toString()=="true":v.toVariant().toBool())?Config::getValue("/Danmaku/Effect",5)/2:-1;
517 | QFont font=getFont(scale?comment.font*scale:comment.font,l<13?Utils::defaultFont(true):data[12].toString());
518 | QString string=data[4].toString();
519 | cache=getCache(string,comment.color,font,getSize(string,font),comment.isLocal(),effect,100);
520 | zRotate=l<6?0:getDouble(5);
521 | yRotate=l<7?0:getDouble(6);
522 | wait=l<11?0:getDouble(10)/1000;
523 | stay=l<10?0:life-wait-getDouble(9)/1000;
524 | enabled=true;
525 | source=&comment;
526 | time=0;
527 | }
528 |
529 | bool Mode7::move(qint64 time)
530 | {
531 | if(enabled){
532 | this->time+=time/1000.0;
533 | }
534 | return (this->time)<=life;
535 | }
536 |
537 | void Mode7::draw(QPainter *painter)
538 | {
539 | if(enabled){
540 | QPointF cPos=bPos+(ePos-bPos)*qBound(0,(time-wait)/(life-stay),1);
541 | QTransform rotate;
542 | rotate.translate(+cPos.x(),+cPos.y());
543 | rotate.rotate(yRotate,Qt::YAxis);
544 | rotate.rotate(zRotate,Qt::ZAxis);
545 | rotate.translate(-cPos.x(),-cPos.y());
546 | painter->save();
547 | painter->setTransform(rotate);
548 | painter->setOpacity(bAlpha+(eAlpha-bAlpha)*time/life);
549 | painter->drawImage(cPos,cache);
550 | painter->restore();
551 | }
552 | }
553 |
--------------------------------------------------------------------------------
/src/List.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: List.cpp
6 | * Time: 2014/11/19
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #include "List.h"
28 | #include "APlayer.h"
29 | #include "Danmaku.h"
30 | #include "Config.h"
31 | #include "Load.h"
32 | #include "Local.h"
33 | #include
34 |
35 | List *List::ins=nullptr;
36 |
37 | List *List::instance()
38 | {
39 | return ins?ins:new List(qApp);
40 | }
41 |
42 | namespace
43 | {
44 | class IconEngine:public QIconEngine
45 | {
46 | public:
47 | explicit IconEngine(int state):
48 | state(state)
49 | {
50 | }
51 |
52 | void paint(QPainter *p,const QRect &r,QIcon::Mode,QIcon::State)
53 | {
54 | switch(state){
55 | case 0:
56 | p->drawPolyline(QPolygon({(r.topRight()+r.bottomRight())/2,r.center(),(r.bottomLeft()+r.bottomRight())/2}));
57 | break;
58 | case 1:
59 | p->drawLine((r.topRight()+r.topLeft())/2,(r.bottomLeft()+r.bottomRight())/2);
60 | break;
61 | case 2:
62 | p->drawPolyline(QPolygon({(r.topRight()+r.bottomRight())/2,r.center(),(r.topLeft() +r.topRight()) /2}));
63 | break;
64 | default:
65 | break;
66 | }
67 | }
68 |
69 | QIconEngine *clone() const
70 | {
71 | return new IconEngine(state);
72 | }
73 |
74 | private:
75 | int state;
76 | };
77 |
78 | QModelIndex getGroupHead(QModelIndex i)
79 | {
80 | QModelIndex f;
81 | for(int o=0;;++o){
82 | f=i.sibling(i.row()-o,0);
83 | if (f.data(List::CodeRole).toInt()==List::Records||f.row()==0){
84 | return f;
85 | }
86 | }
87 | }
88 |
89 | QModelIndex getGroupTail(QModelIndex i)
90 | {
91 | for(;;){
92 | QModelIndex j=i.sibling(i.row()+1,0);
93 | if (j.isValid()&&j.data(List::CodeRole).toInt()!=List::Records){
94 | i=j;
95 | }
96 | else{
97 | return i;
98 | }
99 | }
100 | }
101 |
102 | void clearItemGroup(int row)
103 | {
104 | QStandardItem *i=List::instance()->item(row);
105 | i->setIcon(QIcon());
106 | i->setData(List::Records,List::CodeRole);
107 | }
108 | }
109 |
110 | List::List(QObject *parent):
111 | QStandardItemModel(parent)
112 | {
113 | ins=this;
114 | setObjectName("List");
115 | cur=nullptr;
116 | time=0;
117 | for(int i=0;i<3;++i){
118 | icons.append(QIcon(new IconEngine(i)));
119 | }
120 | QStandardItem *lastE=nullptr;
121 | QStandardItem *lastD=nullptr;
122 | int lastC=0;
123 | auto conbine=[&](){
124 | if (lastE&&lastD){
125 | QModelIndexList indexes;
126 | for(int i=lastE->row();i<=lastD->row();++i){
127 | indexes.append(index(i,0));
128 | }
129 | setRelated(indexes,lastC);
130 | }
131 | };
132 | for(const QJsonValue &i:Config::getValue("/Playing/List")){
133 | QStandardItem *item=new QStandardItem;
134 | QJsonObject data=i.toObject();
135 | QFileInfo info(data["File"].toString());
136 | item->setData(QColor(info.isFile()?Qt::black:Qt::gray),Qt::ForegroundRole);
137 | item->setText(info.completeBaseName());
138 | item->setData(info.absoluteFilePath(),FileRole);
139 | item->setData(data["Time"].toDouble(),TimeRole);
140 | item->setData(data["Date"].toString(),DateRole);
141 | item->setEditable(false);item->setDropEnabled(false);
142 | QJsonValue danm=data["Danm"];
143 | if (danm.isArray()){
144 | for(const QJsonValue &j:danm.toArray()){
145 | QStandardItem *c=new QStandardItem;
146 | QJsonObject d=j.toObject();
147 | c->setData(d["Code"].toString(),CodeRole);
148 | c->setData(d["Time"].toDouble(),TimeRole);
149 | item->appendRow(c);
150 | }
151 | conbine();
152 | lastE=item;
153 | }
154 | else{
155 | lastC=data["Danm"].toString()=="Inherit"?Inherit:Surmise;
156 | lastD=item;
157 | }
158 | appendRow(item);
159 | }
160 | conbine();
161 |
162 | connect(APlayer::instance(),&APlayer::timeChanged, [this](qint64 _time){
163 | time=_time;
164 | });
165 | connect(APlayer::instance(),&APlayer::mediaChanged,[this](QString file){
166 | updateCurrent();
167 | QStandardItem *old=cur;
168 | cur=itemFromFile(file,true);
169 | if (old){
170 | old->setData(QColor(Qt::black),Qt::ForegroundRole);
171 | }
172 | cur->setData(QColor(90,115,210),Qt::ForegroundRole);
173 | cur->setData(QDateTime::currentDateTime(),DateRole);
174 | bool success=false;
175 | switch(cur->data(CodeRole).toInt()){
176 | case Inherit:
177 | Danmaku::instance()->delayAll(-time);
178 | success=true;
179 | break;;
180 | case Surmise:
181 | for(int i=1;;i++){
182 | QStandardItem *head=item(cur->row()-i);
183 | if (head->data(CodeRole).toInt()!=Records){
184 | continue;
185 | }
186 | for(int j=0;jrowCount();++j){
187 | QString code=head->child(j)->data(CodeRole).toString();
188 | int sharp=code.indexOf(QRegularExpression("[#_]"));
189 | if (sharp!=-1&&!QFile::exists(code)){
190 | QString id=code.mid(0,sharp);
191 | QString pt=code.mid(sharp+1);
192 | Load::instance()->loadDanmaku((id+"#%1").arg(pt.toInt()+i));
193 | success=true;
194 | }
195 | }
196 | break;
197 | }
198 | Danmaku::instance()->clearPool();
199 | break;
200 | case Records:
201 | {
202 | QFileInfo info(cur->data(FileRole).toString());
203 | for(int i=0;irowCount();++i){
204 | Load *load=Load::instance();
205 | QStandardItem *d=cur->child(i);
206 | QString danmaku=d->data(CodeRole).toString();
207 | danmaku.replace("%{File}",info.completeBaseName()).replace("%{Path}",info.absolutePath());
208 | Load::Task task=load->codeToTask(danmaku);
209 | task.delay=d->data(List::TimeRole).value();
210 | load->enqueue(task);
211 | success=true;
212 | }
213 | if (old||success){
214 | Danmaku::instance()->clearPool();
215 | }
216 | break;
217 | }
218 | }
219 | if(!success&&Danmaku::instance()->getPool().isEmpty()){
220 | QFileInfo info(cur->data(FileRole).toString());
221 | QStringList accept=Utils::getSuffix(Utils::Danmaku);
222 | for(const QFileInfo &iter:info.dir().entryInfoList(QDir::Files,QDir::Name)){
223 | QString file=iter.absoluteFilePath();
224 | if(!accept.contains(iter.suffix().toLower())||
225 | info.baseName()!=iter.baseName()){
226 | continue;
227 | }
228 | Load::instance()->loadDanmaku(file);
229 | break;
230 | }
231 | }
232 | });
233 | connect(APlayer::instance(),&APlayer::reach,this,[this](bool m){
234 | if(!m){
235 | QModelIndex i=indexFromItem(cur);
236 | if (jumpToIndex(index(i.row()+1,0,i.parent()),false)&&
237 | APlayer::instance()->getState()!=APlayer::Play){
238 | APlayer::instance()->play();
239 | return;
240 | }
241 | }
242 | updateCurrent();
243 | });
244 | }
245 |
246 | List::~List()
247 | {
248 | QJsonArray list;
249 | updateCurrent();
250 | for(int i=0;iitem(i);
252 | QJsonObject data;
253 | data["File"]=item->data(FileRole).toString();
254 | data["Time"]=item->data(TimeRole).toDouble();
255 | data["Date"]=item->data(DateRole).toString();
256 | switch(item->data(CodeRole).toInt()){
257 | case Records:
258 | {
259 | QJsonArray danm;
260 | for(int i=0;irowCount();++i){
261 | QStandardItem *c=item->child(i);
262 | QJsonObject d;
263 | d["Code"]=c->data(CodeRole).toString();
264 | d["Time"]=c->data(TimeRole).toDouble();
265 | danm.append(d);
266 | }
267 | data["Danm"]=danm;
268 | break;
269 | }
270 | case Inherit:
271 | data["Danm"]="Inherit";
272 | break;
273 | case Surmise:
274 | data["Danm"]="Surmise";
275 | break;
276 | }
277 | list.append(data);
278 | }
279 | Config::setValue("/Playing/List",list);
280 | }
281 |
282 | void List::saveList()
283 | {
284 | QJsonArray list;
285 | updateCurrent();
286 | for(int i=0;iitem(i);
288 | QJsonObject data;
289 | data["File"]=item->data(FileRole).toString();
290 | data["Time"]=item->data(TimeRole).toDouble();
291 | data["Date"]=item->data(DateRole).toString();
292 | switch(item->data(CodeRole).toInt()){
293 | case Records:
294 | {
295 | QJsonArray danm;
296 | for(int i=0;irowCount();++i){
297 | QStandardItem *c=item->child(i);
298 | QJsonObject d;
299 | d["Code"]=c->data(CodeRole).toString();
300 | d["Time"]=c->data(TimeRole).toDouble();
301 | danm.append(d);
302 | }
303 | data["Danm"]=danm;
304 | break;
305 | }
306 | case Inherit:
307 | data["Danm"]="Inherit";
308 | break;
309 | case Surmise:
310 | data["Danm"]="Surmise";
311 | break;
312 | }
313 | list.append(data);
314 | }
315 | Config::setValue("/Playing/List",list);
316 | }
317 |
318 | QStringList List::mimeTypes() const
319 | {
320 | return {"application/x-bililocallistdata"};
321 | }
322 |
323 | namespace
324 | {
325 | QList getItems(const QModelIndexList &indexes)
326 | {
327 | QList items;
328 | for(const QModelIndex&i:indexes){
329 | items.append(List::instance()->itemFromIndex(i));
330 | }
331 | std::sort(items.begin(),items.end(),[](QStandardItem *f,QStandardItem *s){return f->row()row();});
332 | return items;
333 | }
334 | }
335 |
336 | QMimeData *List::mimeData(const QModelIndexList &indexes) const
337 | {
338 | QByteArray byte;
339 | QDataStream s(&byte,QIODevice::WriteOnly);
340 | for(QStandardItem *item:getItems(indexes)){
341 | s<row();
342 | }
343 | QMimeData *data=new QMimeData;
344 | data->setData("application/x-bililocallistdata",byte);
345 | return data;
346 | }
347 |
348 | bool List::dropMimeData(const QMimeData *data,Qt::DropAction action,int row,int column,const QModelIndex &parent)
349 | {
350 | if (action!=Qt::MoveAction||column!=0||parent.isValid()){
351 | return false;
352 | }
353 | if (item(row)&&item(row)->data(CodeRole).toInt()!=Records){
354 | return false;
355 | }
356 | QDataStream s(data->data("application/x-bililocallistdata"));
357 | QList items;
358 | while(!s.atEnd()){
359 | int source;
360 | s>> source;
361 | items.append(item(source));
362 | }
363 | if (items.isEmpty()){
364 | return false;
365 | }
366 | std::sort(items.begin(),items.end(),[](QStandardItem *f,QStandardItem *s){return f->row()row();});
367 | for(QStandardItem *item:items){
368 | split(item->index());
369 | if (item->row()row()));
373 | ++row;
374 | }
375 | return true;
376 | }
377 |
378 | void List::setRelated(const QModelIndexList &indexes,int reason)
379 | {
380 | if (indexes.size()<2){
381 | return;
382 | }
383 | int i=-1;
384 | auto items=getItems(indexes);
385 | split(indexes);
386 | for(QStandardItem *item:items){
387 | if (i<0){
388 | i=item->row();
389 | insertRow(i,takeRow(item->row()));
390 | item->setIcon(icons[0]);
391 | }
392 | else{
393 | ++i;
394 | insertRow(i,takeRow(item->row()));
395 | item->setIcon(icons[1]);
396 | item->setData(reason,CodeRole);
397 | item->setRowCount(0);
398 | }
399 | }
400 | item(i)->setIcon(icons[2]);
401 | }
402 |
403 | QString List::defaultPath(int type)
404 | {
405 | QStandardItem *item=cur;
406 | if (hasChildren()&&!item){
407 | item=this->item(0);
408 | for(int i=1;iitem(i);
410 | if (iter->data(DateRole).toDateTime()>item->data(DateRole).toDateTime()){
411 | item=iter;
412 | }
413 | }
414 | }
415 | if (item){
416 | if (type==Utils::Danmaku){
417 | for(int i=0;irowCount();++i){
418 | QString code=item->child(i)->data(CodeRole).toString();
419 | if (QFile::exists(code)){
420 | return code;
421 | }
422 | }
423 | }
424 | return item->data(FileRole).toString();
425 | }
426 | QStringList paths=QStandardPaths::standardLocations(QStandardPaths::MoviesLocation);
427 | paths.append(QDir::homePath());
428 | return paths.front();
429 | }
430 |
431 | namespace
432 | {
433 | int diffAtNum(QString f,QString s)
434 | {
435 | for(int i=0;idata(FileRole).toString()==file){
450 | return item(i);
451 | }
452 | }
453 | if(!create){
454 | return nullptr;
455 | }
456 | else{
457 | QFileInfo info(file);
458 | QString name=info.completeBaseName();
459 | QString path=info.absoluteFilePath();
460 | QStandardItem *item=new QStandardItem;
461 | item->setText(name);
462 | item->setData(path,FileRole);
463 | item->setEditable(false);item->setDropEnabled(false);
464 | appendRow(item);
465 | QModelIndexList indexes;
466 | indexes.append(item->index());
467 | for(const QFileInfo &iter:info.dir().entryInfoList(QDir::Files,QDir::Name)){
468 | QString p=iter.absoluteFilePath();
469 | QString c=info.completeBaseName();
470 | QString o=iter.completeBaseName();
471 | if(!itemFromFile(p)&&info.suffix()==iter.suffix()&&diffAtNum(c,o)>0){
472 | QStandardItem *i=new QStandardItem;
473 | i->setText(o);
474 | i->setData(p,FileRole);
475 | i->setEditable(false);i->setDropEnabled(false);
476 | appendRow(i);
477 | indexes.append(i->index());
478 | }
479 | }
480 | group(indexes);
481 | return item;
482 | }
483 | }
484 |
485 | bool List::finished()
486 | {
487 | return !hasChildren()||cur==item(rowCount()-1);
488 | }
489 |
490 | void List::appendMedia(QString file)
491 | {
492 | itemFromFile(file,true);
493 | }
494 |
495 | void List::updateCurrent()
496 | {
497 | if(!cur){
498 | return;
499 | }
500 | cur->setRowCount(0);
501 | cur->setData(time,TimeRole);
502 | if (cur->data(CodeRole).toInt()!=Records){
503 | return;
504 | }
505 | QFileInfo info(cur->data(FileRole).toString());
506 | for(const Record &r:Danmaku::instance()->getPool()){
507 | QStandardItem *d=new QStandardItem;
508 | QString danmaku=r.access;
509 | danmaku.replace(info.completeBaseName(),"%{File}").replace(info.absolutePath(),"%{Path}");
510 | d->setData(danmaku,CodeRole);
511 | d->setData(r.delay,TimeRole);
512 | cur->appendRow(d);
513 | }
514 | }
515 |
516 | void List::waste(const QModelIndex &index)
517 | {
518 | if (itemFromIndex(index)==cur){
519 | return;
520 | }
521 | int self=index.row();
522 | int head=getGroupHead(index).row();
523 | int tail=getGroupTail(index).row();
524 | removeRow(self);
525 | switch(tail-head){
526 | case 0:
527 | return;
528 | case 1:
529 | clearItemGroup(head);
530 | return;
531 | default:
532 | --tail;
533 | item(tail)->setIcon(icons[2]);
534 | item(head)->setIcon(icons[0]);
535 | item(head)->setData(Records,CodeRole);
536 | return;
537 | }
538 | }
539 |
540 | void List::waste(const QModelIndexList &indexes)
541 | {
542 | for(QStandardItem *item:getItems(indexes)){
543 | waste(item->index());
544 | }
545 | }
546 |
547 | void List::split(const QModelIndex &index)
548 | {
549 | int self=index.row();
550 | int head=getGroupHead(index).row();
551 | int tail=getGroupTail(index).row();
552 | switch(tail-head){
553 | case 0:
554 | return;
555 | case 1:
556 | clearItemGroup(head);
557 | clearItemGroup(tail);
558 | return;
559 | default:
560 | insertRow(tail,takeRow(self));
561 | clearItemGroup(tail);
562 | --tail;
563 | item(tail)->setIcon(icons[2]);
564 | item(head)->setIcon(icons[0]);
565 | item(head)->setData(Records,CodeRole);
566 | return;
567 | }
568 | }
569 |
570 | void List::split(const QModelIndexList &indexes)
571 | {
572 | QList items=getItems(indexes);
573 | while(!items.isEmpty()){
574 | split(items.takeLast()->index());
575 | }
576 | }
577 |
578 | void List::merge(const QModelIndexList &indexes)
579 | {
580 | setRelated(indexes,Inherit);
581 | }
582 |
583 | void List::group(const QModelIndexList &indexes)
584 | {
585 | setRelated(indexes,Surmise);
586 | }
587 |
588 | void List::jumpToLast()
589 | {
590 | int rc=rowCount();
591 | int i=cur?cur->row():rc;
592 | jumpToIndex(index((i+rc-1)%rc,0));
593 | }
594 |
595 | void List::jumpToNext()
596 | {
597 | int rc=rowCount();
598 | int i=cur?cur->row():-1;
599 | jumpToIndex(index((i+rc+1)%rc,0));
600 | }
601 |
602 | bool List::jumpToIndex(const QModelIndex &index,bool manually)
603 | {
604 | QStandardItem *head=itemFromIndex(index);
605 | if(!head||(manually&&head->data(CodeRole).toInt()==Inherit)){
606 | return false;
607 | }
608 | APlayer::instance()->setMedia(head->data(FileRole).toString(),manually);
609 | return true;
610 | }
611 |
--------------------------------------------------------------------------------
/src/Danmaku.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013 Lysine.
4 | *
5 | * Filename: Danmaku.cpp
6 | * Time: 2013/03/18
7 | * Author: Lysine
8 | *
9 | * Lysine is a student majoring in Software Engineering
10 | * from the School of Software, SUN YAT-SEN UNIVERSITY.
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 |
22 | * You should have received a copy of the GNU General Public License
23 | * along with this program. If not, see .
24 | *
25 | =========================================================================*/
26 |
27 | #include "Danmaku.h"
28 | #include "APlayer.h"
29 | #include "Config.h"
30 | #include "Editor.h"
31 | #include "Graphic.h"
32 | #include "Load.h"
33 | #include "Local.h"
34 | #include "Render.h"
35 | #include "Shield.h"
36 | #include
37 | #include
38 | #include
39 |
40 | #define qThreadPool QThreadPool::globalInstance()
41 |
42 | Danmaku *Danmaku::ins=nullptr;
43 |
44 | Danmaku *Danmaku::instance()
45 | {
46 | return ins?ins:new Danmaku(qApp);
47 | }
48 |
49 | Danmaku::Danmaku(QObject *parent):
50 | QAbstractItemModel(parent)
51 | {
52 | ins=this;
53 | setObjectName("Danmaku");
54 | cur=time=0;
55 | qThreadPool->setMaxThreadCount(Config::getValue("/Danmaku/Thread",QThread::idealThreadCount()));
56 | connect(APlayer::instance(),&APlayer::jumped, this,&Danmaku::jumpToTime);
57 | connect(APlayer::instance(),&APlayer::timeChanged,this,&Danmaku::setTime );
58 | connect(this,SIGNAL(layoutChanged()),Render::instance(),SLOT(draw()));
59 | QMetaObject::invokeMethod(this,"alphaChanged",Qt::QueuedConnection,Q_ARG(int,Config::getValue("/Danmaku/Alpha",100)));
60 | }
61 |
62 | Danmaku::~Danmaku()
63 | {
64 | qThreadPool->clear();
65 | qThreadPool->waitForDone();
66 | qDeleteAll(current);
67 | }
68 |
69 | void Danmaku::draw(QPainter *painter,qint64 move)
70 | {
71 | QVarLengthArray dirty;
72 | lock.lockForWrite();
73 | dirty.reserve(current.size());
74 | for(auto iter=current.begin();iter!=current.end();){
75 | Graphic *g=*iter;
76 | if(g->move(move)){
77 | dirty.append(g);
78 | ++iter;
79 | }
80 | else{
81 | delete g;
82 | iter=current.erase(iter);
83 | }
84 | }
85 | lock.unlock();
86 | for(Graphic *g:dirty){
87 | g->draw(painter);
88 | }
89 | }
90 |
91 | QVariant Danmaku::data(const QModelIndex &index,int role) const
92 | {
93 | if(index.isValid()){
94 | const Comment &comment=*danmaku[index.row()];
95 | switch(role){
96 | case Qt::DisplayRole:
97 | if(index.column()==0){
98 | if(comment.blocked){
99 | return tr("Blocked");
100 | }
101 | else{
102 | QString time("%1:%2");
103 | qint64 sec=comment.time/1000;
104 | if(sec<0){
105 | time.prepend("-");
106 | sec=-sec;
107 | }
108 | time=time.arg(sec/60,2,10,QChar('0'));
109 | time=time.arg(sec%60,2,10,QChar('0'));
110 | return time;
111 | }
112 | }
113 | else{
114 | if(comment.mode==7){
115 | QJsonArray data=QJsonDocument::fromJson(comment.string.toUtf8()).array();
116 | return data.size()>=5?data.at(4).toString():QString();
117 | }
118 | else{
119 | return comment.string.left(50).remove('\n');
120 | }
121 | }
122 | case Qt::ForegroundRole:
123 | if(index.column()==0){
124 | if(comment.blocked||comment.time>=60000000){
125 | return QColor(Qt::red);
126 | }
127 | }
128 | else{
129 | if(comment.blocked){
130 | return QColor(Qt::gray);
131 | }
132 | }
133 | break;
134 | case Qt::ToolTipRole:
135 | if(index.column()==1){
136 | return Qt::convertFromPlainText(comment.string);
137 | }
138 | break;
139 | case Qt::TextAlignmentRole:
140 | if(index.column()==0){
141 | return Qt::AlignCenter;
142 | }
143 | break;
144 | case Qt::BackgroundRole:
145 | switch(comment.mode){
146 | case 7:
147 | return QColor(200,255,200);
148 | case 8:
149 | return QColor(255,255,160);
150 | default:
151 | break;
152 | }
153 | case Qt::UserRole:
154 | return (quintptr)&comment;
155 | }
156 | }
157 | return QVariant();
158 | }
159 |
160 | int Danmaku::rowCount(const QModelIndex &parent) const
161 | {
162 | return parent.isValid()?0:danmaku.size();
163 | }
164 |
165 | int Danmaku::columnCount(const QModelIndex &parent) const
166 | {
167 | return parent.isValid()?0:2;
168 | }
169 |
170 | QModelIndex Danmaku::parent(const QModelIndex &) const
171 | {
172 | return QModelIndex();
173 | }
174 |
175 | QModelIndex Danmaku::index(int row,int colum,const QModelIndex &parent) const
176 | {
177 | if(!parent.isValid()&&colum<2){
178 | return createIndex(row,colum);
179 | }
180 | return QModelIndex();
181 | }
182 |
183 | QVariant Danmaku::headerData(int section,Qt::Orientation orientation,int role) const
184 | {
185 | if(role==Qt::DisplayRole&&orientation==Qt::Horizontal){
186 | if(section==0){
187 | return tr("Time");
188 | }
189 | if(section==1){
190 | return tr("Comment");
191 | }
192 | }
193 | return QVariant();
194 | }
195 |
196 | const Comment *Danmaku::commentAt(QPoint point) const
197 | {
198 | lock.lockForRead();
199 | for(Graphic *g:current){
200 | if(g->currentRect().contains(point)){
201 | lock.unlock();
202 | return g->getSource();
203 | }
204 | }
205 | lock.unlock();
206 | return nullptr;
207 | }
208 |
209 | void Danmaku::setAlpha(int _alpha)
210 | {
211 | Config::setValue("/Danmaku/Alpha", _alpha);
212 | emit alphaChanged(_alpha);
213 | }
214 |
215 | void Danmaku::resetTime()
216 | {
217 | cur=0;
218 | time=0;
219 | }
220 |
221 | void Danmaku::clearPool()
222 | {
223 | if(!pool.isEmpty()){
224 | clearCurrent();
225 | pool.clear();
226 | danmaku.clear();
227 | parse(0x1|0x2);
228 | }
229 | }
230 |
231 | namespace
232 | {
233 | class CommentPointer
234 | {
235 | public:
236 | const Comment *comment;
237 |
238 | CommentPointer(const Comment *comment):
239 | comment(comment)
240 | {
241 | }
242 |
243 | inline bool operator == (const CommentPointer &o) const
244 | {
245 | return *comment==*o.comment;
246 | }
247 | };
248 |
249 | inline uint qHash(const CommentPointer &p, uint seed = 0)
250 | {
251 | return ::qHash(*p.comment,seed);
252 | }
253 | }
254 |
255 | void Danmaku::appendToPool(const Record *record)
256 | {
257 | Record *append=0;
258 | for(Record &r:pool){
259 | if (r.source==record->source){
260 | append=&r;
261 | break;
262 | }
263 | }
264 | if(!append){
265 | pool.append(*record);
266 | QSet s;
267 | auto &d=pool.last().danmaku;
268 | for(auto iter=d.begin();iter!=d.end();){
269 | CommentPointer p(&(*iter));
270 | if(!s.contains(p)){
271 | ++iter;
272 | s.insert(p);
273 | }
274 | else{
275 | iter=d.erase(iter);
276 | }
277 | }
278 | }
279 | else{
280 | auto &d=append->danmaku;
281 | QSet s;
282 | for(const Comment &c:d){
283 | s.insert(&c);
284 | }
285 | for(Comment c:record->danmaku){
286 | c.time+=append->delay-record->delay;
287 | if(!s.contains(&c)){
288 | d.append(c);
289 | s.insert(&d.last());
290 | }
291 | }
292 | if (record->full){
293 | append->full=true;
294 | }
295 | }
296 | parse(0x1|0x2);
297 | if(!append&&Load::instance()->size()<2&&pool.size()>=2){
298 | Editor::exec(lApp->mainWidget());
299 | }
300 | }
301 |
302 | namespace
303 | {
304 | class Compare
305 | {
306 | public:
307 | inline bool operator ()(const Comment *c,qint64 time)
308 | {
309 | return c->time