├── .gitignore
├── BiliLocal.ico
├── BiliLocal.pro
├── COPYING
├── README.md
├── plugins
├── BiliAPI
│ ├── BiliAPI.pro
│ ├── Load.h
│ ├── biliapi.cpp
│ ├── biliapi.h
│ └── biliapi_global.h
└── StayAwakePoi
│ ├── StayAwakePoi.pro
│ ├── poi.cpp
│ ├── poi.h
│ └── stayawakepoi_global.h
├── res
├── 00.jpg
├── 00.png
├── 01.jpg
├── 01.png
├── 02.jpg
├── COPYING
├── DATA
├── INFO
├── Res.qrc
├── THANKS
├── icon.png
├── next.png
├── pause.png
├── play.png
├── previous.png
├── sound.png
├── stop.png
├── tv.gif
├── version.png
├── zh_CN.ts
└── zh_TW.ts
└── src
├── Access
├── AccessPrivate.h
├── Load.cpp
├── Load.h
├── NetworkConfiguration.cpp
├── NetworkConfiguration.h
├── Parse.cpp
├── Parse.h
├── Post.cpp
├── Post.h
├── Seek.cpp
├── Seek.h
├── Sign.cpp
└── Sign.h
├── Common.cpp
├── Common.h
├── Config.cpp
├── Config.h
├── Graphic
├── Graphic.cpp
├── Graphic.h
├── GraphicPrivate.cpp
├── GraphicPrivate.h
├── Mode1.cpp
├── Mode1.h
├── Mode4.cpp
├── Mode4.h
├── Mode5.cpp
├── Mode5.h
├── Mode6.cpp
├── Mode6.h
├── Mode7.cpp
├── Mode7.h
├── Plain.cpp
└── Plain.h
├── Local.cpp
├── Local.h
├── Model
├── Danmaku.cpp
├── Danmaku.h
├── List.cpp
├── List.h
├── Shield.cpp
└── Shield.h
├── Player
├── APlayer.cpp
├── APlayer.h
├── NPlayer.cpp
├── NPlayer.h
├── QPlayer.cpp
├── QPlayer.h
├── VPlayer.cpp
└── VPlayer.h
├── Plugin.cpp
├── Plugin.h
├── Render
├── ARender.cpp
├── ARender.h
├── ARenderPrivate.h
├── ElapsedTimer.h
├── ISprite.h
├── OpenGLRender
│ ├── DetachPrivate.cpp
│ ├── DetachPrivate.h
│ ├── OpaquePrivate.h
│ ├── OpenGLRender.cpp
│ ├── OpenGLRender.h
│ ├── OpenGLRenderPrivate.h
│ ├── SyncTextureSprite.cpp
│ ├── SyncTextureSprite.h
│ ├── WidgetPrivate.cpp
│ ├── WidgetPrivate.h
│ ├── WindowPrivate.cpp
│ └── WindowPrivate.h
└── RasterRender
│ ├── AsyncRasterSprite.h
│ ├── RasterRender.cpp
│ ├── RasterRender.h
│ └── RasterRenderPrivate.h
├── UI
├── Editor.cpp
├── Editor.h
├── Info.cpp
├── Info.h
├── Interface.cpp
├── Interface.h
├── Jump.cpp
├── Jump.h
├── Menu.cpp
├── Menu.h
├── Prefer.cpp
├── Prefer.h
├── Search.cpp
├── Search.h
├── Type.cpp
└── Type.h
├── Utils.cpp
└── Utils.h
/.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 | *.vspx
16 | *.ipch
17 | *.opendb
18 | bin
--------------------------------------------------------------------------------
/BiliLocal.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asahui/BiliLocal-OSX/95dab3b53c4bf085626fcbf61f2589afb1f6f356/BiliLocal.ico
--------------------------------------------------------------------------------
/BiliLocal.pro:
--------------------------------------------------------------------------------
1 | QT += \
2 | core \
3 | gui \
4 | network \
5 | widgets \
6 | xml \
7 | concurrent
8 |
9 | TARGET = BiliLocal
10 |
11 | TEMPLATE = app
12 |
13 | CONFIG += c++11
14 |
15 | SOURCES += \
16 | src/Access/Load.cpp \
17 | src/Access/NetworkConfiguration.cpp \
18 | src/Access/Parse.cpp \
19 | src/Access/Post.cpp \
20 | src/Access/Seek.cpp \
21 | src/Access/Sign.cpp \
22 | src/Graphic/Graphic.cpp \
23 | src/Graphic/GraphicPrivate.cpp \
24 | src/Graphic/Mode1.cpp \
25 | src/Graphic/Mode4.cpp \
26 | src/Graphic/Mode5.cpp \
27 | src/Graphic/Mode6.cpp \
28 | src/Graphic/Mode7.cpp \
29 | src/Graphic/Plain.cpp \
30 | src/Model/Danmaku.cpp \
31 | src/Model/List.cpp \
32 | src/Model/Shield.cpp \
33 | src/Player/APlayer.cpp \
34 | src/Render/ARender.cpp \
35 | src/UI/Editor.cpp \
36 | src/UI/Info.cpp \
37 | src/UI/Interface.cpp \
38 | src/UI/Jump.cpp \
39 | src/UI/Menu.cpp \
40 | src/UI/Prefer.cpp \
41 | src/UI/Search.cpp \
42 | src/UI/Type.cpp \
43 | src/Config.cpp \
44 | src/Local.cpp \
45 | src/Utils.cpp \
46 | src/Plugin.cpp
47 |
48 | HEADERS += \
49 | src/Access/AccessPrivate.h \
50 | src/Access/Load.h \
51 | src/Access/NetworkConfiguration.h \
52 | src/Access/Parse.h \
53 | src/Access/Post.h \
54 | src/Access/Seek.h \
55 | src/Access/Sign.h \
56 | src/Graphic/Graphic.h \
57 | src/Graphic/GraphicPrivate.h \
58 | src/Graphic/Mode1.h \
59 | src/Graphic/Mode4.h \
60 | src/Graphic/Mode5.h \
61 | src/Graphic/Mode6.h \
62 | src/Graphic/Mode7.h \
63 | src/Graphic/Plain.h \
64 | src/Model/Danmaku.h \
65 | src/Model/List.h \
66 | src/Model/Shield.h \
67 | src/Player/APlayer.h \
68 | src/Render/ARender.h \
69 | src/Render/ARenderPrivate.h \
70 | src/Render/ISprite.h \
71 | src/Render/ElapsedTimer.h \
72 | src/UI/Editor.h \
73 | src/UI/Info.h \
74 | src/UI/Interface.h \
75 | src/UI/Jump.h \
76 | src/UI/Menu.h \
77 | src/UI/Prefer.h \
78 | src/UI/Search.h \
79 | src/UI/Type.h \
80 | src/Config.h \
81 | src/Local.h \
82 | src/Utils.h \
83 | src/Plugin.h
84 |
85 | INCLUDEPATH += \
86 | src
87 |
88 | PRECOMPILED_HEADER = \
89 | src/Common.h
90 |
91 | RESOURCES += \
92 | res/Res.qrc
93 |
94 | TRANSLATIONS += \
95 | res/zh_CN.ts \
96 | res/zh_TW.ts
97 |
98 | linux{
99 | DEFINES += \
100 | BACKEND_VLC \
101 | BACKEND_QMM \
102 | BACKEND_NIL
103 |
104 | DEFINES += \
105 | RENDER_RASTER \
106 | RENDER_OPENGL
107 |
108 | LIBS += \
109 | -lcrypto \
110 | -lssl
111 | }
112 |
113 | win32{
114 | RC_ICONS = BiliLocal.ico
115 |
116 | DEFINES += \
117 | BACKEND_VLC \
118 | BACKEND_QMM \
119 | BACKEND_NIL
120 |
121 | DEFINES += \
122 | RENDER_OPENGL
123 |
124 | INCLUDEPATH += \
125 | D:/App/Programming/include
126 |
127 | LIBS += \
128 | -llibeay32 \
129 | -lssleay32
130 |
131 | !contains(QMAKE_TARGET.arch, x86_64){
132 | DEFINES += \
133 | RENDER_RASTER
134 |
135 | DEPENDPATH += \
136 | -LD:/App/Programming/lib
137 | }
138 | else{
139 | DEPENDPATH += \
140 | -LD:/App/Programming/lib/amd64
141 | }
142 | }
143 |
144 | macx{
145 | DEFINES += \
146 | BACKEND_VLC \
147 | BACKEND_NIL
148 |
149 | DEFINES += \
150 | # RENDER_RASTER \
151 | RENDER_OPENGL
152 |
153 | LIBS += \
154 | -lcrypto \
155 | -lssl
156 | }
157 |
158 | contains(DEFINES, BACKEND_VLC){
159 | SOURCES += \
160 | src/Player/VPlayer.cpp
161 |
162 | HEADERS += \
163 | src/Player/VPlayer.h
164 |
165 | LIBS += \
166 | -lvlc \
167 | -lvlccore
168 | }
169 |
170 | contains(DEFINES, BACKEND_QMM){
171 | SOURCES += \
172 | src/Player/QPlayer.cpp
173 |
174 | HEADERS += \
175 | src/Player/QPlayer.h
176 |
177 | QT += \
178 | multimedia
179 | }
180 |
181 | contains(DEFINES, BACKEND_NIL){
182 | SOURCES += \
183 | src/Player/NPlayer.cpp
184 |
185 | HEADERS += \
186 | src/Player/NPlayer.h
187 | }
188 |
189 | contains(DEFINES, RENDER_RASTER){
190 | SOURCES += \
191 | src/Render/RasterRender/RasterRender.cpp
192 |
193 | HEADERS += \
194 | src/Render/RasterRender/RasterRender.h \
195 | src/Render/RasterRender/RasterRenderPrivate.h \
196 | src/Render/RasterRender/AsyncRasterSprite.h
197 |
198 | LIBS += \
199 | -lswscale \
200 | -lavutil
201 | }
202 |
203 | contains(DEFINES, RENDER_OPENGL){
204 | SOURCES += \
205 | src/Render/OpenGLRender/OpenGLRender.cpp \
206 | src/Render/OpenGLRender/SyncTextureSprite.cpp \
207 | src/Render/OpenGLRender/DetachPrivate.cpp \
208 | src/Render/OpenGLRender/WidgetPrivate.cpp \
209 | src/Render/OpenGLRender/WindowPrivate.cpp
210 |
211 | HEADERS += \
212 | src/Render/OpenGLRender/OpenGLRender.h \
213 | src/Render/OpenGLRender/OpenGLRenderPrivate.h \
214 | src/Render/OpenGLRender/SyncTextureSprite.h \
215 | src/Render/OpenGLRender/DetachPrivate.h \
216 | src/Render/OpenGLRender/OpaquePrivate.h \
217 | src/Render/OpenGLRender/WidgetPrivate.h \
218 | src/Render/OpenGLRender/WindowPrivate.h
219 | }
220 |
221 | ICON = BiliLocal.icns
222 |
223 | LIBS += -L$$PWD/dep/lib/
224 | INCLUDEPATH += dep/include/
225 | # INCLUDEPATH += dep/include/ffmpeg
226 | DEPENDPATH += dep/include/
227 | # DEPENDPATH += dep/include/ffmpeg
228 |
229 |
230 | DISTFILES += BiliLocal.icns
231 |
232 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | BiliLocal-OSX
2 | =========
3 | OSX build of [BiliLocal](https://github.com/AncientLysine/BiliLocal)
4 |
5 | Features
6 | --------
7 | 1. Fix some problems
8 |
9 | 2. Plugins for this OSX build
10 | - BiliAPI: api plugins. Fetch danmaku (and media url) via bilibili api
11 | - StayAwakePoi: Prevent screen from falling asleep while video is playing.
12 |
13 | 3. [Under Developing] Play online BiliBili video
14 | - Bugs exists.
15 | - Can not fetch url of copyrights video
16 |
17 |
18 | TO-DO
19 | ----
20 | 1. Fix Bugs
21 |
22 | 2. Add mpv as a backend player (I think I am too lazy and don't have time to work on it. It is just a dream)
23 |
24 |
25 | Screenshots
26 | ----------
27 | 
28 |
29 | 
30 |
31 |
--------------------------------------------------------------------------------
/plugins/BiliAPI/BiliAPI.pro:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------
2 | #
3 | # Project created by QtCreator 2015-08-28T16:26:23
4 | #
5 | #-------------------------------------------------
6 |
7 | QT += widgets network xml
8 |
9 | QT -= gui
10 |
11 | CONFIG += c++11
12 |
13 | TARGET = BiliAPI
14 | TEMPLATE = lib
15 |
16 | DEFINES += BILIAPI_LIBRARY
17 |
18 | SOURCES += biliapi.cpp
19 |
20 | HEADERS += biliapi.h\
21 | biliapi_global.h
22 |
23 |
24 | unix {
25 | target.path = /usr/lib
26 | INSTALLS += target
27 | }
28 |
--------------------------------------------------------------------------------
/plugins/BiliAPI/Load.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 | #pragma once
28 |
29 | #include
30 | #include
31 | #include
32 | #include
33 |
34 | class Load : public QObject
35 | {
36 | Q_OBJECT
37 | public:
38 | enum State
39 | {
40 | None = 0,
41 | Page = 381,
42 | Part = 407,
43 | Code = 379,
44 | File = 384,
45 | };
46 |
47 | enum Role
48 | {
49 | UrlRole = Qt::UserRole,
50 | StrRole,
51 | NxtRole
52 | };
53 |
54 | struct Proc
55 | {
56 | std::function regular;
57 | int priority;
58 | std::function process;
59 | };
60 |
61 | struct Task
62 | {
63 | QString code;
64 | QNetworkRequest request;
65 | int state;
66 | const Proc *processer;
67 | qint64 delay;
68 | Task() :state(None), processer(nullptr), delay(0){}
69 | };
70 |
71 | signals:
72 | void stateChanged(int state);
73 |
74 | public slots:
75 | void addProc(const Load::Proc *proc);
76 |
77 | void dumpDanmaku(const QByteArray &data, int site, bool full);
78 |
79 | QStandardItemModel *getModel();
80 | void forward(QNetworkRequest, int);
81 | void dequeue();
82 | Load::Task *getHead();
83 | };
84 |
--------------------------------------------------------------------------------
/plugins/BiliAPI/biliapi.h:
--------------------------------------------------------------------------------
1 | #ifndef BILIAPI_H
2 | #define BILIAPI_H
3 |
4 | #include "biliapi_global.h"
5 | #include
6 | #include
7 |
8 |
9 | extern "C" BILIAPISHARED_EXPORT void regist(const QHash &objects);
10 | extern "C" BILIAPISHARED_EXPORT QString string(QString query);
11 | extern "C" BILIAPISHARED_EXPORT void config(QWidget *parent);
12 |
13 |
14 | class BiliAPI:public QObject
15 | {
16 |
17 | public:
18 | explicit BiliAPI(QObject* parent, QObject *load);
19 |
20 | private:
21 | };
22 |
23 | #endif // BILIAPI_H
24 |
--------------------------------------------------------------------------------
/plugins/BiliAPI/biliapi_global.h:
--------------------------------------------------------------------------------
1 | #ifndef BILIAPI_GLOBAL_H
2 | #define BILIAPI_GLOBAL_H
3 |
4 | #include
5 |
6 | #if defined(BILIAPI_LIBRARY)
7 | # define BILIAPISHARED_EXPORT Q_DECL_EXPORT
8 | #else
9 | # define BILIAPISHARED_EXPORT Q_DECL_IMPORT
10 | #endif
11 |
12 | #endif // BILIAPI_GLOBAL_H
13 |
--------------------------------------------------------------------------------
/plugins/StayAwakePoi/StayAwakePoi.pro:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------
2 | #
3 | # Project created by QtCreator 2015-08-28T16:11:25
4 | #
5 | #-------------------------------------------------
6 |
7 | QT += widgets
8 |
9 | QT -= gui
10 |
11 | CONFIG += c++11
12 |
13 | TARGET = StayAwakePoi
14 | TEMPLATE = lib
15 |
16 | DEFINES += STAYAWAKEPOI_LIBRARY
17 |
18 | SOURCES += poi.cpp\
19 |
20 | HEADERS += poi.h\
21 | stayawakepoi_global.h\
22 |
23 | unix {
24 | target.path = /usr/lib
25 | INSTALLS += target
26 | }
27 |
28 | LIBS += -framework IOKit
29 | LIBS += -framework CoreFoundation
30 |
--------------------------------------------------------------------------------
/plugins/StayAwakePoi/poi.cpp:
--------------------------------------------------------------------------------
1 | #include "poi.h"
2 | #include "../BiliLocal/src/Player/APlayer.h"
3 |
4 | #import
5 | // kIOPMAssertionTypeNoDisplaySleep prevents display sleep,
6 | // kIOPMAssertionTypeNoIdleSleep prevents idle sleep
7 |
8 | // reasonForActivity is a descriptive string used by the system whenever it needs
9 | // to tell the user why the system is not sleeping. For example,
10 | // "Mail Compacting Mailboxes" would be a useful string.
11 |
12 | // NOTE: IOPMAssertionCreateWithName limits the string to 128 characters.
13 |
14 | enum QueryName
15 | {
16 | Name,
17 | Version,
18 | Description,
19 | Author
20 | };
21 |
22 | static QHash queryNameMap;
23 |
24 | void regist(const QHash &objects)
25 | {
26 | Poi* poi = new Poi(objects["Interface"], objects["APlayer"]);
27 | }
28 |
29 | QString string(QString query)
30 | {
31 | queryNameMap["Name"] = Name;
32 | queryNameMap["Version"] = Version;
33 | queryNameMap["Description"] = Description;
34 | queryNameMap["Author"] = Author;
35 | switch(queryNameMap[query]) {
36 | case Name:
37 | return QString("StayAwakePoi");
38 | break;
39 | case Version:
40 | return QString("0.4.2");
41 | break;
42 | case Description:
43 | return QString("Poooooi!");
44 | break;
45 | case Author:
46 | return QString("asahui");
47 | break;
48 | default:
49 | break;
50 | }
51 | }
52 |
53 | void config(QWidget *parent)
54 | {
55 | QDialog d(parent);
56 | if (d.exec()) {
57 |
58 | }
59 | }
60 |
61 | Poi::Poi(QObject *parent, QObject *aplayer):QObject(parent)
62 | {
63 | state = 0;
64 | assertionID = 0;
65 |
66 | connect(aplayer,
67 | aplayer->metaObject()->method(aplayer->metaObject()->indexOfMethod(QMetaObject::normalizedSignature("stateChanged(int)"))),
68 | this,
69 | this->metaObject()->method(this->metaObject()->indexOfSlot(QMetaObject::normalizedSignature("preventSleep(int)")))
70 | );
71 | }
72 |
73 | void Poi::preventSleep(int _state)
74 | {
75 | CFStringRef reasonForActivity= CFSTR("Playing: Prevent Sleeping");
76 | if (_state == APlayer::Play || _state == APlayer::Loop) {
77 | //qDebug() << "assertionID: " << assertionID;
78 | if (state != 0) {
79 | return;
80 | }
81 | IOReturn success = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
82 | kIOPMAssertionLevelOn, reasonForActivity, &assertionID);
83 | if (success == kIOReturnSuccess)
84 | {
85 | qDebug() << "Poi: tetoku, stay awake!";
86 | //qDebug() << "assertionID: " << assertionID;
87 | state = 1;
88 | // Add the work you need to do without
89 | // the system sleeping here.
90 | }
91 | } else {
92 | state = 0;
93 | IOReturn success = IOPMAssertionRelease(assertionID);
94 | if (success == kIOReturnSuccess) {
95 | qDebug() << "Poi: oyasumi";
96 | //qDebug() << "assertionID: " << assertionID;
97 | //assertionID = 0;
98 | }
99 | // The system will be able to sleep again.
100 | }
101 | }
102 |
103 | Poi::~Poi()
104 | {
105 | if (state != 0) {
106 | state = 0;
107 | IOReturn success = IOPMAssertionRelease(assertionID);
108 | if (success == kIOReturnSuccess) {
109 | qDebug() << "Poi: oyasumi";
110 | //qDebug() << "assertionID: " << assertionID;
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/plugins/StayAwakePoi/poi.h:
--------------------------------------------------------------------------------
1 | #ifndef POI_H
2 | #define POI_H
3 |
4 | #include "stayawakepoi_global.h"
5 | #include
6 | #include
7 | #import
8 |
9 |
10 | extern "C" POI_EXPORT void regist(const QHash &objects);
11 |
12 | extern "C" POI_EXPORT QString string(QString query);
13 |
14 | extern "C" POI_EXPORT void config(QWidget *parent);
15 |
16 | class Poi: public QObject
17 | {
18 | Q_OBJECT
19 | public:
20 | explicit Poi(QObject* parent, QObject* aplayer);
21 | ~Poi();
22 | private:
23 | int state;
24 | IOPMAssertionID assertionID;
25 | public slots:
26 | void preventSleep(int state);
27 | };
28 |
29 | #endif // POI_H
30 |
--------------------------------------------------------------------------------
/plugins/StayAwakePoi/stayawakepoi_global.h:
--------------------------------------------------------------------------------
1 | #ifndef STAYAWAKEPOI_GLOBAL_H
2 | #define STAYAWAKEPOI_GLOBAL_H
3 |
4 | #include
5 |
6 | #if defined(STAYAWAKEPOI_LIBRARY)
7 | # define POI_EXPORT Q_DECL_EXPORT
8 | #else
9 | # define POI_EXPORT Q_DECL_IMPORT
10 | #endif
11 |
12 | #endif // STAYAWAKEPOI_GLOBAL_H
13 |
--------------------------------------------------------------------------------
/res/00.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asahui/BiliLocal-OSX/95dab3b53c4bf085626fcbf61f2589afb1f6f356/res/00.jpg
--------------------------------------------------------------------------------
/res/00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asahui/BiliLocal-OSX/95dab3b53c4bf085626fcbf61f2589afb1f6f356/res/00.png
--------------------------------------------------------------------------------
/res/01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asahui/BiliLocal-OSX/95dab3b53c4bf085626fcbf61f2589afb1f6f356/res/01.jpg
--------------------------------------------------------------------------------
/res/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asahui/BiliLocal-OSX/95dab3b53c4bf085626fcbf61f2589afb1f6f356/res/01.png
--------------------------------------------------------------------------------
/res/02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asahui/BiliLocal-OSX/95dab3b53c4bf085626fcbf61f2589afb1f6f356/res/02.jpg
--------------------------------------------------------------------------------
/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 | "Logo": {
55 | "DirectX": "http://upload.wikimedia.org/wikipedia/commons/1/11/DirectX_logo.png",
56 | "FFmpeg": "http://www.ffmpeg.org/ffmpeg-logo.png",
57 | "OpenGL": "https://www.khronos.org/assets/uploads/ceimg/made/assets/uploads/apis/OpenGL-ES_300_199_75.png",
58 | "VLC": "http://images.videolan.org/images/logoOrange.png"
59 | },
60 | "Version": "0.4.2"
61 | }
62 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asahui/BiliLocal-OSX/95dab3b53c4bf085626fcbf61f2589afb1f6f356/res/icon.png
--------------------------------------------------------------------------------
/res/next.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asahui/BiliLocal-OSX/95dab3b53c4bf085626fcbf61f2589afb1f6f356/res/next.png
--------------------------------------------------------------------------------
/res/pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asahui/BiliLocal-OSX/95dab3b53c4bf085626fcbf61f2589afb1f6f356/res/pause.png
--------------------------------------------------------------------------------
/res/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asahui/BiliLocal-OSX/95dab3b53c4bf085626fcbf61f2589afb1f6f356/res/play.png
--------------------------------------------------------------------------------
/res/previous.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asahui/BiliLocal-OSX/95dab3b53c4bf085626fcbf61f2589afb1f6f356/res/previous.png
--------------------------------------------------------------------------------
/res/sound.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asahui/BiliLocal-OSX/95dab3b53c4bf085626fcbf61f2589afb1f6f356/res/sound.png
--------------------------------------------------------------------------------
/res/stop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asahui/BiliLocal-OSX/95dab3b53c4bf085626fcbf61f2589afb1f6f356/res/stop.png
--------------------------------------------------------------------------------
/res/tv.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asahui/BiliLocal-OSX/95dab3b53c4bf085626fcbf61f2589afb1f6f356/res/tv.gif
--------------------------------------------------------------------------------
/res/version.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asahui/BiliLocal-OSX/95dab3b53c4bf085626fcbf61f2589afb1f6f356/res/version.png
--------------------------------------------------------------------------------
/src/Access/AccessPrivate.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "NetworkConfiguration.h"
4 | #include
5 | #include
6 | #include
7 |
8 | template
9 | class AccessPrivate
10 | {
11 | public:
12 | QList pool;
13 | QNetworkAccessManager manager;
14 | QQueue queue;
15 | QSet remain;
16 | Access *const access;
17 |
18 | inline Access* q_func()
19 | {
20 | return static_cast(access);
21 | }
22 |
23 | explicit AccessPrivate(Access *access) :
24 | access(access)
25 | {
26 | QObject::connect(&manager, &QNetworkAccessManager::finished, [this](QNetworkReply *reply){
27 | Q_Q(Access);
28 | remain.remove(reply);
29 | reply->deleteLater();
30 | if (reply->error() != QNetworkReply::NoError && !onError(reply)){
31 | return;
32 | }
33 | QUrl redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
34 | if (!redirect.isValid()){
35 | queue.head().processer->process(reply);
36 | }
37 | else{
38 | queue.head().request = QNetworkRequest(redirect);
39 | q->forward();
40 | }
41 | });
42 | NetworkConfiguration::instance()->setManager(&manager);
43 | }
44 |
45 | virtual ~AccessPrivate() = default;
46 |
47 | void addProc(const Proc *proc)
48 | {
49 | pool.append(*proc);
50 | }
51 |
52 | const Proc *getProc(QString code)
53 | {
54 | const Proc *p = nullptr;
55 | for (const Proc &i : pool){
56 | QString t(code);
57 | if (i.regular(t) && t == code && (!p || i.priority>p->priority)){
58 | p = &i;
59 | }
60 | }
61 | return p;
62 | }
63 |
64 | void dequeue()
65 | {
66 | Q_Q(Access);
67 | static bool flag;
68 | if (flag){
69 | return;
70 | }
71 | flag = 1;
72 | for (QNetworkReply *r : QSet(remain)){
73 | r->abort();
74 | }
75 | flag = 0;
76 | queue.dequeue();
77 | if (queue.size()){
78 | q->forward();
79 | }
80 | }
81 |
82 | bool enqueue(const Task &task)
83 | {
84 | Q_Q(Access);
85 | for (const Task &iter : queue){
86 | if (iter.code == task.code){
87 | return false;
88 | }
89 | }
90 | queue.enqueue(task);
91 | if (queue.size() == 1){
92 | q->forward();
93 | }
94 | return true;
95 | }
96 |
97 | Task *getHead()
98 | {
99 | return queue.isEmpty() ? nullptr : &queue.head();
100 | }
101 |
102 | void forward()
103 | {
104 | Q_Q(Access);
105 | Task &task = queue.head();
106 | if (!task.processer){
107 | task.state = QNetworkReply::ProtocolUnknownError;
108 | emit q->stateChanged(task.state);
109 | q->dequeue();
110 | return;
111 | }
112 | if (task.state == 0){
113 | task.processer->process(nullptr);
114 | }
115 | else{
116 | onShift();
117 | }
118 | }
119 |
120 | virtual void onShift()
121 | {
122 | Q_Q(Access);
123 | Task &task = queue.head();
124 | emit q->stateChanged(task.state);
125 | remain.insert(manager.get(task.request));
126 | }
127 |
128 | virtual bool onError(QNetworkReply *reply)
129 | {
130 | Q_Q(Access);
131 | if (reply->error() != QNetworkReply::OperationCanceledError)
132 | emit q->stateChanged(reply->error());
133 | q->dequeue();
134 | return false;
135 | }
136 |
137 | bool tryNext()
138 | {
139 | Task task = queue.head();
140 | task.request = QNetworkRequest();
141 | task.state = Access::None;
142 | QList list;
143 | int accept = 0;
144 | for (const Proc &i : pool){
145 | QString code(task.code);
146 | if (i.regular(code)){
147 | if (code.length()> accept){
148 | accept = code.length();
149 | list.clear();
150 | }
151 | if (code.length() == accept){
152 | list.append(&i);
153 | }
154 | }
155 | }
156 | std::stable_sort(list.begin(), list.end(), [](const Proc* f, const Proc *s){
157 | return f->priority > s->priority;
158 | });
159 | int offset = list.indexOf(task.processer) + 1;
160 | if (offset.
24 | *
25 | =========================================================================*/
26 |
27 | #pragma once
28 |
29 | #include
30 | #include
31 | #include
32 | #include
33 |
34 | class Comment;
35 | class Record;
36 | class LoadPrivate;
37 |
38 | class Load : public QObject
39 | {
40 | Q_OBJECT
41 | public:
42 | enum State
43 | {
44 | None = 0,
45 | Page = 381,
46 | Part = 407,
47 | Code = 379,
48 | File = 384,
49 | };
50 |
51 | enum Role
52 | {
53 | UrlRole = Qt::UserRole,
54 | StrRole,
55 | NxtRole
56 | };
57 |
58 | struct Proc
59 | {
60 | std::function regular;
61 | int priority;
62 | std::function process;
63 | };
64 |
65 | struct Task
66 | {
67 | QString code;
68 | QNetworkRequest request;
69 | int state;
70 | const Proc *processer;
71 | qint64 delay;
72 | Task() :state(None), processer(nullptr), delay(0){}
73 | };
74 |
75 | Task codeToTask(QString code);
76 | static Load *instance();
77 | ~Load();
78 |
79 | private:
80 | static Load *ins;
81 | LoadPrivate *const d_ptr;
82 | Q_DECLARE_PRIVATE(Load);
83 |
84 | explicit Load(QObject *parent);
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 Load::Proc *proc);
93 | const Load::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 QVector *data, bool full);
105 | void dumpDanmaku(const QByteArray &data, int site, bool full);
106 |
107 | QStandardItemModel *getModel();
108 | void forward();
109 | void forward(QNetworkRequest);
110 | void forward(QNetworkRequest, int);
111 | void dequeue();
112 | bool enqueue(const Load::Task &);
113 | Load::Task *getHead();
114 |
115 | void loadURL(QString);
116 | void setMedia(const QStringList, const QString title);
117 | };
118 |
--------------------------------------------------------------------------------
/src/Access/NetworkConfiguration.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "NetworkConfiguration.h"
3 | #include "../Config.h"
4 | #include
5 |
6 | NetworkConfiguration *NetworkConfiguration::ins = nullptr;
7 |
8 | NetworkConfiguration *NetworkConfiguration::instance()
9 | {
10 | return ins ? ins : new NetworkConfiguration(qApp);
11 | }
12 |
13 | namespace
14 | {
15 | class Cookie :public QNetworkCookieJar
16 | {
17 | public:
18 | Cookie(QObject *parent = 0) :
19 | QNetworkCookieJar(parent)
20 | {
21 | }
22 |
23 | void load()
24 | {
25 | QByteArray buff;
26 | buff = Config::getValue("/Network/Cookie", QString()).toUtf8();
27 | buff = buff.isEmpty() ? buff : qUncompress(QByteArray::fromBase64(buff));
28 | QDataStream read(buff);
29 | QList all;
30 | int n, l;
31 | read >> n;
32 | for (int i = 0; i < n; ++i){
33 | read >> l;
34 | char *d = new char[l];
35 | read.readRawData(d, l);
36 | all.append(QNetworkCookie::parseCookies(QByteArray(d, l)));
37 | delete[]d;
38 | }
39 | setAllCookies(all);
40 | }
41 |
42 | void save()
43 | {
44 | QByteArray buff;
45 | QDataStream save(&buff, QIODevice::WriteOnly);
46 | const QList &all = allCookies();
47 | save << all.count();
48 | for (const QNetworkCookie &iter : all){
49 | QByteArray d = iter.toRawForm();
50 | save << d.size();
51 | save.writeRawData(d.data(), d.size());
52 | }
53 | Config::setValue("/Network/Cookie", QString(qCompress(buff).toBase64()));
54 | }
55 |
56 | void clear()
57 | {
58 | setAllCookies(QList());
59 | }
60 | };
61 |
62 | class DCache :public QNetworkDiskCache
63 | {
64 | public:
65 | DCache(QObject *parent = 0) :
66 | QNetworkDiskCache(parent)
67 | {
68 | }
69 |
70 | void load()
71 | {
72 | setCacheDirectory("./cache");
73 | setMaximumCacheSize(Config::getValue("/Network/Cache/Maximum", 100 * 1024 * 1024));
74 | }
75 | };
76 |
77 | class APorxy
78 | {
79 | public:
80 | void load()
81 | {
82 | QNetworkProxy proxy;
83 | proxy.setType((QNetworkProxy::ProxyType)Config::getValue("/Network/Proxy/Type", QNetworkProxy::NoProxy));
84 | proxy.setHostName(Config::getValue("/Network/Proxy/HostName"));
85 | proxy.setPort(Config::getValue("/Network/Proxy/Port"));
86 | proxy.setUser(Config::getValue("/Network/Proxy/User"));
87 | proxy.setPassword(Config::getValue("/Network/Proxy/Password"));
88 | QNetworkProxy::setApplicationProxy(proxy);
89 | }
90 |
91 | void save()
92 | {
93 | QNetworkProxy proxy = QNetworkProxy::applicationProxy();
94 | Config::setValue("/Network/Proxy/Type", proxy.type());
95 | Config::setValue("/Network/Proxy/HostName", proxy.hostName());
96 | Config::setValue("/Network/Proxy/Port", proxy.port());
97 | Config::setValue("/Network/Proxy/User", proxy.user());
98 | Config::setValue("/Network/Proxy/Password", proxy.password());
99 | }
100 | };
101 | }
102 |
103 | class NetworkConfigurationPrivate
104 | {
105 | public:
106 | DCache d;
107 | Cookie c;
108 | APorxy p;
109 | };
110 |
111 | NetworkConfiguration::NetworkConfiguration(QObject *parent) :
112 | QObject(parent), d_ptr(new NetworkConfigurationPrivate)
113 | {
114 | Q_D(NetworkConfiguration);
115 | ins = this;
116 | d->d.load();
117 | d->c.load();
118 | d->p.load();
119 | connect(Config::instance(), &Config::aboutToSave, [d](){
120 | d->c.save();
121 | d->p.save();
122 | });
123 | }
124 |
125 | qint64 NetworkConfiguration::cacheSize()
126 | {
127 | Q_D(NetworkConfiguration);
128 | return d->d.cacheSize();
129 | }
130 |
131 | void NetworkConfiguration::clear()
132 | {
133 | Q_D(NetworkConfiguration);
134 | d->d.clear();
135 | d->c.clear();
136 | }
137 |
138 | void NetworkConfiguration::setManager(QNetworkAccessManager *manager)
139 | {
140 | Q_D(NetworkConfiguration);
141 | manager->setCache(&d->d);
142 | d->d.setParent(nullptr);
143 | manager->setCookieJar(&d->c);
144 | d->c.setParent(nullptr);
145 | }
146 |
--------------------------------------------------------------------------------
/src/Access/NetworkConfiguration.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class NetworkConfigurationPrivate;
6 |
7 | class NetworkConfiguration :public QObject
8 | {
9 | private:
10 | static NetworkConfiguration *ins;
11 | QScopedPointer const d_ptr;
12 | Q_DECLARE_PRIVATE(NetworkConfiguration);
13 |
14 | explicit NetworkConfiguration(QObject *parent = 0);
15 |
16 | public:
17 | static NetworkConfiguration *instance();
18 | qint64 cacheSize();
19 | void clear();
20 | void setManager(QNetworkAccessManager *manager);
21 | };
22 |
--------------------------------------------------------------------------------
/src/Access/Parse.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "Parse.h"
3 | #include
4 | #include
5 |
6 | namespace
7 | {
8 | class FutureRecord : public Parse::ResultDelegate::Record
9 | {
10 | public:
11 | QFuture> data;
12 |
13 | explicit FutureRecord(const QFuture> &data) :
14 | data(data)
15 | {
16 | }
17 |
18 | virtual QVector get() override
19 | {
20 | return data.result();
21 | }
22 | };
23 |
24 | class VectorRecord : public Parse::ResultDelegate::Record
25 | {
26 | public:
27 | QVector data;
28 |
29 | explicit VectorRecord(const QVector &data) :
30 | data(data)
31 | {
32 | }
33 |
34 | virtual QVector get() override
35 | {
36 | return data;
37 | }
38 | };
39 | }
40 |
41 | Parse::ResultDelegate Parse::parseComment(const QByteArray &data, Utils::Site site)
42 | {
43 | switch (site) {
44 | case Utils::Bilibili:
45 | case Utils::TuCao:
46 | {
47 | auto xml = QSharedPointer::create(Utils::decodeTxt(data));
48 | QVector items = xml->splitRef(" &args = c.splitRef(',');
114 | Comment comment;
115 | if (args.size() > 5) {
116 | comment.time = args[0].toDouble() * 1000 + 0.5;
117 | comment.date = args[5].toInt();
118 | comment.mode = args[2].toInt();
119 | comment.font = args[3].toInt();
120 | comment.color = args[1].toInt();
121 | comment.sender = args[4].toString();
122 | comment.string = m;
123 | }
124 | return comment;
125 | },
126 | [](QVector &list, const Comment &comment) {
127 | if (!comment.isEmpty()) {
128 | list.append(comment);
129 | }
130 | }
131 | );
132 | return ResultDelegate(new FutureRecord(future));
133 | }
134 | case Utils::AcfunLocalizer:
135 | {
136 | QString xml = Utils::decodeTxt(data);
137 | QVector items = xml.splitRef(" list;
143 | list.reserve(items.size());
144 | for (const QStringRef &item : items){
145 | const QVector &args = item.left(item.indexOf("\"")).split(',');
146 | if (args.size() < 6){
147 | continue;
148 | }
149 | Comment comment;
150 | comment.time = args[0].toDouble() * 1000 + 0.5;
151 | comment.date = args[5].toInt();
152 | comment.mode = 1;
153 | comment.font = 25;
154 | comment.color = args[2].toInt();
155 | comment.sender = args[4].toString();
156 | int sta = item.indexOf("", sta) - sta;
158 | comment.string = Utils::decodeXml(item.mid(sta, len), true);
159 | list.append(comment);
160 | }
161 | return ResultDelegate(new VectorRecord(list));
162 | }
163 | case Utils::Niconico:
164 | {
165 | QVector items = Utils::decodeTxt(data).splitRef(" list;
171 | list.reserve(items.size());
172 | for (const QStringRef &item : items){
173 | Comment comment;
174 | QString key, val;
175 | /* 0 wait for key
176 | * 1 wait for left quot
177 | * 2 wait for value
178 | * 3 wait for comment
179 | * 4 finsihed */
180 | int state = 0;
181 | QMap args;
182 | for (const QChar &c : item){
183 | switch (state){
184 | case 0:
185 | if (c == '='){
186 | state = 1;
187 | }
188 | else if (c == '>'){
189 | state = 3;
190 | }
191 | else if (c != ' '){
192 | key.append(c);
193 | }
194 | break;
195 | case 1:
196 | if (c == '\"'){
197 | state = 2;
198 | }
199 | break;
200 | case 2:
201 | if (c == '\"'){
202 | state = 0;
203 | args.insert(key, val);
204 | key = val = QString();
205 | }
206 | else{
207 | val.append(c);
208 | }
209 | break;
210 | case 3:
211 | if (c == '<'){
212 | state = 4;
213 | }
214 | else{
215 | comment.string.append(c);
216 | }
217 | break;
218 | }
219 | }
220 | if (state != 4){
221 | continue;
222 | }
223 | comment.time = args["vpos"].toLongLong() * 10;
224 | comment.date = args["date"].toLongLong();
225 | QStringList ctrl = args["mail"].split(' ', QString::SkipEmptyParts);
226 | comment.mode = ctrl.contains("shita") ? 4 : (ctrl.contains("ue") ? 5 : 1);
227 | comment.font = ctrl.contains("small") ? 15 : (ctrl.contains("big") ? 36 : 25);
228 | comment.color = 0xFFFFFF;
229 | for (const QString &name : ctrl){
230 | QColor color(name);
231 | if (color.isValid()){
232 | comment.color = color.rgb();
233 | break;
234 | }
235 | }
236 | comment.sender = args["user_id"];
237 | list.append(comment);
238 | }
239 | return ResultDelegate(new VectorRecord(list));
240 | }
241 | case Utils::ASS:
242 | {
243 | QString xml = Utils::decodeTxt(data);
244 | int pos = 0, len;
245 | pos = xml.indexOf("PlayResY:") + 9;
246 | len = xml.indexOf('\n', pos) + 1 - pos;
247 | int vertical = xml.midRef(pos, len).trimmed().toInt();
248 | QVector ref;
249 | pos = xml.indexOf("Format:", pos) + 7;
250 | len = xml.indexOf('\n', pos) + 1 - pos;
251 | ref = xml.midRef(pos, len).split(',');
252 | int name = -1, size = -1;
253 | for (int i = 0; i < ref.size(); ++i){
254 | const QStringRef &item = ref[i].trimmed();
255 | if (item == "Name"){
256 | name = i;
257 | }
258 | else if (item == "Fontsize"){
259 | size = i;
260 | }
261 | }
262 | if (name < 0 || size < 0){
263 | return ResultDelegate();
264 | }
265 | pos += len;
266 | len = xml.indexOf("Format:", pos) - pos;
267 | ref = xml.midRef(pos, len).split("Style:", QString::SkipEmptyParts);
268 | QMap style;
269 | for (const QStringRef &item : ref){
270 | const auto &args = item.split(',');
271 | style[args[name].trimmed().toString()] = args[size].toInt();
272 | }
273 | pos += len;
274 | pos = xml.indexOf("Format:", pos) + 7;
275 | len = xml.indexOf("\n", pos) + 1 - pos;
276 | ref = xml.midRef(pos, len).split(',');
277 | int text = -1, font = -1, time = -1;
278 | for (int i = 0; i < ref.size(); ++i){
279 | const QStringRef &item = ref[i].trimmed();
280 | if (item == "Text"){
281 | text = i;
282 | }
283 | else if (item == "Start"){
284 | time = i;
285 | }
286 | else if (item == "Style"){
287 | font = i;
288 | }
289 | }
290 | if (text < 0 || font < 0 || time < 0){
291 | return ResultDelegate();
292 | }
293 | qint64 dat = QDateTime::currentDateTime().toTime_t();
294 | pos += len;
295 | ref = xml.midRef(pos).split("Dialogue:",QString::SkipEmptyParts);
296 | QVector list;
297 | list.reserve(ref.size());
298 | for (const QStringRef &item : ref){
299 | const auto &args = item.split(',');
300 | Comment comment;
301 | comment.date = dat;
302 | QString t;
303 | t = args[time].trimmed().toString();
304 | comment.time = 1000 * Utils::evaluate(t);
305 | t = args[font].trimmed().toString();
306 | comment.font = style[t];
307 | t = item.mid(args[text].position()-item.position()).trimmed().toString();
308 | int split = t.indexOf("}") + 1;
309 | comment.string = t.midRef(split).trimmed().toString();
310 | const auto &m = t.midRef(1, split - 2).split('\\', QString::SkipEmptyParts);
311 | for (const QStringRef &i : m){
312 | if (i.startsWith("fs")){
313 | comment.font = i.mid(2).toInt();
314 | }
315 | else if (i.startsWith("c&H", Qt::CaseSensitive)){
316 | comment.color = i.mid(3).toInt(nullptr, 16);
317 | }
318 | else if (i.startsWith("c")){
319 | comment.color = i.mid(1).toInt();
320 | }
321 | else if (i.startsWith("move")){
322 | const auto &p = i.mid(5, i.length() - 6).split(',');
323 | if (p.size() == 4){
324 | comment.mode = p[0].toInt() > p[2].toInt() ? 1 : 6;
325 | }
326 | }
327 | else if (i.startsWith("pos")){
328 | const auto &p = i.mid(4, i.length() - 5).split(',');
329 | if (p.size() == 2){
330 | comment.mode = p[1].toInt() > vertical / 2 ? 4 : 5;
331 | }
332 | }
333 | else{
334 | comment.mode = 0;
335 | break;
336 | }
337 | }
338 | if (comment.mode != 0 && comment.color != 0){
339 | list.append(comment);
340 | }
341 | }
342 | return ResultDelegate(new VectorRecord(list));
343 | }
344 | default:
345 | return ResultDelegate();
346 | }
347 | }
348 |
--------------------------------------------------------------------------------
/src/Access/Parse.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include "../Utils.h"
5 |
6 | namespace Parse
7 | {
8 | class ResultDelegate
9 | {
10 | public:
11 | class Record
12 | {
13 | public:
14 | virtual ~Record() = default;
15 | virtual QVector get() = 0;
16 | };
17 |
18 | QSharedPointer data;
19 |
20 | ResultDelegate() :
21 | data(nullptr)
22 | {
23 | }
24 |
25 | explicit ResultDelegate(Record *data) :
26 | data(data)
27 | {
28 | }
29 |
30 | operator QVector()
31 | {
32 | return data == nullptr ? QVector() : data->get();
33 | }
34 | };
35 |
36 | ResultDelegate parseComment(const QByteArray &data, Utils::Site site);
37 | }
38 |
--------------------------------------------------------------------------------
/src/Access/Post.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 "Common.h"
29 | #include "Post.h"
30 | #include "AccessPrivate.h"
31 | #include "../Model/Danmaku.h"
32 |
33 | Post *Post::ins = nullptr;
34 |
35 | Post *Post::instance()
36 | {
37 | return ins ? ins : new Post(qApp);
38 | }
39 |
40 | class PostPrivate : public AccessPrivate
41 | {
42 | public:
43 | explicit PostPrivate(Post *post):
44 | AccessPrivate(post)
45 | {
46 | }
47 |
48 | virtual void onShift() override
49 | {
50 | Q_Q(Post);
51 | Post::Task &task = queue.head();
52 | emit q->stateChanged(task.state);
53 | remain.insert(task.data.isEmpty() ? manager.get(task.request) : manager.post(task.request, task.data));
54 | }
55 | };
56 |
57 | Post::Post(QObject *parent) : QObject(parent), d_ptr(new PostPrivate(this))
58 | {
59 | Q_D(Post);
60 | ins = this;
61 | setObjectName("Post");
62 |
63 | auto avProcess = [this](QNetworkReply *reply){
64 | Q_D(Post);
65 | Task &task = d->queue.head();
66 | switch (task.state){
67 | case None:{
68 | QString api("http://interface.%1/dmpost");
69 | api = api.arg(Utils::customUrl(Utils::Bilibili));
70 | task.request.setUrl(api);
71 | task.request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
72 | const Comment &c = task.comment;
73 | QUrlQuery params;
74 | params.addQueryItem("cid", QFileInfo(task.target->source).baseName());
75 | params.addQueryItem("date", QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"));
76 | params.addQueryItem("pool", "0");
77 | params.addQueryItem("playTime", QString::number(c.time / 1000.0, 'f', 4));
78 | params.addQueryItem("color", QString::number(c.color));
79 | params.addQueryItem("fontsize", QString::number(c.font));
80 | params.addQueryItem("message", c.string);
81 | params.addQueryItem("rnd", QString::number(qrand()));
82 | params.addQueryItem("mode", QString::number(c.mode));
83 | task.data = params.query(QUrl::FullyEncoded).toUtf8();
84 | task.state = Code;
85 | forward();
86 | break;
87 | }
88 | case Code:{
89 | int code = QString(reply->readAll()).toInt();
90 | emit stateChanged(task.state = code > 0 ? None : code);
91 | dequeue();
92 | break;
93 | }
94 | }
95 | };
96 | auto avRegular = [](QString code){
97 | static QRegularExpression r("a(v(\\d+([#_])?(\\d+)?)?)?");
98 | r.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
99 | return r.match(code).capturedLength() == code.length();
100 | };
101 | d->pool.append({ avRegular, 0, avProcess });
102 |
103 | connect(this, &Post::stateChanged, [this](int code){
104 | switch (code){
105 | case None:
106 | case Code:
107 | break;
108 | default:
109 | {
110 | Q_D(Post);
111 | if (!d->tryNext()){
112 | emit errorOccured(code);
113 | }
114 | break;
115 | }
116 | }
117 | });
118 | }
119 |
120 | Post::~Post()
121 | {
122 | delete d_ptr;
123 | }
124 |
125 | void Post::addProc(const Post::Proc *proc)
126 | {
127 | Q_D(Post);
128 | d->addProc(proc);
129 | }
130 |
131 | const Post::Proc *Post::getProc(QString code)
132 | {
133 | Q_D(Post);
134 | return d->getProc(code);
135 | }
136 |
137 | bool Post::canPost(QString code)
138 | {
139 | return getProc(code) != nullptr;
140 | }
141 |
142 | void Post::postComment(const Record *r, const Comment *c)
143 | {
144 | Task task;
145 | task.code = r->access;
146 | task.comment = *c;
147 | task.comment.time -= r->delay;
148 | task.target = r;
149 | task.processer = getProc(task.code);
150 | enqueue(task);
151 | }
152 |
153 | void Post::forward()
154 | {
155 | Q_D(Post);
156 | d->forward();
157 | }
158 |
159 | void Post::dequeue()
160 | {
161 | Q_D(Post);
162 | d->dequeue();
163 | }
164 |
165 | bool Post::enqueue(const Post::Task &task)
166 | {
167 | Q_D(Post);
168 | return d->enqueue(task);
169 | }
170 |
171 | Post::Task *Post::getHead()
172 | {
173 | Q_D(Post);
174 | return d->getHead();
175 | }
176 |
--------------------------------------------------------------------------------
/src/Access/Post.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 | #pragma once
29 |
30 | #include "../Utils.h"
31 | #include
32 | #include
33 | #include
34 |
35 | class PostPrivate;
36 |
37 | class Post : public QObject
38 | {
39 | Q_OBJECT
40 | public:
41 | enum State
42 | {
43 | None,
44 | Code
45 | };
46 |
47 | struct Proc
48 | {
49 | std::function regular;
50 | int priority;
51 | std::function process;
52 | };
53 |
54 | struct Task
55 | {
56 | QString code;
57 | Comment comment;
58 | QNetworkRequest request;
59 | QByteArray data;
60 | int state;
61 | const Record *target;
62 | const Proc *processer;
63 | Task() :state(0), processer(nullptr){}
64 | };
65 |
66 | static Post *instance();
67 | ~Post();
68 |
69 | private:
70 | static Post *ins;
71 | PostPrivate *const d_ptr;
72 | Q_DECLARE_PRIVATE(Post);
73 |
74 | explicit Post(QObject *parent);
75 |
76 | signals:
77 | void stateChanged(int code);
78 | void errorOccured(int code);
79 |
80 | public slots:
81 | void addProc(const Post::Proc *proc);
82 | const Post::Proc *getProc(QString code);
83 |
84 | bool canPost(QString code);
85 | void postComment(const Record *, const Comment *);
86 |
87 | void forward();
88 | void dequeue();
89 | bool enqueue(const Post::Task &);
90 | Post::Task *getHead();
91 | };
92 |
--------------------------------------------------------------------------------
/src/Access/Seek.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 Lysine.
4 | *
5 | * Filename: Seek.h
6 | * Time: 2015/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 | #pragma once
28 |
29 | #include
30 | #include
31 | #include
32 | #include
33 |
34 | class SeekPrivate;
35 |
36 | class Seek : public QObject
37 | {
38 | Q_OBJECT
39 | public:
40 | enum State
41 | {
42 | None,
43 | List,
44 | More,
45 | Data
46 | };
47 |
48 | struct Proc
49 | {
50 | QString name;
51 | QStringList sort;
52 | inline bool regular(QString &code) const { return code == name; }
53 | int priority;
54 | std::function process;
55 | };
56 |
57 | struct Task
58 | {
59 | QString code;
60 | QString text;
61 | int sort;
62 | QPair page;
63 | QSize cover;
64 | QStandardItemModel *model;
65 | int state;
66 | QNetworkRequest request;
67 | const Proc *processer;
68 | Task() :sort(0), state(None), processer(nullptr){}
69 | };
70 |
71 | static Seek *instance();
72 | ~Seek();
73 |
74 | private:
75 | static Seek *ins;
76 | SeekPrivate *const d_ptr;
77 | Q_DECLARE_PRIVATE(Seek);
78 |
79 | explicit Seek(QObject *parent);
80 |
81 | signals:
82 | void stateChanged(int code);
83 | void errorOccured(int code);
84 |
85 | public slots:
86 | void addProc(const Seek::Proc *proc);
87 | const Seek::Proc *getProc(QString name);
88 |
89 | QStringList modules();
90 | void dequeue();
91 | bool enqueue(const Seek::Task &);
92 | Seek::Task *getHead();
93 | void forward();
94 | };
95 |
--------------------------------------------------------------------------------
/src/Access/Sign.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 Lysine.
4 | *
5 | * Filename: Sign.cpp
6 | * Time: 2015/11/14
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 "Common.h"
28 | #include "Sign.h"
29 | #include "AccessPrivate.h"
30 | #include "../Utils.h"
31 |
32 | extern "C"
33 | {
34 | #include
35 | #include
36 | }
37 |
38 | Sign *Sign::ins = nullptr;
39 |
40 | Sign *Sign::instance()
41 | {
42 | return ins ? ins : new Sign(qApp);
43 | }
44 |
45 | class SignPrivate : public AccessPrivate
46 | {
47 | public:
48 | explicit SignPrivate(Sign *sign):
49 | AccessPrivate(sign)
50 | {
51 | }
52 |
53 | virtual void onShift() override
54 | {
55 | Q_Q(Sign);
56 | Sign::Task &task = queue.head();
57 | emit q->stateChanged(task.state);
58 | remain.insert(task.data.isEmpty() ? manager.get(task.request) : manager.post(task.request, task.data));
59 | }
60 | };
61 |
62 | Sign::Sign(QObject *parent) : QObject(parent), d_ptr(new SignPrivate(this))
63 | {
64 | Q_D(Sign);
65 | ins = this;
66 | setObjectName("Sign");
67 |
68 | auto biCaptcha = [this](){
69 | Task &task = *getHead();
70 | QString url("https://passport.%1/captcha");
71 | url = url.arg(Utils::customUrl(Utils::Bilibili));
72 | task.request.setUrl(url);
73 | forward(Code);
74 | };
75 |
76 | auto biProcess = [this, biCaptcha](QNetworkReply *reply){
77 | Task &task = *getHead();
78 | switch (task.state){
79 | case None:
80 | {
81 | QString url("http://member.%1/main.html");
82 | url = url.arg(Utils::customUrl(Utils::Bilibili));
83 | task.request.setUrl(url);
84 | forward(Test);
85 | break;
86 | }
87 | case Test:
88 | {
89 | QRegularExpressionMatch m = QRegularExpression("(?<=\\>).*(?=\\<\\/h3\\>)").match(reply->readAll());
90 | if (m.hasMatch()){
91 | task.username = m.captured();
92 | task.logged = true;
93 | emit stateChanged(task.state = Wait);
94 | }
95 | else{
96 | biCaptcha();
97 | }
98 | break;
99 | }
100 | case Code:
101 | {
102 | task.data = reply->readAll();
103 | emit stateChanged(task.state = Wait);
104 | task.data.clear();
105 | break;
106 | }
107 | case Wait:
108 | {
109 | QString url = "https://passport.%1/login?act=%2";
110 | url = url.arg(Utils::customUrl(Utils::Bilibili));
111 | if (task.logged){
112 | task.request.setUrl(url.arg("exit"));
113 | task.state = Data;
114 | }
115 | else{
116 | task.request.setUrl(url.arg("getkey"));
117 | task.state = Salt;
118 | }
119 | forward();
120 | break;
121 | }
122 | case Salt:
123 | {
124 | //RSA Encrypt
125 | try{
126 | QJsonObject key = QJsonDocument::fromJson(reply->readAll()).object();
127 | QByteArray pub = key["key"].toString().toUtf8();
128 | BIO *bio = BIO_new_mem_buf(pub.data(), pub.length());
129 | if (!bio){
130 | throw "failed to generate BIO";
131 | }
132 | RSA *rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL);
133 | if (!rsa){
134 | throw "failed to generate RSA_PUBKEY";
135 | }
136 | task.password.prepend(key["hash"].toString());
137 | QByteArray dat = task.password.toUtf8();
138 | QByteArray buf;
139 | buf.resize(1024);
140 | int len = RSA_public_encrypt(dat.length(), (const unsigned char *)dat.data(), (unsigned char*)buf.data(), rsa, RSA_PKCS1_PADDING);
141 | if (len == -1){
142 | throw "failed to encrypt using RSA";
143 | }
144 | buf.resize(len);
145 | task.password = buf.toBase64();
146 | }
147 | catch (...)
148 | {
149 | task.error = tr("An error occurred in RSA encryption.");
150 | biCaptcha();
151 | }
152 |
153 | QString url("https://passport.%1/login/dologin");
154 | url = url.arg(Utils::customUrl(Utils::Bilibili));
155 | task.request.setUrl(url);
156 | task.request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
157 | QUrlQuery params;
158 | params.addQueryItem("act", "login");
159 | params.addQueryItem("userid", task.username);
160 | params.addQueryItem("pwd", task.password);
161 | params.addQueryItem("vdcode", task.captcha.toUpper());
162 | params.addQueryItem("keeptime", "604800");
163 | task.data = params.query(QUrl::FullyEncoded).toUtf8();
164 | forward(Data);
165 | task.data.clear();
166 | break;
167 | }
168 | case Data:
169 | {
170 | if (task.logged){
171 | task.logged = false;
172 | }
173 | else{
174 | QByteArray data = reply->readAll();
175 | QString page = QTextCodec::codecForHtml(data, QTextCodec::codecForName("UTF-8"))->toUnicode(data);
176 | int sta = page.indexOf("document.write(\"");
177 | if (sta < 0){
178 | task.logged = true;
179 | }
180 | else{
181 | sta += 16;
182 | task.error = page.mid(sta, page.indexOf("\"", sta) - sta);
183 | }
184 | }
185 | if (task.logged){
186 | emit stateChanged(task.state = Wait);
187 | }
188 | else{
189 | biCaptcha();
190 | }
191 | }
192 | }
193 | };
194 | d->pool.append({ "Bilibili", 0, biProcess });
195 |
196 | connect(this, &Sign::stateChanged, [this](int code){
197 | switch (code){
198 | case None:
199 | case Test:
200 | case Code:
201 | case Wait:
202 | case Salt:
203 | case Data:
204 | break;
205 | default:
206 | {
207 | Q_D(Sign);
208 | if (!d->tryNext()){
209 | emit errorOccured(code);
210 | }
211 | break;
212 | }
213 | }
214 | });
215 | }
216 |
217 | Sign::~Sign()
218 | {
219 | delete d_ptr;
220 | }
221 |
222 | void Sign::addProc(const Sign::Proc *proc)
223 | {
224 | Q_D(Sign);
225 | d->addProc(proc);
226 | }
227 |
228 | const Sign::Proc *Sign::getProc(QString name)
229 | {
230 | Q_D(Sign);
231 | return d->getProc(name);
232 | }
233 |
234 | QStringList Sign::modules()
235 | {
236 | Q_D(Sign);
237 | QStringList list;
238 | for (const Proc &iter : d->pool){
239 | list << iter.name;
240 | }
241 | return list;
242 | }
243 |
244 | void Sign::forward()
245 | {
246 | Q_D(Sign);
247 | d->forward();
248 | }
249 |
250 | void Sign::forward(int state)
251 | {
252 | Q_D(Sign);
253 | d->queue.head().state = state;
254 | d->forward();
255 | }
256 |
257 | void Sign::dequeue()
258 | {
259 | Q_D(Sign);
260 | d->dequeue();
261 | }
262 |
263 | bool Sign::enqueue(QString site)
264 | {
265 | Task task;
266 | task.code = site;
267 | task.processer = getProc(site);
268 | if (task.processer == nullptr){
269 | return false;
270 | }
271 |
272 | Q_D(Sign);
273 | if (d->queue.size()){
274 | d->dequeue();
275 | }
276 |
277 | return d->enqueue(task);
278 | }
279 |
280 | Sign::Task *Sign::getHead()
281 | {
282 | Q_D(Sign);
283 | return d->getHead();
284 | }
285 |
--------------------------------------------------------------------------------
/src/Access/Sign.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 Lysine.
4 | *
5 | * Filename: Sign.h
6 | * Time: 2015/11/14
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
28 | #include
29 | #include
30 |
31 | class SignPrivate;
32 |
33 | class Sign : public QObject
34 | {
35 | Q_OBJECT
36 | public:
37 | enum State
38 | {
39 | None,
40 | Test,
41 | Code,
42 | Wait,
43 | Salt,
44 | Data
45 | };
46 |
47 | struct Proc
48 | {
49 | QString name;
50 | inline bool regular(QString &code) const { return code == name; }
51 | int priority;
52 | std::function process;
53 | };
54 |
55 | struct Task
56 | {
57 | QString username;
58 | QString password;
59 | QString captcha;
60 |
61 | QString code;
62 | QNetworkRequest request;
63 | int state;
64 | const Proc *processer;
65 | QByteArray data;
66 | bool logged;
67 | QString error;
68 |
69 | Task() :state(None), processer(nullptr), logged(false){}
70 | };
71 |
72 | static Sign *instance();
73 | ~Sign();
74 |
75 | private:
76 | static Sign *ins;
77 | SignPrivate *const d_ptr;
78 | Q_DECLARE_PRIVATE(Sign);
79 |
80 | explicit Sign(QObject *parent);
81 |
82 | signals:
83 | void stateChanged(int state);
84 | void errorOccured(int state);
85 |
86 | public slots:
87 | void addProc(const Sign::Proc *proc);
88 | const Sign::Proc *getProc(QString name);
89 | QStringList modules();
90 |
91 | void forward();
92 | void forward(int state);
93 | void dequeue();
94 | bool enqueue(QString site);
95 | Sign::Task *getHead();
96 | };
--------------------------------------------------------------------------------
/src/Common.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
--------------------------------------------------------------------------------
/src/Common.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include "Config.h"
8 | #include "Local.h"
9 | #include "Utils.h"
--------------------------------------------------------------------------------
/src/Config.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 Lysine.
4 | *
5 | * Filename: Config.cpp
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 | #include "Common.h"
28 | #include "Config.h"
29 |
30 | Config *Config::ins = nullptr;
31 |
32 | QReadWriteLock Config::lock;
33 |
34 | Config *Config::instance()
35 | {
36 | return ins ? ins : new Config(qApp);
37 | }
38 |
39 | Config::Config(QObject *parent) :
40 | QObject(parent)
41 | {
42 | ins = this;
43 | }
44 |
45 | QJsonObject Config::config;
46 |
47 | void Config::load()
48 | {
49 | QFile conf("./Config.txt");
50 | if (conf.open(QIODevice::ReadOnly | QIODevice::Text)){
51 | config = QJsonDocument::fromJson(conf.readAll()).object();
52 | conf.close();
53 | }
54 | }
55 |
56 | void Config::save()
57 | {
58 | emit instance()->aboutToSave();
59 | QFile conf("./Config.txt");
60 | conf.open(QIODevice::WriteOnly | QIODevice::Text);
61 | conf.write(QJsonDocument(config).toJson());
62 | conf.close();
63 | }
64 |
65 | void Config::setVariant(QString key, QVariant val)
66 | {
67 | setValue(key, val);
68 | }
69 |
70 | QVariant Config::getVariant(QString key, QVariant val)
71 | {
72 | return getValue(key, val);
73 | }
--------------------------------------------------------------------------------
/src/Config.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 | #pragma once
28 |
29 | #include
30 | #include
31 |
32 | namespace{
33 | template
34 | TypeName fromJsonValue(QJsonValue v)
35 | {
36 | QVariant t = v.toVariant();
37 | if (!t.canConvert()){
38 | throw std::runtime_error("type missmatch");
39 | }
40 | return t.value();
41 | }
42 |
43 | template<>
44 | QVariant fromJsonValue(QJsonValue v)
45 | {
46 | return v.toVariant();
47 | }
48 |
49 | template<>
50 | QJsonArray fromJsonValue(QJsonValue v)
51 | {
52 | if (QJsonValue::Array != v.type()){
53 | throw std::runtime_error("type missmatch");
54 | }
55 | return v.toArray();
56 | }
57 |
58 | template<>
59 | QJsonObject fromJsonValue(QJsonValue v)
60 | {
61 | if (QJsonValue::Object != v.type()){
62 | throw std::runtime_error("type missmatch");
63 | }
64 | return v.toObject();
65 | }
66 |
67 | template
68 | QJsonValue toJsonValue(TypeName v)
69 | {
70 | return QJsonValue(v);
71 | }
72 |
73 | template<>
74 | QJsonValue toJsonValue(QVariant v)
75 | {
76 | return QJsonValue::fromVariant(v);
77 | }
78 | }
79 |
80 | class Config :public QObject
81 | {
82 | Q_OBJECT
83 | public:
84 | explicit Config(QObject *parent = 0);
85 |
86 | template
87 | static T getValue(QString key, T def = T())
88 | {
89 | QStringList tree = key.split('/', QString::SkipEmptyParts);
90 | QString last = tree.takeLast();
91 | lock.lockForRead();
92 | QJsonObject cur = config;
93 | lock.unlock();
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 | lock.lockForWrite();
114 | config = cur;
115 | lock.unlock();
116 | }
117 | return def;
118 | }
119 |
120 | template
121 | static void setValue(QString key, T set)
122 | {
123 | QStringList tree = key.split('/', QString::SkipEmptyParts);
124 | QString last = tree.takeLast();
125 | QJsonObject cur = config;
126 | QList path;
127 | for (const QString &k : tree){
128 | path.append(cur);
129 | cur = cur.value(k).toObject();
130 | }
131 | cur[last] = toJsonValue(set);
132 | while (!path.isEmpty()){
133 | QJsonObject pre = path.takeLast();
134 | pre[tree.takeLast()] = cur;
135 | cur = pre;
136 | }
137 | lock.lockForWrite();
138 | config = cur;
139 | lock.unlock();
140 | }
141 |
142 | static Config *instance();
143 |
144 | private:
145 | static Config *ins;
146 | static QJsonObject config;
147 | static QReadWriteLock lock;
148 |
149 | signals:
150 | void aboutToSave();
151 |
152 | public slots:
153 | static void load();
154 | static void save();
155 | void setVariant(QString key, QVariant val);
156 | QVariant getVariant(QString key, QVariant val = QVariant());
157 | };
158 |
--------------------------------------------------------------------------------
/src/Graphic/Graphic.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 "Common.h"
28 | #include "Graphic.h"
29 | #include "../Config.h"
30 | #include "../Render/ARender.h"
31 | #include "Mode1.h"
32 | #include "Mode4.h"
33 | #include "Mode5.h"
34 | #include "Mode6.h"
35 | #include "Mode7.h"
36 |
37 | Graphic *Graphic::create(const Comment &comment)
38 | {
39 | switch (comment.mode){
40 | case 1:
41 | return new Mode1(comment);
42 | case 4:
43 | return new Mode4(comment);
44 | case 5:
45 | return new Mode5(comment);
46 | case 6:
47 | return new Mode6(comment);
48 | case 7:
49 | return new Mode7(comment);
50 | default:
51 | throw format_unrecognized();
52 | }
53 | }
54 |
55 | void Graphic::setIndex()
56 | {
57 | static quint64 globalIndex;
58 | index = globalIndex++;
59 | }
60 |
--------------------------------------------------------------------------------
/src/Graphic/Graphic.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 | #pragma once
28 |
29 | #include
30 | #include
31 | #include "../Utils.h"
32 | #include
33 |
34 | class Graphic
35 | {
36 | public:
37 | class format_unrecognized :public std::runtime_error
38 | {
39 | public:
40 | format_unrecognized() :
41 | runtime_error("format unrecognized")
42 | {
43 | }
44 | };
45 |
46 | class args_prasing_error :public std::runtime_error
47 | {
48 | public:
49 | args_prasing_error() :
50 | runtime_error("args prasing error")
51 | {
52 | }
53 | };
54 |
55 | virtual QList locate() = 0;
56 | virtual bool move(double time) = 0;
57 | virtual void draw(QPainter *painter) = 0;
58 | virtual uint intersects(Graphic *other) = 0;
59 | virtual bool stay(){ return false; }
60 | virtual QRectF ¤tRect(){ return rect; }
61 | virtual ~Graphic() = default;
62 |
63 | inline int getMode()
64 | {
65 | return source ? source->mode : 0;
66 | }
67 |
68 | inline bool isEnabled()
69 | {
70 | return enabled;
71 | }
72 |
73 | inline void setEnabled(bool enabled)
74 | {
75 | this->enabled = enabled;
76 | }
77 |
78 | inline quint64 getIndex()
79 | {
80 | return index;
81 | }
82 |
83 | void setIndex();
84 |
85 | inline const Comment *getSource()
86 | {
87 | return source;
88 | }
89 |
90 | inline void setSource(const Comment *source)
91 | {
92 | this->source = source;
93 | }
94 |
95 | static Graphic *create(const Comment &comment);
96 |
97 | protected:
98 | bool enabled;
99 | QRectF rect;
100 | quint64 index;
101 | const Comment *source;
102 | Graphic() :enabled(true), source(nullptr){}
103 | };
104 |
--------------------------------------------------------------------------------
/src/Graphic/GraphicPrivate.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "GraphicPrivate.h"
3 |
4 | QFont GraphicPrivate::getFont(int pixelSize, QString family)
5 | {
6 | QFont font;
7 | font.setBold(Config::getValue("/Danmaku/Effect", 5) % 2);
8 | font.setFamily(family);
9 | font.setPixelSize(pixelSize);
10 | return font;
11 | }
12 |
13 | QSize GraphicPrivate::getSize(QString string, QFont font)
14 | {
15 | QStringList lines = string.split('\n');
16 | for (QString &line : lines){
17 | QChar h = ' ', f(0x3000);
18 | int hc = line.count(h), fc = line.count(f);
19 | line.remove(h).prepend(QString(hc, h));
20 | line.remove(f).prepend(QString(fc, f));
21 | }
22 | return QFontMetrics(font).size(0, lines.join('\n')) + QSize(4, 4);
23 | }
24 |
25 | QSizeF GraphicPrivate::getPlayer(qint64 date)
26 | {
27 | return date <= 1384099200 ? QSizeF(545, 388) : QSizeF(862, 568);
28 | }
29 |
30 | double GraphicPrivate::getScale(int mode, qint64 date, QSize size)
31 | {
32 | int m = Config::getValue("/Danmaku/Scale/Fitted", 0x1);
33 | if (mode == 7 && (m & 0x1) == 0){
34 | return 0;
35 | }
36 | if (mode <= 6 && (m & 0x2) == 0){
37 | return Config::getValue("/Danmaku/Scale/Factor", 1.0);
38 | }
39 | QSizeF player = getPlayer(date);
40 | return qMin(size.width() / player.width(), size.height() / player.height());
41 | }
42 |
43 | void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius,
44 | bool quality, bool alphaOnly, int transposed);
45 |
46 | QImage GraphicPrivate::getCache(QString string,
47 | int color,
48 | QFont font,
49 | QSize size,
50 | bool frame,
51 | int effect,
52 | int opacity)
53 | {
54 | QPainter painter;
55 | QColor base(color), edge = qGray(color) < 30 ? Qt::white : Qt::black;
56 | QImage src(size, QImage::Format_ARGB32_Premultiplied);
57 | src.fill(Qt::transparent);
58 | painter.begin(&src);
59 | painter.setPen(base);
60 | painter.setFont(font);
61 | painter.drawText(src.rect().adjusted(2, 2, -2, -2), string);
62 | painter.end();
63 | QImage fst(size, QImage::Format_ARGB32_Premultiplied);
64 | fst.fill(Qt::transparent);
65 | if (effect == 2){
66 | QImage blr = src;
67 | painter.begin(&fst);
68 | painter.save();
69 | qt_blurImage(&painter, blr, 4, false, true, 0);
70 | painter.restore();
71 | painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
72 | painter.fillRect(src.rect(), edge);
73 | painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
74 | painter.drawImage(0, 0, src);
75 | painter.end();
76 | QImage sec(size, QImage::Format_ARGB32_Premultiplied);
77 | sec.fill(Qt::transparent);
78 | painter.begin(&sec);
79 | blr = fst;
80 | painter.save();
81 | qt_blurImage(&painter, blr, 4, false, true, 0);
82 | painter.restore();
83 | painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
84 | painter.fillRect(sec.rect(), edge);
85 | painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
86 | painter.drawImage(0, 0, fst);
87 | painter.end();
88 | fst = sec;
89 | }
90 | else{
91 | QImage edg = src;
92 | painter.begin(&edg);
93 | painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
94 | painter.fillRect(edg.rect(), edge);
95 | painter.end();
96 | painter.begin(&fst);
97 | switch (effect){
98 | case 0:
99 | painter.drawImage(+1, 0, edg);
100 | painter.drawImage(-1, 0, edg);
101 | painter.drawImage(0, +1, edg);
102 | painter.drawImage(0, -1, edg);
103 | break;
104 | case 1:
105 | painter.drawImage(1, 1, edg);
106 | break;
107 | }
108 | painter.drawImage(0, 0, src);
109 | painter.end();
110 | }
111 | if (frame){
112 | painter.begin(&fst);
113 | painter.setPen(QColor(100, 255, 255));
114 | painter.setBrush(Qt::NoBrush);
115 | painter.drawRect(fst.rect().adjusted(0, 0, -1, -1));
116 | painter.end();
117 | }
118 | if (opacity != 100){
119 | QImage sec(size, QImage::Format_ARGB32_Premultiplied);
120 | sec.fill(Qt::transparent);
121 | painter.begin(&sec);
122 | painter.setOpacity(opacity / 100.0);
123 | painter.drawImage(QPoint(0, 0), fst);
124 | painter.end();
125 | fst = sec;
126 | }
127 | return fst;
128 | }
129 |
130 | double GraphicPrivate::getOverlap(double ff, double fs, double sf, double ss)
131 | {
132 | if (sf <= ff&&ss >= fs){
133 | return fs - ff;
134 | }
135 | if (sf >= ff&&sf <= fs){
136 | return qMin(fs - sf, ss - sf);
137 | }
138 | if (ss <= fs&&ss >= ff){
139 | return qMin(ss - ff, ss - sf);
140 | }
141 | return 0;
142 | }
143 |
--------------------------------------------------------------------------------
/src/Graphic/GraphicPrivate.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include "../Config.h"
6 |
7 | namespace GraphicPrivate
8 | {
9 | QFont getFont(int pixelSize,
10 | QString family = Config::getValue("/Danmaku/Font", QFont().family()));
11 |
12 | QSize getSize(QString string,
13 | QFont font);
14 |
15 | QSizeF getPlayer(qint64 date);
16 |
17 | double getScale(int mode,
18 | qint64 date,
19 | QSize size);
20 |
21 | QImage getCache(QString string,
22 | int color,
23 | QFont font,
24 | QSize size,
25 | bool frame,
26 | int effect = Config::getValue("/Danmaku/Effect", 5) / 2,
27 | int opacity = Config::getValue("/Danmaku/Alpha", 100));
28 |
29 | double getOverlap(double ff, double fs, double sf, double ss);
30 | }
31 |
--------------------------------------------------------------------------------
/src/Graphic/Mode1.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "Mode1.h"
3 | #include "GraphicPrivate.h"
4 | #include "../Config.h"
5 |
6 | using namespace GraphicPrivate;
7 |
8 | Mode1::Mode1(const Comment &comment) :
9 | Plain(comment)
10 | {
11 | Q_ASSERT(comment.mode == 1);
12 | speed = evaluate(Config::getValue("/Danmaku/Speed", "125+%{width}/5"));
13 | }
14 |
15 | QList Mode1::locate()
16 | {
17 | QList results;
18 | if (rect.height() > 360){
19 | return results;
20 | }
21 | QSize size = ARender::instance()->getActualSize();
22 | QRectF init = rect;
23 | init.moveLeft(size.width());
24 | int end = size.height()*(Config::getValue("/Danmaku/Protect", false) ? 0.85 : 1) - rect.height();
25 | int stp = Config::getValue("/Danmaku/Grating", 10);
26 | for (int height = 0; height <= end; height += stp){
27 | init.moveTop(height);
28 | results.append(init);
29 | }
30 | return results;
31 | }
32 |
33 | bool Mode1::move(double time)
34 | {
35 | if (enabled){
36 | rect.moveLeft(rect.left() - speed * time);
37 | }
38 | return rect.right() >= 0;
39 | }
40 |
41 | uint Mode1::intersects(Graphic *other)
42 | {
43 | Q_ASSERT(other->getMode() == 1);
44 | const Mode1 &f = *static_cast(other);
45 | const Mode1 &s = *this;
46 | int h;
47 | if ((h = getOverlap(f.rect.top(), f.rect.bottom(), s.rect.top(), s.rect.bottom())) == 0){
48 | return 0;
49 | }
50 | int w = 0;
51 | if (f.rect.intersects(s.rect)){
52 | if (f.speed > s.speed){
53 | w = getOverlap(f.rect.left(), f.rect.right(), s.rect.left(), s.rect.right());
54 | }
55 | else{
56 | w = qMin(f.rect.width(), s.rect.width());
57 | }
58 | }
59 | else{
60 | double o = f.rect.right() - f.speed*s.rect.left() / s.speed;
61 | w = o > 0 ? qMin(qMin(f.rect.width(), s.rect.width()), o) : 0;
62 | }
63 | return h*w;
64 | }
65 |
--------------------------------------------------------------------------------
/src/Graphic/Mode1.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Plain.h"
4 |
5 | class Mode1 :public Plain
6 | {
7 | public:
8 | Mode1(const Comment &comment);
9 | QList locate();
10 | bool move(double time);
11 | uint intersects(Graphic *other);
12 |
13 | private:
14 | double speed;
15 | };
16 |
--------------------------------------------------------------------------------
/src/Graphic/Mode4.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "Mode4.h"
3 | #include "GraphicPrivate.h"
4 | #include "../Config.h"
5 |
6 | using namespace GraphicPrivate;
7 |
8 | Mode4::Mode4(const Comment &comment) :
9 | Plain(comment)
10 | {
11 | Q_ASSERT(comment.mode == 4);
12 | life = evaluate(Config::getValue("/Danmaku/Life", "5"));
13 | }
14 |
15 | QList Mode4::locate()
16 | {
17 | QList results;
18 | if (rect.height() > 360){
19 | return results;
20 | }
21 | QSize size = ARender::instance()->getActualSize();
22 | QRectF init = rect;
23 | init.moveCenter(QPointF(size.width() / 2.0, 0));
24 | init.moveBottom(size.height()*(Config::getValue("/Danmaku/Protect", false) ? 0.85 : 1));
25 | int stp = Config::getValue("/Danmaku/Grating", 10);
26 | for (int height = init.top(); height >= 0; height -= stp){
27 | init.moveTop(height);
28 | results.append(init);
29 | }
30 | return results;
31 | }
32 |
33 | bool Mode4::move(double time)
34 | {
35 | if (enabled){
36 | life -= time;
37 | }
38 | return life > 0;
39 | }
40 |
41 | uint Mode4::intersects(Graphic *other)
42 | {
43 | Q_ASSERT(other->getMode() == 4);
44 | const Mode4 &f = *this;
45 | const Mode4 &s = *static_cast(other);
46 | return getOverlap(f.rect.top(), f.rect.bottom(), s.rect.top(), s.rect.bottom())*qMin(f.rect.width(), s.rect.width());
47 | }
48 |
--------------------------------------------------------------------------------
/src/Graphic/Mode4.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Plain.h"
4 |
5 | class Mode4 :public Plain
6 | {
7 | public:
8 | Mode4(const Comment &comment);
9 | QList locate();
10 | bool move(double time);
11 | uint intersects(Graphic *other);
12 |
13 | private:
14 | double life;
15 | };
16 |
--------------------------------------------------------------------------------
/src/Graphic/Mode5.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "Mode5.h"
3 | #include "GraphicPrivate.h"
4 | #include "../Config.h"
5 |
6 | using namespace GraphicPrivate;
7 |
8 | Mode5::Mode5(const Comment &comment) :
9 | Plain(comment)
10 | {
11 | Q_ASSERT(comment.mode == 5);
12 | life = evaluate(Config::getValue("/Danmaku/Life", "5"));
13 | }
14 |
15 | QList Mode5::locate()
16 | {
17 | QList results;
18 | if (rect.height() > 360){
19 | return results;
20 | }
21 | QSize size = ARender::instance()->getActualSize();
22 | QRectF init = rect;
23 | init.moveCenter(QPointF(size.width() / 2.0, 0));
24 | int end = size.height()*(Config::getValue("/Danmaku/Protect", false) ? 0.85 : 1) - rect.height();
25 | int stp = Config::getValue("/Danmaku/Grating", 10);
26 | for (int height = 0; height <= end; height += stp){
27 | init.moveTop(height);
28 | results.append(init);
29 | }
30 | return results;
31 | }
32 |
33 | bool Mode5::move(double time)
34 | {
35 | if (enabled){
36 | life -= time;
37 | }
38 | return life > 0;
39 | }
40 |
41 | uint Mode5::intersects(Graphic *other)
42 | {
43 | Q_ASSERT(other->getMode() == 5);
44 | const Mode5 &f = *this;
45 | const Mode5 &s = *static_cast(other);
46 | return getOverlap(f.rect.top(), f.rect.bottom(), s.rect.top(), s.rect.bottom())*qMin(f.rect.width(), s.rect.width());
47 | }
--------------------------------------------------------------------------------
/src/Graphic/Mode5.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Plain.h"
4 |
5 | class Mode5 :public Plain
6 | {
7 | public:
8 | Mode5(const Comment &comment);
9 | QList locate();
10 | bool move(double time);
11 | uint intersects(Graphic *other);
12 |
13 | private:
14 | double life;
15 | };
--------------------------------------------------------------------------------
/src/Graphic/Mode6.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "Mode6.h"
3 | #include "GraphicPrivate.h"
4 | #include "../Config.h"
5 |
6 | using namespace GraphicPrivate;
7 |
8 | Mode6::Mode6(const Comment &comment) :
9 | Plain(comment)
10 | {
11 | Q_ASSERT(comment.mode == 6);
12 | speed = evaluate(Config::getValue("/Danmaku/Speed", "125+%{width}/5"));
13 | }
14 |
15 | QList Mode6::locate()
16 | {
17 | QList results;
18 | if (rect.height() > 360){
19 | return results;
20 | }
21 | QSize size = ARender::instance()->getActualSize();
22 | QRectF init = rect;
23 | init.moveRight(0);
24 | int end = size.height()*(Config::getValue("/Danmaku/Protect", false) ? 0.85 : 1) - rect.height();
25 | int stp = Config::getValue("/Danmaku/Grating", 10);
26 | for (int height = 0; height <= end; height += stp){
27 | init.moveTop(height);
28 | results.append(init);
29 | }
30 | return results;
31 | }
32 |
33 | bool Mode6::move(double time)
34 | {
35 | QSize size = ARender::instance()->getActualSize();
36 | if (enabled){
37 | rect.moveLeft(rect.left() + speed * time);
38 | }
39 | return rect.left() <= size.width();
40 | }
41 |
42 | uint Mode6::intersects(Graphic *other)
43 | {
44 | Q_ASSERT(other->getMode() == 6);
45 | const Mode6 &f = *static_cast(other);
46 | const Mode6 &s = *this;
47 | int h;
48 | if ((h = getOverlap(f.rect.top(), f.rect.bottom(), s.rect.top(), s.rect.bottom())) == 0){
49 | return 0;
50 | }
51 | int w = 0;
52 | if (f.rect.intersects(s.rect)){
53 | if (f.speed > s.speed){
54 | w = getOverlap(f.rect.left(), f.rect.right(), s.rect.left(), s.rect.right());
55 | }
56 | else{
57 | w = qMin(f.rect.width(), s.rect.width());
58 | }
59 | }
60 | else{
61 | double o = f.rect.left() - f.speed*s.rect.right() / s.speed;
62 | w = o > 0 ? qMin(qMin(f.rect.width(), s.rect.width()), o) : 0;
63 | }
64 | return h*w;
65 | }
66 |
--------------------------------------------------------------------------------
/src/Graphic/Mode6.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Plain.h"
4 |
5 | class Mode6 :public Plain
6 | {
7 | public:
8 | Mode6(const Comment &comment);
9 | QList locate();
10 | bool move(double time);
11 | uint intersects(Graphic *other);
12 |
13 | private:
14 | double speed;
15 | };
16 |
--------------------------------------------------------------------------------
/src/Graphic/Mode7.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "Mode7.h"
3 | #include "GraphicPrivate.h"
4 | #include "../Config.h"
5 | #include "../Render/ARender.h"
6 |
7 | using namespace GraphicPrivate;
8 |
9 | Mode7::Mode7(const Comment &comment)
10 | {
11 | Q_ASSERT(comment.mode == 7);
12 | QJsonArray data = QJsonDocument::fromJson(comment.string.toUtf8()).array();
13 | int l = data.size();
14 | if (l < 5){
15 | throw format_unrecognized();
16 | }
17 | QSize size = ARender::instance()->getActualSize();
18 | auto getDouble = [&data](int i){return data.at(i).toVariant().toDouble(); };
19 | double scale = getScale(comment.mode, comment.date, size);
20 | bPos = QPointF(getDouble(0), getDouble(1));
21 | ePos = l < 8 ? bPos : QPointF(getDouble(7), getDouble(8));
22 | int w = size.width(), h = size.height();
23 | if (bPos.x() < 1 && bPos.y() < 1 && ePos.x() < 1 && ePos.y() < 1){
24 | bPos.rx() *= w;
25 | ePos.rx() *= w;
26 | bPos.ry() *= h;
27 | ePos.ry() *= h;
28 | scale = 1;
29 | }
30 | else if (scale == 0){
31 | scale = 1;
32 | }
33 | else{
34 | QSizeF player = getPlayer(comment.date);
35 | QPoint offset = QPoint((w - player.width()*scale) / 2, (h - player.height()*scale) / 2);
36 | bPos = bPos*scale + offset;
37 | ePos = ePos*scale + offset;
38 | }
39 | QStringList alpha = data[2].toString().split('-');
40 | bAlpha = alpha[0].toDouble();
41 | eAlpha = alpha[1].toDouble();
42 | life = getDouble(3);
43 | QJsonValue v = l < 12 ? QJsonValue(true) : data[11];
44 | int effect = (v.isString() ? v.toString() == "true" : v.toVariant().toBool()) ? Config::getValue("/Danmaku/Effect", 5) / 2 : -1;
45 | QFont font = getFont(scale ? comment.font*scale : comment.font, l < 13 ? Utils::defaultFont(true) : data[12].toString());
46 | QString string = data[4].toString();
47 | //TODO: using ARender::getSprite
48 | cache = getCache(string, comment.color, font, getSize(string, font), comment.isLocal(), effect, 100);
49 | zRotate = l < 6 ? 0 : getDouble(5);
50 | yRotate = l < 7 ? 0 : getDouble(6);
51 | wait = l < 11 ? 0 : getDouble(10) / 1000;
52 | stay = l < 10 ? 0 : life - wait - getDouble(9) / 1000;
53 | source = &comment;
54 | time = 0;
55 | }
56 |
57 | bool Mode7::move(double time)
58 | {
59 | if (enabled){
60 | this->time += time;
61 | }
62 | return (this->time) <= life;
63 | }
64 |
65 | void Mode7::draw(QPainter *painter)
66 | {
67 | if (enabled){
68 | QPointF cPos = bPos + (ePos - bPos)*qBound(0, (time - wait) / (life - stay), 1);
69 | QTransform rotate;
70 | rotate.translate(+cPos.x(), +cPos.y());
71 | rotate.rotate(yRotate, Qt::YAxis);
72 | rotate.rotate(zRotate, Qt::ZAxis);
73 | rotate.translate(-cPos.x(), -cPos.y());
74 | painter->save();
75 | painter->setTransform(rotate);
76 | painter->setOpacity(bAlpha + (eAlpha - bAlpha)*time / life);
77 | painter->drawImage(cPos, cache);
78 | painter->restore();
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Graphic/Mode7.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Graphic.h"
4 |
5 | class Mode7 :public Graphic
6 | {
7 | public:
8 | Mode7(const Comment &comment);
9 | QList locate(){ return QList(); }
10 | bool move(double time);
11 | void draw(QPainter *painter);
12 | uint intersects(Graphic *){ return 0; }
13 |
14 | private:
15 | QPointF bPos;
16 | QPointF ePos;
17 | double bAlpha;
18 | double eAlpha;
19 | double zRotate;
20 | double yRotate;
21 | QImage cache;
22 | double wait;
23 | double stay;
24 | double life;
25 | double time;
26 | };
27 |
--------------------------------------------------------------------------------
/src/Graphic/Plain.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "Plain.h"
3 | #include "GraphicPrivate.h"
4 |
5 | using namespace GraphicPrivate;
6 |
7 | Plain::Plain(const Comment &comment)
8 | {
9 | source = &comment;
10 | sprite = ARender::instance()->getSprite(comment);
11 | rect.setSize(sprite->getSize());
12 | }
13 |
14 | Plain::~Plain()
15 | {
16 | delete sprite;
17 | }
18 |
19 | void Plain::draw(QPainter *painter)
20 | {
21 | if (enabled){
22 | sprite->draw(painter, rect);
23 | }
24 | }
25 |
26 | double Plain::evaluate(QString expression)
27 | {
28 | expression.replace("%{width}", QString::number(rect.width()), Qt::CaseInsensitive);
29 | try{
30 | return Utils::evaluate(expression);
31 | }
32 | catch (std::runtime_error){
33 | throw args_prasing_error();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Graphic/Plain.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Graphic.h"
4 | #include "../Render/ARender.h"
5 | #include "../Render/ISprite.h"
6 |
7 | class Plain :public Graphic
8 | {
9 | public:
10 | void draw(QPainter *painter);
11 |
12 | protected:
13 | ISprite *sprite;
14 |
15 | explicit Plain(const Comment &comment);
16 | virtual ~Plain();
17 |
18 | double evaluate(QString expression);
19 | };
20 |
--------------------------------------------------------------------------------
/src/Local.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 "Common.h"
28 | #include "Local.h"
29 | #include "Config.h"
30 | #include "Plugin.h"
31 | #include "Utils.h"
32 | #include "Model/Danmaku.h"
33 | #include "Model/List.h"
34 | #include "Model/Shield.h"
35 | #include "Player/APlayer.h"
36 | #include "Render/ARender.h"
37 | #include "UI/Interface.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 | qThreadPool->setMaxThreadCount(Config::getValue("/Danmaku/Thread", QThread::idealThreadCount()));
50 | qsrand(QTime::currentTime().msec());
51 | }
52 |
53 | void Local::exit(int code)
54 | {
55 | delete List::instance();
56 | Config::save();
57 | delete APlayer::instance();
58 | delete Danmaku::instance();
59 | QApplication::exit(code);
60 | }
61 |
62 | namespace
63 | {
64 | void setDefaultFont()
65 | {
66 | QString def = Utils::defaultFont();
67 | QFontInfo i(qApp->font());
68 | if (!QFontDatabase().families().contains(def)){
69 | def = i.family();
70 | }
71 | double p = i.pointSizeF();
72 | QFont f;
73 | f.setFamily(Config::getValue("/Interface/Font/Family", def));
74 | f.setPointSizeF(Config::getValue("/Interface/Font/Size", p));
75 | qApp->setFont(f);
76 | }
77 |
78 | void loadTranslator()
79 | {
80 | QString locale = Config::getValue("/Interface/Locale", QLocale::system().name());
81 | QFileInfoList list;
82 | list += QDir("./locale/" + locale).entryInfoList();
83 | list += QFileInfo("./locale/" + locale + ".qm");
84 | locale.resize(2);
85 | list += QDir("./locale/" + locale).entryInfoList();
86 | list += QFileInfo("./locale/" + locale + ".qm");
87 | for (QFileInfo info : list){
88 | if (!info.isFile()){
89 | continue;
90 | }
91 | QTranslator *trans = new QTranslator(qApp);
92 | if (trans->load(info.absoluteFilePath())){
93 | qApp->installTranslator(trans);
94 | }
95 | else{
96 | delete trans;
97 | }
98 | }
99 | }
100 |
101 | void setToolTipBase()
102 | {
103 | QPalette tip = qApp->palette();
104 | tip.setColor(QPalette::Inactive, QPalette::ToolTipBase, Qt::white);
105 | qApp->setPalette(tip);
106 | QToolTip::setPalette(tip);
107 | }
108 | }
109 |
110 | int main(int argc, char *argv[])
111 | {
112 | Local a(argc, argv);
113 | int single;
114 | if ((single = Config::getValue("/Interface/Single", 1))){
115 | QLocalSocket socket;
116 | socket.connectToServer("BiliLocalInstance");
117 | if (socket.waitForConnected()){
118 | QDataStream s(&socket);
119 | s << a.arguments().mid(1);
120 | socket.waitForBytesWritten();
121 | return 0;
122 | }
123 | }
124 | loadTranslator();
125 | setDefaultFont();
126 | setToolTipBase();
127 | Interface w;
128 | Plugin::loadPlugins();
129 | if (!w.testAttribute(Qt::WA_WState_ExplicitShowHide)){
130 | w.show();
131 | }
132 | w.tryLocal(a.arguments().mid(1));
133 | QLocalServer *server = nullptr;
134 | if (single){
135 | server = new QLocalServer(lApp);
136 | server->listen("BiliLocalInstance");
137 | QObject::connect(server, &QLocalServer::newConnection, [&](){
138 | QLocalSocket *r = server->nextPendingConnection();
139 | r->waitForReadyRead();
140 | QDataStream s(r);
141 | QStringList args;
142 | s >> args;
143 | delete r;
144 | w.tryLocal(args);
145 | });
146 | }
147 | int r;
148 | if ((r = a.exec()) == 12450){
149 | if (server){
150 | delete server;
151 | }
152 | QProcess::startDetached(a.applicationFilePath(), QStringList());
153 | return 0;
154 | }
155 | else{
156 | return r;
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/src/Local.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 | #pragma once
28 |
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | #define lApp (static_cast(QCoreApplication::instance()))
37 |
38 | #define qThreadPool QThreadPool::globalInstance()
39 |
40 | class Local :public QApplication
41 | {
42 | Q_OBJECT
43 | public:
44 | Local(int &argc, char **argv);
45 |
46 | static Local *instance()
47 | {
48 | return lApp;
49 | }
50 |
51 | static QHash objects;
52 |
53 | public slots:
54 | void exit(int code = 0);
55 |
56 | QWidget *mainWidget()
57 | {
58 | return qobject_cast(objects["Interface"]);
59 | }
60 |
61 | QObject *findObject(QString name)
62 | {
63 | return objects[name];
64 | }
65 |
66 | void synchronize(void *func)
67 | {
68 | ((void(*)())func)();
69 | }
70 |
71 | void synchronize(void *func, void *args)
72 | {
73 | ((void(*)(void *))func)(args);
74 | }
75 | };
76 |
--------------------------------------------------------------------------------
/src/Model/Danmaku.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 | #pragma once
28 |
29 | #include
30 | #include
31 |
32 | class Comment;
33 | class Graphic;
34 | class Record;
35 | class DanmakuPrivate;
36 |
37 | class Danmaku :public QAbstractItemModel
38 | {
39 | Q_OBJECT
40 | public:
41 | virtual QVariant data(const QModelIndex &index, int role) const override;
42 | virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
43 | virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;
44 | virtual QModelIndex parent(const QModelIndex &) const override;
45 | virtual QModelIndex index(int row, int colum, const QModelIndex &parent = QModelIndex()) const override;
46 | virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
47 |
48 | virtual ~Danmaku();
49 | QList &getPool();
50 | void draw(QPainter *painter, double move);
51 | static Danmaku *instance();
52 |
53 | private:
54 | static Danmaku *ins;
55 | DanmakuPrivate *const d_ptr;
56 | Q_DECLARE_PRIVATE(Danmaku);
57 |
58 | explicit Danmaku(QObject *parent = 0);
59 |
60 | signals:
61 | void alphaChanged(int);
62 | void unrecognizedComment(const Comment *);
63 |
64 | public slots:
65 | const Comment *commentAt(QPointF point) const;
66 | void setAlpha(int alpha);
67 | void clearPool();
68 | void resetTime();
69 | void setTime(qint64 time);
70 | void appendToPool(const Record *record);
71 | void appendToPool(QString source, const Comment *comment);
72 | void clearCurrent(bool soft = false);
73 | void insertToCurrent(Graphic *graphic, int index = -1);
74 | void parse(int flag = 0);
75 | void delayAll(qint64 time);
76 | void jumpToTime(qint64 time);
77 | void saveToFile(QString file) const;
78 | qint64 getDuration() const;
79 | };
80 |
--------------------------------------------------------------------------------
/src/Model/List.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 | #pragma once
28 |
29 | #include
30 | #include
31 |
32 | class List :public QStandardItemModel
33 | {
34 | Q_OBJECT
35 | public:
36 | enum Role
37 | {
38 | FileRole = Qt::UserRole,
39 | CodeRole,
40 | TimeRole,
41 | DateRole
42 | };
43 |
44 | enum Danm
45 | {
46 | Records,
47 | Inherit,
48 | Surmise
49 | };
50 |
51 | ~List();
52 | static List *instance();
53 | QStringList mimeTypes() const;
54 | QMimeData *mimeData(const QModelIndexList &) const;
55 | bool dropMimeData(const QMimeData *, Qt::DropAction, int, int, const QModelIndex &p);
56 |
57 | private:
58 | QStandardItem *cur;
59 | qint64 time;
60 | QList icons;
61 | static List *ins;
62 | List(QObject *parent);
63 | void setRelated(const QModelIndexList &indexes, int reason);
64 |
65 | public slots:
66 | QString defaultPath(int type);
67 | QStandardItem *getCurrent(){ return cur; }
68 | QStandardItem *itemFromFile(QString file, bool create = false);
69 | bool finished();
70 | void appendMedia(QString file);
71 | void updateCurrent();
72 | void split(const QModelIndex &index);
73 | void split(const QModelIndexList &indexes);
74 | void waste(const QModelIndex &index);
75 | void waste(const QModelIndexList &indexes);
76 | void merge(const QModelIndexList &indexes);
77 | void group(const QModelIndexList &indexes);
78 | void jumpToLast();
79 | void jumpToNext();
80 | bool jumpToIndex(const QModelIndex &index, bool manually = true);
81 | };
82 |
--------------------------------------------------------------------------------
/src/Model/Shield.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 "Common.h"
28 | #include "Shield.h"
29 | #include "../Config.h"
30 | #include "../Utils.h"
31 | #include
32 |
33 | Shield *Shield::ins = nullptr;
34 |
35 | Shield *Shield::instance()
36 | {
37 | return ins ? ins : new Shield(qApp);
38 | }
39 |
40 | class ShieldPrivate
41 | {
42 | public:
43 | bool shieldG[8];
44 | QSet shieldS;
45 | QList shieldR;
46 |
47 | bool contains(const QString &shield)
48 | {
49 | if (shield.length() <= 2){
50 | return false;
51 | }
52 | QString content = shield.mid(2);
53 | switch (shield[0].unicode()){
54 | case 'm':
55 | {
56 | bool ok;
57 | int i = content.toInt(&ok);
58 | return ok&&i >= 0 && i < 8 && shieldG[i];
59 | }
60 | case 't':
61 | for (const auto &iter : shieldR){
62 | if (content == iter.pattern()){
63 | return true;
64 | }
65 | }
66 | return false;
67 | case 'u':
68 | return shieldS.contains(content);
69 | default:
70 | return false;
71 | }
72 | }
73 |
74 | void insert(const QString &shield)
75 | {
76 | if (shield.length() <= 2){
77 | return;
78 | }
79 | QString content = shield.mid(2);
80 | switch (shield[0].unicode()){
81 | case 'm':
82 | {
83 | bool ok;
84 | int i = content.toInt(&ok);
85 | if (ok&&i >= 0 && i < 8){
86 | shieldG[i] = true;
87 | }
88 | break;
89 | }
90 | case 't':
91 | {
92 | QRegularExpression r(content);
93 | if (r.isValid()){
94 | shieldR.append(r);
95 | }
96 | break;
97 | }
98 | case 'u':
99 | shieldS.insert(content);
100 | break;
101 | default:
102 | break;
103 | }
104 | }
105 |
106 | void remove(const QString &shield)
107 | {
108 | if (shield.length() <= 2){
109 | return;
110 | }
111 | QString content = shield.mid(2);
112 | switch (shield[0].unicode()){
113 | case 'm':
114 | {
115 | bool ok;
116 | int i = content.toInt(&ok);
117 | if (ok&&i >= 0 && i < 8){
118 | shieldG[i] = false;
119 | }
120 | break;
121 | }
122 | case 't':
123 | for (auto iter = shieldR.begin(); iter != shieldR.end(); ++iter){
124 | if (iter->pattern() == content){
125 | shieldR.erase(iter);
126 | break;
127 | }
128 | }
129 | break;
130 | case 'u':
131 | shieldS.remove(content);
132 | break;
133 | default:
134 | break;
135 | }
136 | }
137 | };
138 |
139 | Shield::Shield(QObject *parent) :
140 | QObject(parent), d_ptr(new ShieldPrivate)
141 | {
142 | Q_D(Shield);
143 | ins = this;
144 | QJsonArray s = Config::getValue("/Shield/Sender");
145 | QJsonArray r = Config::getValue("/Shield/Regexp");
146 | for (const QJsonValue &item : s){
147 | d->shieldS.insert(item.toString());
148 | }
149 | for (const QJsonValue &item : r){
150 | d->shieldR.append(QRegularExpression(item.toString()));
151 | }
152 | int group = Config::getValue("/Shield/Group", 0);
153 | for (int i = 7; i >= 0; --i){
154 | d->shieldG[i] = group & 1;
155 | group = group >> 1;
156 | }
157 | connect(Config::instance(), &Config::aboutToSave, [d]{
158 | QJsonArray s, r;
159 | for (auto &item : d->shieldS){
160 | s.append(item);
161 | }
162 | Config::setValue("/Shield/Sender", s);
163 | for (auto &item : d->shieldR){
164 | r.append(item.pattern());
165 | }
166 | Config::setValue("/Shield/Regexp", r);
167 | int g = 0;
168 | for (int i = 0; i < 8; ++i){
169 | g = (g << 1) + d->shieldG[i];
170 | }
171 | Config::setValue("/Shield/Group", g);
172 | });
173 | }
174 |
175 | Shield::~Shield()
176 | {
177 | delete d_ptr;
178 | }
179 |
180 | void Shield::setAllShields(const QStringList &shields)
181 | {
182 | Q_D(Shield);
183 | d->shieldR.clear();
184 | d->shieldS.clear();
185 | for (auto &iter : d->shieldG){
186 | iter = false;
187 | }
188 | for (const QString &iter : shields){
189 | d->insert(iter);
190 | }
191 | emit shieldChanged();
192 | }
193 |
194 | QStringList Shield::getAllShields()
195 | {
196 | Q_D(Shield);
197 | QStringList shields;
198 | for (int i = 0; i < 8;++i){
199 | if (d->shieldG[i]){
200 | shields.append(QString("m=%1").arg(i));
201 | }
202 | }
203 | for (const auto &iter : d->shieldS){
204 | shields.append("u=" + iter);
205 | }
206 | for (const auto &iter : d->shieldR){
207 | shields.append("t=" + iter.pattern());
208 | }
209 | std::sort(shields.begin(), shields.end());
210 | return shields;
211 | }
212 |
213 | bool Shield::contains(const QString &shield)
214 | {
215 | Q_D(Shield);
216 | return d->contains(shield);
217 | }
218 |
219 | void Shield::insert(const QString &shield)
220 | {
221 | Q_D(Shield);
222 | d->insert(shield);
223 | emit shieldChanged();
224 | }
225 |
226 | void Shield::remove(const QString &shield)
227 | {
228 | Q_D(Shield);
229 | d->remove(shield);
230 | emit shieldChanged();
231 | }
232 |
233 | bool Shield::isBlocked(const Comment &comment)
234 | {
235 | Q_D(Shield);
236 | if (d->shieldG[Whole]
237 | || (comment.mode == 1 && d->shieldG[Slide])
238 | || (comment.mode == 4 && d->shieldG[Bottom])
239 | || (comment.mode == 5 && d->shieldG[Top])
240 | || (comment.mode == 6 && d->shieldG[Reverse])
241 | || (d->shieldG[Advanced] && (comment.mode == 7 || comment.mode == 8))
242 | || (comment.color != 0xFFFFFF && d->shieldG[Color])){
243 | return true;
244 | }
245 | if (d->shieldG[Guest]){
246 | if (comment.sender.length() == 14 && comment.sender[3] == 'k'){
247 | return true;
248 | }
249 | if (comment.sender.startsWith('D', Qt::CaseInsensitive)){
250 | return true;
251 | }
252 | if (comment.sender == "0"){
253 | return true;
254 | }
255 | }
256 | if (d->shieldS.contains(comment.sender)){
257 | return true;
258 | }
259 | for (const auto &r : d->shieldR){
260 | if (r.match(comment.string).hasMatch()){
261 | return true;
262 | }
263 | }
264 | return false;
265 | }
266 |
--------------------------------------------------------------------------------
/src/Model/Shield.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 | #pragma once
28 |
29 | #include
30 |
31 | class Comment;
32 | class ShieldPrivate;
33 |
34 | class Shield :public QObject
35 | {
36 | Q_OBJECT
37 | public:
38 | enum Group
39 | {
40 | Top,
41 | Bottom,
42 | Slide,
43 | Reverse,
44 | Guest,
45 | Advanced,
46 | Color,
47 | Whole
48 | };
49 |
50 | static Shield *instance();
51 | ~Shield();
52 |
53 | private:
54 | static Shield *ins;
55 | ShieldPrivate *const d_ptr;
56 | Q_DECLARE_PRIVATE(Shield);
57 |
58 | explicit Shield(QObject *parent = 0);
59 |
60 | signals:
61 | void shieldChanged();
62 |
63 | public slots:
64 | void setAllShields(const QStringList &);
65 | QStringList getAllShields();
66 | bool contains(const QString &);
67 | void insert(const QString &);
68 | void remove(const QString &);
69 | bool isBlocked(const Comment &);
70 | };
71 |
--------------------------------------------------------------------------------
/src/Player/APlayer.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 Lysine.
4 | *
5 | * Filename: VPlayer.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 "Common.h"
28 | #include "APlayer.h"
29 | #include "../Config.h"
30 | #include "../Utils.h"
31 |
32 | #ifdef BACKEND_VLC
33 | #include "VPlayer.h"
34 | #endif
35 | #ifdef BACKEND_QMM
36 | #include "QPlayer.h"
37 | #endif
38 | #ifdef BACKEND_NIL
39 | #include "NPlayer.h"
40 | #endif
41 |
42 | QStringList APlayer::getModules()
43 | {
44 | QStringList modules;
45 | #ifdef BACKEND_VLC
46 | modules << "VLC";
47 | #endif
48 | #ifdef BACKEND_QMM
49 | modules << "QMM";
50 | #endif
51 | #ifdef BACKEND_NIL
52 | modules << "NIL";
53 | #endif
54 | return modules;
55 | }
56 |
57 | APlayer *APlayer::ins = nullptr;
58 |
59 | APlayer *APlayer::instance()
60 | {
61 | if (ins){
62 | return ins;
63 | }
64 | QString d;
65 | QStringList l = getModules();
66 | switch (l.size()){
67 | case 0:
68 | break;
69 | case 1:
70 | d = l[0];
71 | break;
72 | default:
73 | d = Config::getValue("/Performance/Decode", l[0]);
74 | d = l.contains(d) ? d : l[0];
75 | break;
76 | }
77 | #ifdef BACKEND_VLC
78 | if (d == "VLC"){
79 | return new VPlayer(qApp);
80 | }
81 | #endif
82 | #ifdef BACKEND_QMM
83 | if (d == "QMM"){
84 | return new QPlayer(qApp);
85 | }
86 | #endif
87 | #ifdef BACKEND_NIL
88 | if (d == "NIL"){
89 | return new NPlayer(qApp);
90 | }
91 | #endif
92 | return 0;
93 | }
94 |
95 | void APlayer::setRate(double)
96 | {
97 | }
98 |
99 | double APlayer::getRate()
100 | {
101 | return 0;
102 | }
103 |
104 | qint64 APlayer::getDelay(int)
105 | {
106 | return 0;
107 | }
108 |
109 | void APlayer::setDelay(int, qint64)
110 | {
111 | }
112 |
113 | void APlayer::addSubtitle(QString)
114 | {
115 | }
116 |
117 | void APlayer::event(int)
118 | {
119 | }
120 |
--------------------------------------------------------------------------------
/src/Player/APlayer.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 | #pragma once
28 |
29 | #include
30 | #include
31 |
32 | class APlayer :public QObject
33 | {
34 | Q_OBJECT
35 | public:
36 | static QStringList getModules();
37 |
38 | enum State
39 | {
40 | Stop,
41 | Play,
42 | Pause,
43 | Loop
44 | };
45 |
46 | enum Error
47 | {
48 | UnknownError,
49 | ResourceError,
50 | FormatError,
51 | NetworkError,
52 | AccessDeniedError,
53 | ServiceMissingError
54 | };
55 |
56 | static APlayer *instance();
57 |
58 | virtual QList getTracks(int type) = 0;
59 |
60 | protected:
61 | static APlayer *ins;
62 |
63 | APlayer(QObject *parent = 0) :QObject(parent){}
64 |
65 | signals:
66 | void errorOccurred(int);
67 | void begin();
68 | void reach(bool);
69 | void decode();
70 | void jumped(qint64);
71 | void stateChanged(int);
72 | void mediaChanged(QString);
73 | void delayChanged(int, qint64);
74 | void timeChanged(qint64);
75 | void rateChanged(double);
76 | void volumeChanged(int);
77 |
78 | public slots:
79 | virtual void play() = 0;
80 | virtual void stop(bool manually = true) = 0;
81 | virtual int getState() = 0;
82 |
83 | virtual void setTime(qint64 time) = 0;
84 | virtual qint64 getTime() = 0;
85 |
86 | virtual void setMedia(QString file, bool manually = true) = 0;
87 | virtual QString getMedia() = 0;
88 |
89 | virtual qint64 getDuration() = 0;
90 |
91 | virtual void setVolume(int volume) = 0;
92 | virtual int getVolume() = 0;
93 |
94 | virtual void setRate(double rate);
95 | virtual double getRate();
96 |
97 | virtual qint64 getDelay(int type);
98 | virtual void setDelay(int type, qint64 delay);
99 |
100 | virtual void addSubtitle(QString file);
101 |
102 | virtual void event(int type);
103 | };
104 |
--------------------------------------------------------------------------------
/src/Player/NPlayer.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "NPlayer.h"
3 | #include "../Render/ARender.h"
4 |
5 | NPlayer::NPlayer(QObject *parent) :
6 | APlayer(parent)
7 | {
8 | ins = this;
9 | setObjectName("NPlayer");
10 |
11 | state = Stop;
12 | startTimer(100);
13 | }
14 |
15 | void NPlayer::timerEvent(QTimerEvent *)
16 | {
17 | if (state == Play){
18 | emit timeChanged(getTime());
19 | }
20 | }
21 |
22 | QList NPlayer::getTracks(int)
23 | {
24 | return QList();
25 | }
26 |
27 | void NPlayer::play()
28 | {
29 | if (state != Stop){
30 | return;
31 | }
32 | ARender::instance()->setMusic(true);
33 | emit stateChanged(state = Play);
34 | emit begin();
35 | start = QDateTime::currentMSecsSinceEpoch();
36 | }
37 |
38 | void NPlayer::stop(bool)
39 | {
40 | emit reach(true);
41 | emit stateChanged(state = Stop);
42 | }
43 |
44 | void NPlayer::setTime(qint64)
45 | {
46 | }
47 |
48 | qint64 NPlayer::getTime()
49 | {
50 | return state == Stop ? -1 : (QDateTime::currentMSecsSinceEpoch() - start);
51 | }
52 |
53 | void NPlayer::setMedia(QString, bool)
54 | {
55 | }
56 |
57 | QString NPlayer::getMedia()
58 | {
59 | return QString();
60 | }
61 |
62 | qint64 NPlayer::getDuration()
63 | {
64 | return -1;
65 | }
66 |
67 | void NPlayer::setVolume(int)
68 | {
69 | }
70 |
71 | int NPlayer::getVolume()
72 | {
73 | return 0;
74 | }
75 |
--------------------------------------------------------------------------------
/src/Player/NPlayer.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "APlayer.h"
4 |
5 | class NPlayer :public APlayer
6 | {
7 | public:
8 | explicit NPlayer(QObject *parent = 0);
9 | QList getTracks(int type);
10 |
11 | private:
12 | qint64 start;
13 | int state;
14 |
15 | void timerEvent(QTimerEvent * e);
16 |
17 | public slots:
18 | void play();
19 | void stop(bool manually = true);
20 | int getState(){ return state; }
21 |
22 | void setTime(qint64 time);
23 | qint64 getTime();
24 |
25 | void setMedia(QString file, bool manually = true);
26 | QString getMedia();
27 |
28 | qint64 getDuration();
29 |
30 | void setVolume(int volume);
31 | int getVolume();
32 | };
33 |
--------------------------------------------------------------------------------
/src/Player/QPlayer.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "QPlayer.h"
3 | #include "../Config.h"
4 | #include "../Render/ARender.h"
5 |
6 | namespace
7 | {
8 | QString getFormat(QVideoFrame::PixelFormat format)
9 | {
10 | switch (format){
11 | case QVideoFrame::Format_YUV420P:
12 | return "I420";
13 | case QVideoFrame::Format_YV12:
14 | return "YV12";
15 | case QVideoFrame::Format_NV12:
16 | return "NV12";
17 | case QVideoFrame::Format_NV21:
18 | return "NV21";
19 | default:
20 | return QString();
21 | }
22 | }
23 |
24 | class RenderAdapter :public QAbstractVideoSurface
25 | {
26 | public:
27 | RenderAdapter(QObject *parent = 0) :
28 | QAbstractVideoSurface(parent)
29 | {
30 | }
31 |
32 | bool start(const QVideoSurfaceFormat &format)
33 | {
34 | QString chroma = getFormat(format.pixelFormat());
35 | if (chroma.isEmpty())
36 | return false;
37 | QString buffer(chroma);
38 | ARender::instance()->setBuffer(buffer, format.frameSize(), 1);
39 | if (buffer != chroma)
40 | return false;
41 | QSize pixel(format.pixelAspectRatio());
42 | ARender::instance()->setPixelAspectRatio(pixel.width() / (double)pixel.height());
43 | return true;
44 | }
45 |
46 | bool present(const QVideoFrame &frame)
47 | {
48 | QVideoFrame f(frame);
49 | if (f.map(QAbstractVideoBuffer::ReadOnly)){
50 | int len = f.mappedBytes();
51 | const quint8 *dat = f.bits();
52 | QList buffer = ARender::instance()->getBuffer();
53 | memcpy(buffer[0], dat, len);
54 | ARender::instance()->releaseBuffer();
55 | f.unmap();
56 | }
57 | else{
58 | return false;
59 | }
60 | emit APlayer::instance()->decode();
61 | return true;
62 | }
63 |
64 | QList supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const
65 | {
66 | QList f;
67 | if (QAbstractVideoBuffer::NoHandle == handleType){
68 | f << QVideoFrame::Format_NV12 <<
69 | QVideoFrame::Format_NV21 <<
70 | QVideoFrame::Format_YV12 <<
71 | QVideoFrame::Format_YUV420P;
72 | }
73 | return f;
74 | }
75 | };
76 |
77 | class QPlayerThread :public QThread
78 | {
79 | public:
80 | explicit QPlayerThread(QObject *parent = 0) :
81 | QThread(parent), mp(0)
82 | {
83 | }
84 |
85 | ~QPlayerThread()
86 | {
87 | if (isRunning()){
88 | quit();
89 | wait();
90 | }
91 | }
92 |
93 | QMediaPlayer *getMediaPlayer()
94 | {
95 | if (!isRunning() && mp == 0){
96 | m.lock();
97 | start();
98 | w.wait(&m);
99 | m.unlock();
100 | }
101 | return mp;
102 | }
103 |
104 | private:
105 | QMediaPlayer *mp;
106 | QMutex m;
107 | QWaitCondition w;
108 |
109 | void run()
110 | {
111 | m.lock();
112 | mp = new QMediaPlayer;
113 | mp->setNotifyInterval(300);
114 | mp->setVideoOutput(new RenderAdapter(mp));
115 | m.unlock();
116 | w.wakeAll();
117 | exec();
118 | delete mp;
119 | }
120 | };
121 | }
122 |
123 |
124 | QPlayer::QPlayer(QObject *parent) :
125 | APlayer(parent)
126 | {
127 | ins = this;
128 | setObjectName("QPlayer");
129 | state = Stop;
130 | manuallyStopped = false;
131 | waitingForBegin = false;
132 | skipTimeChanged = false;
133 |
134 | mp = (new QPlayerThread(this))->getMediaPlayer();
135 | mp->setVolume(Config::getValue("/Playing/Volume", 50));
136 |
137 | connect(mp, &QMediaPlayer::error, this, [this](int error){
138 | if ((State)mp->state() == Play){
139 | manuallyStopped = true;
140 | }
141 | emit errorOccurred(error);
142 | });
143 |
144 | connect(mp, &QMediaPlayer::volumeChanged, this, &QPlayer::volumeChanged);
145 |
146 | connect(mp, &QMediaPlayer::stateChanged, this, [this](int _state){
147 | if (_state == Stop){
148 | if (!manuallyStopped&&Config::getValue("/Playing/Loop", false)){
149 | stateChanged(state = Loop);
150 | play();
151 | emit jumped(0);
152 | }
153 | else{
154 | stateChanged(state = Stop);
155 | emit reach(manuallyStopped);
156 | }
157 | manuallyStopped = false;
158 | }
159 | else{
160 | manuallyStopped = false;
161 | if (_state == Play&&state == Stop){
162 | waitingForBegin = true;
163 | }
164 | else{
165 | emit stateChanged(state = _state);
166 | }
167 | }
168 | });
169 |
170 | connect(mp, &QMediaPlayer::positionChanged, this, [this](qint64 time){
171 | if (waitingForBegin&&time > 0){
172 | waitingForBegin = false;
173 | ARender::instance()->setMusic(!mp->isVideoAvailable());
174 | emit stateChanged(state = Play);
175 | emit begin();
176 | }
177 | if (!skipTimeChanged){
178 | emit timeChanged(time);
179 | }
180 | else{
181 | skipTimeChanged = false;
182 | }
183 | });
184 |
185 | connect(mp, &QMediaPlayer::mediaChanged, this, [this](){
186 | emit mediaChanged(getMedia());
187 | });
188 |
189 | connect(mp, &QMediaPlayer::playbackRateChanged, this, &QPlayer::rateChanged);
190 | }
191 |
192 | QList QPlayer::getTracks(int)
193 | {
194 | return QList();
195 | }
196 |
197 | void QPlayer::play()
198 | {
199 | QMetaObject::invokeMethod(mp, getState() == Play ? "pause" : "play",
200 | Qt::BlockingQueuedConnection);
201 | }
202 |
203 | void QPlayer::stop(bool manually)
204 | {
205 | manuallyStopped = manually;
206 | QMetaObject::invokeMethod(mp, "stop",
207 | Qt::BlockingQueuedConnection);
208 | }
209 |
210 | void QPlayer::setTime(qint64 _time)
211 | {
212 | QMetaObject::invokeMethod(mp, "setPosition",
213 | Qt::BlockingQueuedConnection,
214 | Q_ARG(qint64, _time));
215 | skipTimeChanged = true;
216 | emit jumped(_time);
217 | }
218 |
219 | qint64 QPlayer::getTime()
220 | {
221 | return mp->position();
222 | }
223 |
224 | void QPlayer::setMedia(QString _file, bool manually)
225 | {
226 | stop(manually);
227 | QMetaObject::invokeMethod(mp, "setMedia",
228 | Qt::BlockingQueuedConnection,
229 | Q_ARG(QMediaContent, QUrl::fromLocalFile(_file)));
230 | QMetaObject::invokeMethod(mp, "setPlaybackRate",
231 | Qt::BlockingQueuedConnection,
232 | Q_ARG(qreal, 1.0));
233 | if (Config::getValue("/Playing/Immediate", false)){
234 | play();
235 | }
236 | }
237 |
238 | QString QPlayer::getMedia()
239 | {
240 | QUrl u = mp->media().canonicalUrl();
241 | return u.isLocalFile() ? u.toLocalFile() : QString();
242 | }
243 |
244 | qint64 QPlayer::getDuration()
245 | {
246 | return mp->duration();
247 | }
248 |
249 | void QPlayer::setVolume(int _volume)
250 | {
251 | _volume = qBound(0, _volume, 100);
252 | mp->setVolume(_volume);
253 | Config::setValue("/Playing/Volume", _volume);
254 | }
255 |
256 | int QPlayer::getVolume()
257 | {
258 | return mp->volume();
259 | }
260 |
261 | void QPlayer::setRate(double _rate)
262 | {
263 | mp->setPlaybackRate(_rate);
264 | }
265 |
266 | double QPlayer::getRate()
267 | {
268 | return mp->playbackRate();
269 | }
270 |
--------------------------------------------------------------------------------
/src/Player/QPlayer.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "APlayer.h"
4 | #include
5 |
6 | class QPlayer :public APlayer
7 | {
8 | public:
9 | explicit QPlayer(QObject *parent = 0);
10 | QList getTracks(int type);
11 |
12 | private:
13 | QMediaPlayer *mp;
14 | int state;
15 | bool manuallyStopped;
16 | bool waitingForBegin;
17 | bool skipTimeChanged;
18 |
19 | public slots:
20 | void play();
21 | void stop(bool manually = true);
22 | int getState(){ return state; }
23 |
24 | void setTime(qint64 time);
25 | qint64 getTime();
26 |
27 | void setMedia(QString file, bool manually = true);
28 | QString getMedia();
29 |
30 | qint64 getDuration();
31 |
32 | void setVolume(int volume);
33 | int getVolume();
34 |
35 | void setRate(double rate);
36 | double getRate();
37 | };
38 |
--------------------------------------------------------------------------------
/src/Player/VPlayer.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "APlayer.h"
4 | #include
5 |
6 | extern "C"
7 | {
8 | #include
9 | }
10 |
11 | class VPlayer :public APlayer
12 | {
13 | public:
14 | enum Event
15 | {
16 | Init,
17 | Wait,
18 | Free,
19 | Fail
20 | };
21 |
22 | explicit VPlayer(QObject *parent = 0);
23 | ~VPlayer();
24 | static QMutex time;
25 | QList getTracks(int type);
26 |
27 | private:
28 | int state;
29 | QActionGroup *tracks[3];
30 | libvlc_instance_t *vlc;
31 | libvlc_media_player_t *mp;
32 |
33 | void init();
34 | void wait();
35 | void free();
36 |
37 | public slots:
38 | void play();
39 | void stop(bool manually = true);
40 | int getState(){ return state; }
41 |
42 | void setTime(qint64 time);
43 | qint64 getTime();
44 |
45 | void setMedia(QString file, bool manually = true);
46 | QString getMedia();
47 |
48 | qint64 getDuration();
49 |
50 | void setVolume(int volume);
51 | int getVolume();
52 |
53 | void setRate(double rate);
54 | double getRate();
55 |
56 | qint64 getDelay(int type);
57 | void setDelay(int type, qint64 delay);
58 |
59 | void addSubtitle(QString file);
60 |
61 | void event(int type);
62 | };
63 |
--------------------------------------------------------------------------------
/src/Plugin.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 "Common.h"
28 | #include "Plugin.h"
29 | #include "Config.h"
30 | #include "Local.h"
31 |
32 | QList Plugin::plugins;
33 |
34 | Plugin::Plugin(QString path)
35 | {
36 | m_regist = (RegistPtr)QLibrary::resolve(path, "regist");
37 | m_config = (ConfigPtr)QLibrary::resolve(path, "config");
38 | m_string = (StringPtr)QLibrary::resolve(path, "string");
39 | }
40 |
41 | bool Plugin::loaded()
42 | {
43 | return m_regist&&m_config&&m_string;
44 | }
45 |
46 | void Plugin::regist(const QHash &objects)
47 | {
48 | if (m_regist)
49 | m_regist(objects);
50 | }
51 |
52 | void Plugin::config(QWidget *parent)
53 | {
54 | if (m_config)
55 | m_config(parent);
56 | }
57 |
58 | QString Plugin::string(QString query)
59 | {
60 | return m_string(query);
61 | }
62 |
63 | void Plugin::loadPlugins()
64 | {
65 | QFileInfoList list = QDir("./plugins/bililocal/").entryInfoList();
66 | for (const QFileInfo &info : list){
67 | if (info.isFile() && QLibrary::isLibrary(info.fileName())){
68 | Plugin lib(info.absoluteFilePath());
69 | if (lib.loaded()){
70 | if (Config::getValue("/Plugin/" + lib.string("Name"), true)){
71 | lib.regist(Local::objects);
72 | }
73 | else{
74 | lib.m_config = nullptr;
75 | lib.m_regist = nullptr;
76 | }
77 | plugins.append(lib);
78 | }
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/Plugin.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 | #pragma once
28 |
29 | #include
30 | #include
31 |
32 | class Plugin
33 | {
34 | public:
35 | typedef void(*RegistPtr)(const QHash &);
36 | typedef void(*ConfigPtr)(QWidget *);
37 | typedef QString(*StringPtr)(QString);
38 |
39 | static QList plugins;
40 | static void loadPlugins();
41 |
42 | Plugin(QString path);
43 | bool loaded();
44 | void regist(const QHash &);
45 | void config(QWidget *);
46 | QString string(QString query);
47 |
48 | private:
49 | RegistPtr m_regist;
50 | ConfigPtr m_config;
51 | StringPtr m_string;
52 | };
53 |
--------------------------------------------------------------------------------
/src/Render/ARender.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 Lysine.
4 | *
5 | * Filename: ARender.cpp
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 | #include "Common.h"
28 | #include "ARender.h"
29 | #include "ARenderPrivate.h"
30 | #include "../Config.h"
31 | #include "../Local.h"
32 | #include "../Utils.h"
33 | #include "../Model/Danmaku.h"
34 | #include "../Player/APlayer.h"
35 |
36 | #ifdef RENDER_RASTER
37 | #include "RasterRender/RasterRender.h"
38 | #endif
39 | #ifdef RENDER_OPENGL
40 | #include "OpenGLRender/OpenGLRender.h"
41 | #endif
42 |
43 | QStringList ARender::getModules()
44 | {
45 | QStringList modules;
46 | #ifdef RENDER_OPENGL
47 | modules << "OpenGL";
48 | #endif
49 | #ifdef RENDER_RASTER
50 | modules << "Raster";
51 | #endif
52 | return modules;
53 | }
54 |
55 | ARender *ARender::ins = nullptr;
56 |
57 | ARender *ARender::instance()
58 | {
59 | if (ins){
60 | return ins;
61 | }
62 | QString r;
63 | QStringList l = getModules();
64 | switch (l.size()){
65 | case 0:
66 | break;
67 | case 1:
68 | r = l[0];
69 | break;
70 | default:
71 | r = Config::getValue("/Performance/Render", l[0]);
72 | r = l.contains(r) ? r : l[0];
73 | break;
74 | }
75 | #ifdef RENDER_OPENGL
76 | if (r == "OpenGL"){
77 | return new OpenGLRender(qApp);
78 | }
79 | #endif
80 | #ifdef RENDER_RASTER
81 | if (r=="Raster"){
82 | return new RasterRender(qApp);
83 | }
84 | #endif
85 | return nullptr;
86 | }
87 |
88 | ARender::ARender(ARenderPrivate *data, QObject *parent) :
89 | QObject(parent), d_ptr(data)
90 | {
91 | Q_D(ARender);
92 | d->time = 0;
93 | connect(lApp, &Local::aboutToQuit, this, &ARender::deleteLater);
94 | if (Config::getValue("/Interface/Version", true)){
95 | d->tv.setFileName(":/Picture/tv.gif");
96 | d->tv.setCacheMode(QMovie::CacheAll);
97 | d->tv.start();
98 | d->me = QImage(":/Picture/version.png");
99 | connect(APlayer::instance(), &APlayer::begin, &d->tv, &QMovie::stop);
100 | connect(APlayer::instance(), &APlayer::reach, &d->tv, &QMovie::start);
101 | connect(&d->tv, &QMovie::updated, [=](){
102 | QImage cf = d->tv.currentImage();
103 | QPoint ps = QRect(QPoint(0, 0), getActualSize()).center() - cf.rect().center();
104 | ps.ry() -= 40;
105 | draw(QRect(ps, cf.size()));
106 | });
107 | }
108 | QString path = Config::getValue("/Interface/Background", QString());
109 | if (!path.isEmpty()){
110 | d->background = QImage(path);
111 | }
112 | d->sound = QImage(":/Picture/sound.png");
113 | d->music = 1;
114 | d->dirty = 0;
115 | d->videoAspectRatio = 0;
116 | d->pixelAspectRatio = 1;
117 | connect(APlayer::instance(), &APlayer::stateChanged, [d](){
118 | d->timer.invalidate();
119 | });
120 | }
121 |
122 | ARender::~ARender()
123 | {
124 | delete d_ptr;
125 | }
126 |
127 | QList ARender::getBuffer()
128 | {
129 | Q_D(ARender);
130 | return d->getBuffer();
131 | }
132 |
133 | void ARender::releaseBuffer()
134 | {
135 | Q_D(ARender);
136 | d->releaseBuffer();
137 | }
138 |
139 | void ARender::setBuffer(QString &chroma, QSize size, int alignment, QList *bufferSize)
140 | {
141 | Q_D(ARender);
142 | d->setBuffer(chroma, size, alignment, bufferSize);
143 | }
144 |
145 | void ARender::setBackground(QString path)
146 | {
147 | Q_D(ARender);
148 | d->background = QImage(path);
149 | Config::setValue("/Interface/Background", path);
150 | }
151 |
152 | void ARender::setMusic(bool music)
153 | {
154 | Q_D(ARender);
155 | d->music = music;
156 | }
157 |
158 | void ARender::setDisplayTime(double t)
159 | {
160 | Q_D(ARender);
161 | d->time = t;
162 | QSize s = getActualSize();
163 | draw(QRect(0, s.height() - 2, s.width()*d->time, 2));
164 | }
165 |
166 | void ARender::setVideoAspectRatio(double ratio)
167 | {
168 | Q_D(ARender);
169 | d->videoAspectRatio = ratio;
170 | }
171 |
172 | void ARender::setPixelAspectRatio(double ratio)
173 | {
174 | Q_D(ARender);
175 | d->pixelAspectRatio = ratio;
176 | }
177 |
178 | void ARender::draw()
179 | {
180 | QRect rect;
181 | rect.setSize(getActualSize());
182 | draw(rect);
183 | }
184 |
185 | QSize ARender::getPreferSize()
186 | {
187 | Q_D(ARender);
188 | if (d->music){
189 | return QSize();
190 | }
191 | if (d->pref.isValid()){
192 | return d->pref;
193 | }
194 | QSize s = getBufferSize();
195 | d->pixelAspectRatio > 1 ? (s.rwidth() *= d->pixelAspectRatio) : (s.rheight() /= d->pixelAspectRatio);
196 | return s;
197 | }
198 |
199 | void ARender::setPreferSize(QSize size)
200 | {
201 | Q_D(ARender);
202 | d->pref = size;
203 | }
204 |
205 | QRect ARenderPrivate::fitRect(QSize size, QRect rect)
206 | {
207 | QRect dest;
208 | QSizeF s = videoAspectRatio > 0 ? QSizeF(videoAspectRatio, 1) : QSizeF(size);
209 | dest.setSize(s.scaled(rect.size(), Qt::KeepAspectRatio).toSize() / 4 * 4);
210 | dest.moveCenter(rect.center());
211 | return dest;
212 | }
213 |
214 | void ARenderPrivate::drawPlay(QPainter *painter, QRect rect)
215 | {
216 | painter->fillRect(rect, Qt::black);
217 | if (music){
218 | painter->drawImage(rect.center() - QRect(QPoint(0, 0), sound.size()).center(), sound);
219 | }
220 | else{
221 | drawData(painter, rect);
222 | }
223 | }
224 |
225 | void ARenderPrivate::drawStop(QPainter *painter, QRect rect)
226 | {
227 | if (background.isNull()){
228 | painter->fillRect(rect, qApp->palette().color(QPalette::Window));
229 | }
230 | else{
231 | QRect dest = rect;
232 | dest.setSize(background.size().scaled(dest.size(), Qt::KeepAspectRatioByExpanding));
233 | dest.moveCenter(rect.center());
234 | painter->drawImage(dest, background);
235 | }
236 | int w = rect.width(), h = rect.height();
237 | QImage cf = tv.currentImage();
238 | painter->drawImage((w - cf.width()) / 2, (h - cf.height()) / 2 - 40, cf);
239 | painter->drawImage((w - me.width()) / 2, (h - me.height()) / 2 + 40, me);
240 | }
241 |
242 |
243 | void ARenderPrivate::drawTime(QPainter *painter, QRect rect)
244 | {
245 | if (time <= 0){
246 | return;
247 | }
248 | rect = QRect(0, rect.height() - 2, rect.width()*time, 2);
249 | QLinearGradient gradient;
250 | gradient.setStart(rect.center().x(), rect.top());
251 | gradient.setFinalStop(rect.center().x(), rect.bottom());
252 | QColor outline = qApp->palette().background().color().darker(140);
253 | QColor highlight = qApp->palette().color(QPalette::Highlight);
254 | QColor highlightedoutline = highlight.darker(140);
255 | if (qGray(outline.rgb()) > qGray(highlightedoutline.rgb())){
256 | outline = highlightedoutline;
257 | }
258 | painter->setPen(QPen(outline));
259 | gradient.setColorAt(0, highlight);
260 | gradient.setColorAt(1, highlight.lighter(130));
261 | painter->setBrush(gradient);
262 | painter->drawRect(rect);
263 | }
264 |
265 | void ARenderPrivate::drawDanm(QPainter *painter, QRect)
266 | {
267 | Danmaku::instance()->draw(painter, timer.step());
268 | }
269 |
--------------------------------------------------------------------------------
/src/Render/ARender.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 Lysine.
4 | *
5 | * Filename: ARender.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 | #pragma once
28 |
29 | #include
30 | #include
31 |
32 | class ARenderPrivate;
33 | class Comment;
34 | class ISprite;
35 |
36 | class ARender :public QObject
37 | {
38 | Q_OBJECT
39 | public:
40 | static QStringList getModules();
41 |
42 | virtual ~ARender();
43 | static ARender *instance();
44 |
45 | protected:
46 | static ARender *ins;
47 | ARenderPrivate *const d_ptr;
48 | Q_DECLARE_PRIVATE(ARender);
49 | ARender(ARenderPrivate *data, QObject *parent = 0);
50 |
51 | public slots:
52 | virtual QList getBuffer();
53 | virtual void releaseBuffer();
54 | virtual void setBuffer(QString &chroma, QSize size, int alignment, QList *bufferSize = 0);
55 |
56 | void setBackground(QString path);
57 | void setMusic(bool music);
58 | void setDisplayTime(double t);
59 | void setVideoAspectRatio(double ratio);
60 | void setPixelAspectRatio(double ratio);
61 | void draw();
62 |
63 | virtual ISprite *getSprite(const Comment &comment) = 0;
64 | virtual quintptr getHandle() = 0;
65 | virtual void resize(QSize size) = 0;
66 | virtual QSize getBufferSize() = 0;
67 | virtual QSize getActualSize() = 0;
68 | virtual QSize getPreferSize();
69 | virtual void setPreferSize(QSize size);
70 | virtual void draw(QRect rect) = 0;
71 | };
72 |
--------------------------------------------------------------------------------
/src/Render/ARenderPrivate.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include "ElapsedTimer.h"
6 |
7 | class ARenderPrivate
8 | {
9 | public:
10 | QMovie tv;
11 | double time;
12 | QImage me, background, sound;
13 | QSize pref;
14 | bool music;
15 | bool dirty;
16 | double videoAspectRatio;
17 | double pixelAspectRatio;
18 | ElapsedTimer timer;
19 |
20 | virtual ~ARenderPrivate() = default;
21 | QRect fitRect(QSize size, QRect rect);
22 | void drawPlay(QPainter *painter, QRect rect);
23 | void drawStop(QPainter *painter, QRect rect);
24 | void drawDanm(QPainter *painter, QRect rect);
25 | void drawTime(QPainter *painter, QRect rect);
26 | virtual void drawData(QPainter *painter, QRect rect) = 0;
27 | virtual QList getBuffer() = 0;
28 | virtual void releaseBuffer() = 0;
29 | virtual void setBuffer(QString &chroma, QSize size, int alignment, QList *bufferSize = 0) = 0;
30 |
31 | };
32 |
--------------------------------------------------------------------------------
/src/Render/ElapsedTimer.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class ElapsedTimer
6 | {
7 | public:
8 | ElapsedTimer()
9 | {
10 | estimate = qSNaN();
11 | interval = overflow = 0;
12 | }
13 |
14 | void setInterval(double second)
15 | {
16 | interval = second;
17 | }
18 |
19 | void invalidate()
20 | {
21 | inner.invalidate();
22 | }
23 |
24 | bool swap()
25 | {
26 | overflow = inner.isValid() ? qMax(0.0, elapsed() - estimate) : 0.0;
27 | inner.start();
28 | estimate = qSNaN();
29 | return overflow > 0;
30 | }
31 |
32 | double step()
33 | {
34 | if (inner.isValid() && qIsNaN(estimate)){
35 | estimate = qMax(interval, elapsed());
36 | return estimate + overflow;
37 | }
38 | else{
39 | return 0;
40 | }
41 | }
42 |
43 | private:
44 | double interval;
45 | double estimate;
46 | double overflow;
47 | QElapsedTimer inner;
48 |
49 | double elapsed()
50 | {
51 | return inner.nsecsElapsed() / 1000000000.0;
52 | }
53 | };
54 |
--------------------------------------------------------------------------------
/src/Render/ISprite.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | class ISprite
7 | {
8 | public:
9 | virtual void draw(QPainter *, QRectF) = 0;
10 | virtual QSize getSize() = 0;
11 | virtual ~ISprite() = default;
12 | };
13 |
--------------------------------------------------------------------------------
/src/Render/OpenGLRender/DetachPrivate.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "DetachPrivate.h"
3 | #include
4 | #include
5 |
6 | namespace
7 | {
8 | class DWindow :public QOpenGLWindow
9 | {
10 | public:
11 | explicit DWindow(OpenGLDetachRenderPrivate *render) :
12 | render(render)
13 | {
14 | QSurfaceFormat f = format();
15 | f.setAlphaBufferSize(8);
16 | setFormat(f);
17 | setFlags(flags() | Qt::Tool | Qt::FramelessWindowHint | Qt::WindowTransparentForInput | Qt::WindowStaysOnTopHint);
18 | setGeometry(lApp->desktop()->screenGeometry());
19 | connect(this, &DWindow::frameSwapped, std::bind(&OpenGLRenderPrivate::onSwapped, render));
20 | }
21 |
22 | private:
23 | OpenGLDetachRenderPrivate *const render;
24 |
25 | void initializeGL()
26 | {
27 | render->initialize();
28 | }
29 |
30 | void paintGL()
31 | {
32 | render->glClearColor(0, 0, 0, 0);
33 | render->glClear(GL_COLOR_BUFFER_BIT);
34 | QPainter painter(this);
35 | painter.setRenderHints(QPainter::SmoothPixmapTransform);
36 | QRect rect(QPoint(0, 0), ARender::instance()->getActualSize());
37 | render->drawDanm(&painter, rect);
38 | }
39 | };
40 | }
41 |
42 | OpenGLDetachRenderPrivate::OpenGLDetachRenderPrivate()
43 | {
44 | tv.disconnect();
45 | window = new DWindow(this);
46 | window->create();
47 | QObject::connect(APlayer::instance(), &APlayer::begin, window, &QWindow::show);
48 | QObject::connect(APlayer::instance(), &APlayer::reach, window, &QWindow::hide);
49 | }
50 |
--------------------------------------------------------------------------------
/src/Render/OpenGLRender/DetachPrivate.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "OpaquePrivate.h"
4 | #include "../../Local.h"
5 | #include
6 |
7 | class OpenGLDetachRenderPrivate :public OpenGLRenderPrivate
8 | {
9 | public:
10 | OpenGLDetachRenderPrivate();
11 |
12 | virtual ~OpenGLDetachRenderPrivate()
13 | {
14 | delete window;
15 | }
16 |
17 | virtual bool isVisible() override
18 | {
19 | return window->isVisible();
20 | }
21 |
22 | virtual void drawData(QPainter *, QRect) override
23 | {
24 | }
25 |
26 | virtual QList getBuffer() override
27 | {
28 | return QList();
29 | }
30 |
31 | virtual void setBuffer(QString &chroma, QSize, int, QList *) override
32 | {
33 | chroma = "NONE";
34 | }
35 |
36 | virtual void releaseBuffer() override
37 | {
38 | }
39 |
40 | virtual quintptr getHandle() override
41 | {
42 | return (quintptr)window;
43 | }
44 |
45 | virtual void resize(QSize) override
46 | {
47 | }
48 |
49 | virtual QSize getActualSize() override
50 | {
51 | return window->size();
52 | }
53 |
54 | virtual QSize getBufferSize() override
55 | {
56 | return QSize();
57 | }
58 |
59 | virtual void draw(QRect rect) override
60 | {
61 | window->update(rect);
62 | }
63 |
64 | private:
65 | QOpenGLWindow *window;
66 | };
67 |
--------------------------------------------------------------------------------
/src/Render/OpenGLRender/OpaquePrivate.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "OpenGLRenderPrivate.h"
4 | #include "../ARender.h"
5 | #include "../../Player/APlayer.h"
6 |
7 | class OpenGLOpaqueRenderPrivate :public OpenGLRenderPrivate
8 | {
9 | public:
10 | QSize inner;
11 | int format;
12 | GLuint frame[3];
13 | QMutex dataLock;
14 | QList buffer;
15 | int alignment;
16 |
17 | virtual void initialize() override
18 | {
19 | OpenGLRenderPrivate::initialize();
20 | glGenTextures(3, frame);
21 | }
22 |
23 | void loadTexture(int index, int channel, int width, int height)
24 | {
25 | OpenGLRenderPrivate::loadTexture(frame[index], channel, width, height, buffer[index], alignment);
26 | }
27 |
28 | virtual void drawData(QPainter *painter, QRect rect) override
29 | {
30 | if (inner.isEmpty()){
31 | return;
32 | }
33 | painter->beginNativePainting();
34 | if (dirty){
35 | int w = inner.width(), h = inner.height();
36 | dataLock.lock();
37 | switch (format){
38 | case 0:
39 | case 1:
40 | loadTexture(0, 1, w, h);
41 | loadTexture(1, 1, w / 2, h / 2);
42 | loadTexture(2, 1, w / 2, h / 2);
43 | break;
44 | case 2:
45 | case 3:
46 | loadTexture(0, 1, w, h);
47 | loadTexture(1, 2, w / 2, h / 2);
48 | break;
49 | case 4:
50 | loadTexture(0, 4, w, h);
51 | break;
52 | }
53 | dirty = false;
54 | dataLock.unlock();
55 | }
56 | QRect dest = fitRect(ARender::instance()->getPreferSize(), rect);
57 | drawTexture(frame, format, dest, rect);
58 | painter->endNativePainting();
59 | }
60 |
61 | void paint(QPaintDevice *device)
62 | {
63 | QPainter painter(device);
64 | painter.setRenderHints(QPainter::SmoothPixmapTransform);
65 | QRect rect(QPoint(0, 0), ARender::instance()->getActualSize());
66 | if (APlayer::instance()->getState() == APlayer::Stop){
67 | drawStop(&painter, rect);
68 | }
69 | else{
70 | drawPlay(&painter, rect);
71 | drawDanm(&painter, rect);
72 | drawTime(&painter, rect);
73 | }
74 | }
75 |
76 | virtual QList getBuffer() override
77 | {
78 | dataLock.lock();
79 | return buffer;
80 | }
81 |
82 | virtual void releaseBuffer() override
83 | {
84 | dirty = true;
85 | dataLock.unlock();
86 | }
87 |
88 | inline void align(int &size, int alignment)
89 | {
90 | --alignment;
91 | size = (size + alignment) & (~alignment);
92 | }
93 |
94 | virtual void setBuffer(QString &chroma, QSize size, int alignment, QList *bufferSize) override
95 | {
96 | if (chroma == "YV12"){
97 | format = 1;
98 | }
99 | else if (chroma == "NV12"){
100 | format = 2;
101 | }
102 | else if (chroma == "NV21"){
103 | format = 3;
104 | }
105 | else{
106 | format = 0;
107 | chroma = "I420";
108 | }
109 |
110 | inner = size;
111 |
112 | if (alignment >= 8) {
113 | alignment = 8;
114 | }
115 | else if (alignment >= 4) {
116 | alignment = 4;
117 | }
118 | else if (alignment >= 2) {
119 | alignment = 2;
120 | }
121 | else {
122 | alignment = 1;
123 | }
124 | this->alignment = alignment;
125 |
126 | QList plane;
127 | switch (format){
128 | case 0:
129 | case 1:
130 | plane.append(size);
131 | size /= 2;
132 | plane.append(size);
133 | plane.append(size);
134 | break;
135 | case 2:
136 | case 3:
137 | plane.append(size);
138 | size.rheight() /= 2;
139 | plane.append(size);
140 | break;
141 | }
142 | if (buffer.size() > 0) {
143 | delete[]buffer[0];
144 | buffer.clear();
145 | }
146 | size_t len = 0;
147 | for (QSize &s : plane){
148 | align(s.rwidth(), alignment);
149 | len += s.width() * s.height();
150 | }
151 | quint8 *buf = new quint8[len];
152 | for (QSize &s : plane) {
153 | buffer.append(buf);
154 | buf += s.width() * s.height();
155 | }
156 | if (bufferSize)
157 | bufferSize->swap(plane);
158 | }
159 |
160 | virtual QSize getBufferSize() override
161 | {
162 | return inner;
163 | }
164 |
165 | virtual ~OpenGLOpaqueRenderPrivate()
166 | {
167 | if (!buffer.isEmpty()){
168 | delete[]buffer[0];
169 | }
170 | }
171 | };
172 |
--------------------------------------------------------------------------------
/src/Render/OpenGLRender/OpenGLRender.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "OpenGLRender.h"
3 | #include "OpenGLRenderPrivate.h"
4 | #include "WidgetPrivate.h"
5 | #include "WindowPrivate.h"
6 | #include "DetachPrivate.h"
7 | #include "SyncTextureSprite.h"
8 | #include "../../Config.h"
9 | #include "../../Player/APlayer.h"
10 |
11 | namespace
12 | {
13 | OpenGLRenderPrivate *choose()
14 | {
15 | bool detach = Config::getValue("/Performance/Option/OpenGL/Detach", 0);
16 | bool buffer = Config::getValue("/Performance/Option/OpenGL/Buffer", 1);
17 | if (detach)
18 | return new OpenGLDetachRenderPrivate;
19 | else if (buffer)
20 | return new OpenGLWidgetRenderPrivate;
21 | else
22 | return new OpenGLWindowRenderPrivate;
23 | }
24 | }
25 |
26 | OpenGLRender::OpenGLRender(QObject *parent) :
27 | ARender(choose(), parent)
28 | {
29 | ins = this;
30 | setObjectName("ORender");
31 | }
32 |
33 | ISprite *OpenGLRender::getSprite(const Comment &comment)
34 | {
35 | Q_D(OpenGLRender);
36 | return new SyncTextureSprite(comment, d);
37 | }
38 |
39 | quintptr OpenGLRender::getHandle()
40 | {
41 | Q_D(OpenGLRender);
42 | return d->getHandle();
43 | }
44 |
45 | void OpenGLRender::resize(QSize size)
46 | {
47 | Q_D(OpenGLRender);
48 | d->resize(size);
49 | }
50 |
51 | QSize OpenGLRender::getActualSize()
52 | {
53 | Q_D(OpenGLRender);
54 | return d->getActualSize();
55 | }
56 |
57 | QSize OpenGLRender::getBufferSize()
58 | {
59 | Q_D(OpenGLRender);
60 | return d->getBufferSize();
61 | }
62 |
63 | void OpenGLRender::draw(QRect rect)
64 | {
65 | Q_D(OpenGLRender);
66 | d->draw(rect.isValid() ? rect : QRect(QPoint(0, 0), getActualSize()));
67 | }
68 |
69 | namespace
70 | {
71 | const char *vShaderCode =
72 | "attribute mediump vec4 VtxCoord;\n"
73 | "attribute mediump vec2 TexCoord;\n"
74 | "varying mediump vec2 TexCoordOut;\n"
75 | "void main(void)\n"
76 | "{\n"
77 | " gl_Position = VtxCoord;\n"
78 | " TexCoordOut = TexCoord;\n"
79 | "}\n";
80 |
81 | const char *fShaderI420 =
82 | "varying mediump vec2 TexCoordOut;\n"
83 | "uniform sampler2D SamplerY;\n"
84 | "uniform sampler2D SamplerU;\n"
85 | "uniform sampler2D SamplerV;\n"
86 | "void main(void)\n"
87 | "{\n"
88 | " lowp vec4 yuv;\n"
89 | " lowp vec4 rgb;\n"
90 | " yuv.r = texture2D(SamplerY, TexCoordOut).r;\n"
91 | " yuv.g = texture2D(SamplerU, TexCoordOut).r;\n"
92 | " yuv.b = texture2D(SamplerV, TexCoordOut).r;\n"
93 | " yuv.a = 1.0;\n"
94 | " rgb = mat4( 1.164, 1.164, 1.164, 0, \n"
95 | " 0, -0.391, 2.018, 0, \n"
96 | " 1.596, -0.813, 0, 0, \n"
97 | " -0.871, 0.529, -1.082, 1) * yuv;\n"
98 | " gl_FragColor = rgb;\n"
99 | "}";
100 |
101 | const char *fShaderNV12 =
102 | "varying mediump vec2 TexCoordOut;\n"
103 | "uniform sampler2D SamplerY;\n"
104 | "uniform sampler2D SamplerA;\n"
105 | "void main(void)\n"
106 | "{\n"
107 | " lowp vec4 yuv;\n"
108 | " lowp vec4 rgb;\n"
109 | " yuv.r = texture2D(SamplerY, TexCoordOut).r; \n"
110 | " yuv.gb = texture2D(SamplerA, TexCoordOut).ra;\n"
111 | " yuv.a = 1.0;\n"
112 | " rgb = mat4( 1.164, 1.164, 1.164, 0, \n"
113 | " 0, -0.391, 2.018, 0, \n"
114 | " 1.596, -0.813, 0, 0, \n"
115 | " -0.871, 0.529, -1.082, 1) * yuv;\n"
116 | " gl_FragColor = rgb;\n"
117 | "}";
118 |
119 | const char *fShaderNV21 =
120 | "varying mediump vec2 TexCoordOut;\n"
121 | "uniform sampler2D SamplerY;\n"
122 | "uniform sampler2D SamplerA;\n"
123 | "void main(void)\n"
124 | "{\n"
125 | " lowp vec4 yuv;\n"
126 | " lowp vec4 rgb;\n"
127 | " yuv.r = texture2D(SamplerY, TexCoordOut).r; \n"
128 | " yuv.gb = texture2D(SamplerA, TexCoordOut).ar;\n"
129 | " yuv.a = 1.0;\n"
130 | " rgb = mat4( 1.164, 1.164, 1.164, 0, \n"
131 | " 0, -0.391, 2.018, 0, \n"
132 | " 1.596, -0.813, 0, 0, \n"
133 | " -0.871, 0.529, -1.082, 1) * yuv;\n"
134 | " gl_FragColor = rgb;\n"
135 | "}";
136 |
137 | const char *fShaderBGRP =
138 | "varying mediump vec2 TexCoordOut;\n"
139 | "uniform sampler2D SamplerP;\n"
140 | "void main(void)\n"
141 | "{\n"
142 | " lowp vec4 p;\n"
143 | " p = texture2D(SamplerP, TexCoordOut);\n"
144 | " if (p.a != 0.0) {\n"
145 | " p.r /= p.a;\n"
146 | " p.g /= p.a;\n"
147 | " p.b /= p.a;\n"
148 | " gl_FragColor = vec4(p.b, p.g, p.r, p.a);\n"
149 | " } else {\n"
150 | " gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n"
151 | " }\n"
152 | "}";
153 | }
154 |
155 | void OpenGLRenderPrivate::initialize()
156 | {
157 | initializeOpenGLFunctions();
158 | for (int i = 0; i < 5; ++i){
159 | const char *fShaderCode = nullptr;
160 | switch (i){
161 | case 0:
162 | case 1:
163 | fShaderCode = fShaderI420;
164 | break;
165 | case 2:
166 | fShaderCode = fShaderNV12;
167 | break;
168 | case 3:
169 | fShaderCode = fShaderNV21;
170 | break;
171 | case 4:
172 | fShaderCode = fShaderBGRP;
173 | break;
174 | }
175 | QOpenGLShaderProgram &p = program[i];
176 | p.addShaderFromSourceCode(QOpenGLShader::Vertex, vShaderCode);
177 | p.addShaderFromSourceCode(QOpenGLShader::Fragment, fShaderCode);
178 | p.bindAttributeLocation("VtxCoord", 0);
179 | p.bindAttributeLocation("TexCoord", 1);
180 | p.bind();
181 | switch (i){
182 | case 0:
183 | p.setUniformValue("SamplerY", 0);
184 | p.setUniformValue("SamplerU", 1);
185 | p.setUniformValue("SamplerV", 2);
186 | break;
187 | case 1:
188 | p.setUniformValue("SamplerY", 0);
189 | p.setUniformValue("SamplerV", 1);
190 | p.setUniformValue("SamplerU", 2);
191 | break;
192 | case 2:
193 | case 3:
194 | p.setUniformValue("SamplerY", 0);
195 | p.setUniformValue("SamplerA", 1);
196 | break;
197 | case 4:
198 | p.setUniformValue("SamplerP", 0);
199 | break;
200 | }
201 | }
202 | tex[0] = 0; tex[1] = 0;
203 | tex[2] = 1; tex[3] = 0;
204 | tex[4] = 0; tex[5] = 1;
205 | tex[6] = 1; tex[7] = 1;
206 | QOpenGLContext *c = QOpenGLContext::currentContext();
207 | timer.setInterval(c->format().swapInterval() / (double)c->screen()->refreshRate());
208 | }
209 |
210 | void OpenGLRenderPrivate::loadTexture(GLuint texture, int channel, int width, int height, quint8 *data, int alignment)
211 | {
212 | int format;
213 | switch (channel){
214 | case 1:
215 | format = GL_LUMINANCE;
216 | break;
217 | case 2:
218 | format = GL_LUMINANCE_ALPHA;
219 | break;
220 | case 3:
221 | format = GL_RGB;
222 | break;
223 | case 4:
224 | format = GL_RGBA;
225 | break;
226 | default:
227 | return;
228 | }
229 | glBindTexture(GL_TEXTURE_2D, texture);
230 | glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
231 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
232 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
233 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
234 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
235 | glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
236 | }
237 |
238 | void OpenGLRenderPrivate::drawTexture(GLuint *planes, int format, QRectF dest, QRectF rect)
239 | {
240 | QOpenGLShaderProgram &p = program[format];
241 | p.bind();
242 | GLfloat h = 2 / rect.width(), v = 2 / rect.height();
243 | GLfloat l = dest.left()*h - 1, r = dest.right()*h - 1, t = 1 - dest.top()*v, b = 1 - dest.bottom()*v;
244 | vtx[0] = l; vtx[1] = t;
245 | vtx[2] = r; vtx[3] = t;
246 | vtx[4] = l; vtx[5] = b;
247 | vtx[6] = r; vtx[7] = b;
248 | p.setAttributeArray(0, vtx, 2);
249 | p.setAttributeArray(1, tex, 2);
250 | p.enableAttributeArray(0);
251 | p.enableAttributeArray(1);
252 | switch (format){
253 | case 0:
254 | case 1:
255 | glActiveTexture(GL_TEXTURE2);
256 | glBindTexture(GL_TEXTURE_2D, planes[2]);
257 | case 2:
258 | case 3:
259 | glActiveTexture(GL_TEXTURE1);
260 | glBindTexture(GL_TEXTURE_2D, planes[1]);
261 | case 4:
262 | glActiveTexture(GL_TEXTURE0);
263 | glBindTexture(GL_TEXTURE_2D, planes[0]);
264 | break;
265 | }
266 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
267 | }
268 |
269 | void OpenGLRenderPrivate::onSwapped()
270 | {
271 | if (isVisible() && APlayer::instance()->getState() == APlayer::Play){
272 | if (timer.swap()){
273 | ARender::instance()->draw();
274 | }
275 | else{
276 | QTimer::singleShot(1, ARender::instance(), SLOT(draw()));
277 | }
278 | }
279 | }
280 |
--------------------------------------------------------------------------------
/src/Render/OpenGLRender/OpenGLRender.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../ARender.h"
4 |
5 | class ISprite;
6 | class OpenGLRenderPrivate;
7 |
8 | class OpenGLRender :public ARender
9 | {
10 | public:
11 | explicit OpenGLRender(QObject *parent = 0);
12 |
13 | private:
14 | Q_DECLARE_PRIVATE(OpenGLRender);
15 |
16 | public slots:
17 | virtual ISprite *getSprite(const Comment &comment) override;
18 | virtual quintptr getHandle() override;
19 | virtual void resize(QSize size) override;
20 | virtual QSize getActualSize() override;
21 | virtual QSize getBufferSize() override;
22 | virtual void draw(QRect rect = QRect()) override;
23 | };
24 |
--------------------------------------------------------------------------------
/src/Render/OpenGLRender/OpenGLRenderPrivate.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../ARenderPrivate.h"
4 | #include
5 |
6 | class OpenGLRenderPrivate :public ARenderPrivate, public QOpenGLFunctions
7 | {
8 | public:
9 | QOpenGLShaderProgram program[5];
10 | GLfloat vtx[8];
11 | GLfloat tex[8];
12 |
13 | virtual void initialize();
14 | void loadTexture(GLuint texture, int channel, int width, int height, quint8 *data, int alignment);
15 | void drawTexture(GLuint *planes, int format, QRectF dest, QRectF rect);
16 | virtual void onSwapped();
17 | virtual bool isVisible() = 0;
18 | virtual quintptr getHandle() = 0;
19 | virtual void resize(QSize size) = 0;
20 | virtual QSize getActualSize() = 0;
21 | virtual QSize getBufferSize() = 0;
22 | virtual void draw(QRect rect) = 0;
23 | };
24 |
--------------------------------------------------------------------------------
/src/Render/OpenGLRender/SyncTextureSprite.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "SyncTextureSprite.h"
3 | #include "../ARender.h"
4 | #include "OpenGLRenderPrivate.h"
5 | #include "../../Graphic/GraphicPrivate.h"
6 | #include "../../Utils.h"
7 |
8 | SyncTextureSprite::SyncTextureSprite(const Comment &comment, OpenGLRenderPrivate *render) :
9 | texture(0), render(render)
10 | {
11 | QSize size = ARender::instance()->getActualSize();
12 | QFont font = GraphicPrivate::getFont(comment.font*GraphicPrivate::getScale(comment.mode, comment.date, size));
13 | QSize need = GraphicPrivate::getSize(comment.string, font);
14 | source = new QImage(GraphicPrivate::getCache(comment.string, comment.color, font, need, comment.isLocal()));
15 | }
16 |
17 | SyncTextureSprite::~SyncTextureSprite()
18 | {
19 | if (texture)
20 | render->glDeleteTextures(1, &texture);
21 | delete source;
22 | }
23 |
24 | void SyncTextureSprite::draw(QPainter *painter, QRectF dest)
25 | {
26 | if (!texture){
27 | render->glGenTextures(1, &texture);
28 | render->loadTexture(texture, 4, source->width(), source->height(), source->bits(), 4);
29 | delete source;
30 | source = nullptr;
31 | }
32 |
33 | painter->beginNativePainting();
34 | QRect rect(QPoint(0, 0), ARender::instance()->getActualSize());
35 | render->glEnable(GL_BLEND);
36 | render->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
37 | render->drawTexture(&texture, 4, dest, rect);
38 | painter->endNativePainting();
39 | }
40 |
41 | QSize SyncTextureSprite::getSize()
42 | {
43 | return source ? source->size() : QSize();
44 | }
45 |
--------------------------------------------------------------------------------
/src/Render/OpenGLRender/SyncTextureSprite.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../ISprite.h"
4 | #include
5 |
6 | class OpenGLRenderPrivate;
7 |
8 | class SyncTextureSprite :public ISprite
9 | {
10 | public:
11 | GLuint texture;
12 | QImage *source;
13 | OpenGLRenderPrivate *const render;
14 |
15 | SyncTextureSprite(const Comment &comment, OpenGLRenderPrivate *render);
16 | virtual ~SyncTextureSprite();
17 | void draw(QPainter *painter, QRectF dest);
18 | QSize getSize();
19 | };
20 |
--------------------------------------------------------------------------------
/src/Render/OpenGLRender/WidgetPrivate.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "WidgetPrivate.h"
3 | #include
4 |
5 | namespace
6 | {
7 | class OWidget :public QOpenGLWidget
8 | {
9 | public:
10 | explicit OWidget(OpenGLOpaqueRenderPrivate *render) :
11 | QOpenGLWidget(lApp->mainWidget()), render(render)
12 | {
13 | setAttribute(Qt::WA_TransparentForMouseEvents);
14 | lower();
15 | connect(this, &OWidget::frameSwapped, std::bind(&OpenGLRenderPrivate::onSwapped, render));
16 | }
17 |
18 | private:
19 | OpenGLOpaqueRenderPrivate *const render;
20 |
21 | void initializeGL()
22 | {
23 | render->initialize();
24 | }
25 |
26 | void paintGL()
27 | {
28 | render->paint(this);
29 | }
30 | };
31 | }
32 |
33 | OpenGLWidgetRenderPrivate::OpenGLWidgetRenderPrivate()
34 | {
35 | widget = new OWidget(this);
36 | }
37 |
--------------------------------------------------------------------------------
/src/Render/OpenGLRender/WidgetPrivate.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "OpaquePrivate.h"
4 | #include "../../Local.h"
5 | #include
6 |
7 | class OpenGLWidgetRenderPrivate :public OpenGLOpaqueRenderPrivate
8 | {
9 | public:
10 | OpenGLWidgetRenderPrivate();
11 |
12 | virtual bool isVisible() override
13 | {
14 | return widget->isVisible();
15 | }
16 |
17 | virtual quintptr getHandle() override
18 | {
19 | return (quintptr)widget;
20 | }
21 |
22 | virtual void resize(QSize size) override
23 | {
24 | widget->resize(size);
25 | }
26 |
27 | virtual QSize getActualSize() override
28 | {
29 | return widget->size();
30 | }
31 |
32 | virtual void draw(QRect rect) override
33 | {
34 | widget->update(rect);
35 | }
36 |
37 | private:
38 | QOpenGLWidget *widget;
39 | };
40 |
--------------------------------------------------------------------------------
/src/Render/OpenGLRender/WindowPrivate.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "WindowPrivate.h"
3 | #include
4 | #include
5 |
6 | namespace
7 | {
8 | class OWindow :public QOpenGLWindow
9 | {
10 | public:
11 | explicit OWindow(OpenGLOpaqueRenderPrivate *render) :
12 | render(render)
13 | {
14 | window = nullptr;
15 | QTimer::singleShot(0, [this]() {
16 | window = lApp->mainWidget()->backingStore()->window();
17 | });
18 | connect(this, &OWindow::frameSwapped, std::bind(&OpenGLRenderPrivate::onSwapped, render));
19 | }
20 |
21 | private:
22 | QWindow *window;
23 | OpenGLOpaqueRenderPrivate *const render;
24 |
25 | void initializeGL()
26 | {
27 | render->initialize();
28 | }
29 |
30 | void paintGL()
31 | {
32 | render->paint(this);
33 | }
34 |
35 | bool event(QEvent *e)
36 | {
37 | switch (e->type()) {
38 | case QEvent::KeyPress:
39 | case QEvent::KeyRelease:
40 | case QEvent::Enter:
41 | case QEvent::Leave:
42 | case QEvent::MouseMove:
43 | case QEvent::MouseButtonPress:
44 | case QEvent::MouseButtonRelease:
45 | case QEvent::MouseButtonDblClick:
46 | case QEvent::Wheel:
47 | case QEvent::DragEnter:
48 | case QEvent::DragMove:
49 | case QEvent::DragLeave:
50 | case QEvent::Drop:
51 | case QEvent::ContextMenu:
52 | return window ? qApp->sendEvent(window, e) : false;
53 | default:
54 | return QOpenGLWindow::event(e);
55 | }
56 | }
57 |
58 | };
59 |
60 | /* only QMdiSubWindow & QAbstractScrollArea
61 | will make windowcontainer to create native widgets.
62 | */
63 | class FParent :public QAbstractScrollArea
64 | {
65 | public:
66 | explicit FParent(QWidget *parent) :
67 | QAbstractScrollArea(parent)
68 | {
69 | }
70 | };
71 | }
72 |
73 | OpenGLWindowRenderPrivate::OpenGLWindowRenderPrivate()
74 | {
75 | middle = new FParent(lApp->mainWidget());
76 | middle->lower();
77 | window = new OWindow(this);
78 | widget = QWidget::createWindowContainer(window, middle);
79 | middle->setAcceptDrops(false);
80 | widget->setAcceptDrops(false);
81 | }
82 |
--------------------------------------------------------------------------------
/src/Render/OpenGLRender/WindowPrivate.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "OpaquePrivate.h"
4 | #include "../../Local.h"
5 | #include
6 | #include
7 |
8 | class OpenGLWindowRenderPrivate :public OpenGLOpaqueRenderPrivate
9 | {
10 | public:
11 | OpenGLWindowRenderPrivate();
12 |
13 | virtual bool isVisible() override
14 | {
15 | return widget->isVisible();
16 | }
17 |
18 | virtual quintptr getHandle() override
19 | {
20 | return (quintptr)window;
21 | }
22 |
23 | virtual void resize(QSize size) override
24 | {
25 | middle->resize(size);
26 | widget->resize(size);
27 | }
28 |
29 | virtual QSize getActualSize() override
30 | {
31 | return widget->size();
32 | }
33 |
34 | virtual void draw(QRect rect) override
35 | {
36 | window->update(rect);
37 | }
38 |
39 | private:
40 | QWidget *widget;
41 | QWidget *middle;
42 | QOpenGLWindow *window;
43 | };
44 |
--------------------------------------------------------------------------------
/src/Render/RasterRender/AsyncRasterSprite.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../ISprite.h"
4 | #include "../ARender.h"
5 | #include "../../Graphic/GraphicPrivate.h"
6 | #include
7 | #include
8 |
9 | class AsyncRasterSprite :public ISprite
10 | {
11 | public:
12 | QImage image;
13 |
14 | explicit AsyncRasterSprite(const Comment &comment)
15 | {
16 | QSize size = ARender::instance()->getActualSize();
17 | QFont font = GraphicPrivate::getFont(comment.font*GraphicPrivate::getScale(comment.mode, comment.date, size));
18 | QSize need = GraphicPrivate::getSize(comment.string, font);
19 | image = GraphicPrivate::getCache(comment.string, comment.color, font, need, comment.isLocal());
20 | }
21 |
22 | void draw(QPainter *painter, QRectF dest)
23 | {
24 | painter->drawImage(dest, image);
25 | }
26 |
27 | QSize getSize()
28 | {
29 | return image.size();
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/src/Render/RasterRender/RasterRender.cpp:
--------------------------------------------------------------------------------
1 | #include "Common.h"
2 | #include "RasterRender.h"
3 | #include "RasterRenderPrivate.h"
4 | #include "AsyncRasterSprite.h"
5 | #include "../../Config.h"
6 | #include "../../Local.h"
7 | #include "../../Player/APlayer.h"
8 |
9 | RasterRender::RasterRender(QObject *parent) :
10 | ARender(new RasterRenderPrivate, parent)
11 | {
12 | Q_D(RasterRender);
13 | ins = this;
14 | setObjectName("RRender");
15 | d->power = new QTimer(this);
16 | d->power->setTimerType(Qt::PreciseTimer);
17 | int fps = Config::getValue("/Performance/Option/Raster/Update", 100);
18 | d->power->start(1000 / (fps > 0 ? fps : 60));
19 | connect(APlayer::instance(), &APlayer::decode, d->power, [=](){
20 | if (!d->power->isActive()){
21 | draw();
22 | }
23 | });
24 | connect(d->power, &QTimer::timeout, APlayer::instance(), [=](){
25 | if (APlayer::instance()->getState() == APlayer::Play){
26 | draw();
27 | }
28 | });
29 | d->widget = new RasterRenderPrivate::Widget(d);
30 | }
31 |
32 | ISprite *RasterRender::getSprite(const Comment &comment)
33 | {
34 | return new AsyncRasterSprite(comment);
35 | }
36 |
37 | quintptr RasterRender::getHandle()
38 | {
39 | Q_D(RasterRender);
40 | return (quintptr)d->widget;
41 | }
42 |
43 | void RasterRender::resize(QSize size)
44 | {
45 | Q_D(RasterRender);
46 | d->widget->resize(size);
47 | }
48 |
49 | QSize RasterRender::getActualSize()
50 | {
51 | Q_D(RasterRender);
52 | return d->widget->size();
53 | }
54 |
55 | QSize RasterRender::getBufferSize()
56 | {
57 | Q_D(RasterRender);
58 | return d->srcFrame->size;
59 | }
60 |
61 | void RasterRender::draw(QRect rect)
62 | {
63 | Q_D(RasterRender);
64 | d->widget->update(rect.isValid() ? rect : QRect(QPoint(0, 0), getActualSize()));
65 | }
66 |
67 | RasterRenderPrivate::Buffer::Buffer(AVPixelFormat format, QSize size, int alignment) :
68 | format(AV_PIX_FMT_NONE), size(size)
69 | {
70 | int len = av_image_alloc(data, width, size.width(), size.height(), format, alignment);
71 | if (len < 0 || data[0] == nullptr) {
72 | return;
73 | }
74 | size_t i = 0;
75 | for (; i < 3; ++i) {
76 | quint8 *ptr = data[i + 1];
77 | if (ptr == nullptr) {
78 | break;
79 | }
80 | int num = ptr - data[i];
81 | if (num == 0) {
82 | continue;
83 | }
84 | lines[i] = num / width[i];
85 | len -= num;
86 | }
87 | lines[i] = len / width[i];
88 | ++i;
89 | for (; i < 4; ++i) {
90 | lines[i] = 0;
91 | }
92 | this->format = format;
93 | }
94 |
95 | RasterRenderPrivate::Buffer::~Buffer()
96 | {
97 | if (isValid()) {
98 | av_freep(&data[0]);
99 | }
100 | }
101 |
102 | bool RasterRenderPrivate::Buffer::isValid()
103 | {
104 | return format != AV_PIX_FMT_NONE;
105 | }
106 |
107 | RasterRenderPrivate::Widget::Widget(RasterRenderPrivate *render) :
108 | QWidget(lApp->mainWidget()), render(render)
109 | {
110 | setAttribute(Qt::WA_TransparentForMouseEvents);
111 | lower();
112 | }
113 |
114 | void RasterRenderPrivate::Widget::paintEvent(QPaintEvent *)
115 | {
116 | QPainter painter(this);
117 | QRect rect(QPoint(0, 0), ARender::instance()->getActualSize());
118 | painter.setRenderHints(QPainter::SmoothPixmapTransform);
119 | if (APlayer::instance()->getState() == APlayer::Stop){
120 | render->drawStop(&painter, rect);
121 | }
122 | else{
123 | render->drawPlay(&painter, rect);
124 | render->drawTime(&painter, rect);
125 | render->drawDanm(&painter, rect);
126 | render->timer.swap();
127 | }
128 | }
129 |
130 | RasterRenderPrivate::RasterRenderPrivate()
131 | {
132 | swsctx = nullptr;
133 | srcFrame = nullptr;
134 | dstFrame = nullptr;
135 | }
136 |
137 | AVPixelFormat RasterRenderPrivate::getFormat(QString &chroma)
138 | {
139 | static QHash f;
140 | if (f.isEmpty()){
141 | f.insert("RV32", AV_PIX_FMT_RGB32);
142 | f.insert("RV24", AV_PIX_FMT_RGB24);
143 | f.insert("RGB8", AV_PIX_FMT_RGB8);
144 | f.insert("RV12", AV_PIX_FMT_RGB444);
145 | f.insert("RV15", AV_PIX_FMT_RGB555);
146 | f.insert("RV16", AV_PIX_FMT_RGB565);
147 | f.insert("RGBA", AV_PIX_FMT_RGBA);
148 | f.insert("ARGB", AV_PIX_FMT_ARGB);
149 | f.insert("BGRA", AV_PIX_FMT_BGRA);
150 | f.insert("I410", AV_PIX_FMT_YUV410P);
151 | f.insert("I411", AV_PIX_FMT_YUV411P);
152 | f.insert("I420", AV_PIX_FMT_YUV420P);
153 | f.insert("IYUV", AV_PIX_FMT_YUV420P);
154 | f.insert("I422", AV_PIX_FMT_YUV422P);
155 | f.insert("I440", AV_PIX_FMT_YUV440P);
156 | f.insert("I444", AV_PIX_FMT_YUV444P);
157 | f.insert("J420", AV_PIX_FMT_YUVJ420P);
158 | f.insert("J422", AV_PIX_FMT_YUVJ422P);
159 | f.insert("J440", AV_PIX_FMT_YUVJ440P);
160 | f.insert("J444", AV_PIX_FMT_YUVJ444P);
161 | f.insert("I40A", AV_PIX_FMT_YUVA420P);
162 | f.insert("I42A", AV_PIX_FMT_YUVA422P);
163 | f.insert("YUVA", AV_PIX_FMT_YUVA444P);
164 | f.insert("YA0L", AV_PIX_FMT_YUVA444P10LE);
165 | f.insert("YA0B", AV_PIX_FMT_YUVA444P10BE);
166 | f.insert("NV12", AV_PIX_FMT_NV12);
167 | f.insert("NV21", AV_PIX_FMT_NV21);
168 | f.insert("I09L", AV_PIX_FMT_YUV420P9LE);
169 | f.insert("I09B", AV_PIX_FMT_YUV420P9BE);
170 | f.insert("I29L", AV_PIX_FMT_YUV422P9LE);
171 | f.insert("I29B", AV_PIX_FMT_YUV422P9BE);
172 | f.insert("I49L", AV_PIX_FMT_YUV444P9LE);
173 | f.insert("I49B", AV_PIX_FMT_YUV444P9BE);
174 | f.insert("I0AL", AV_PIX_FMT_YUV420P10LE);
175 | f.insert("I0AB", AV_PIX_FMT_YUV420P10BE);
176 | f.insert("I2AL", AV_PIX_FMT_YUV422P10LE);
177 | f.insert("I2AB", AV_PIX_FMT_YUV422P10BE);
178 | f.insert("I4AL", AV_PIX_FMT_YUV444P10LE);
179 | f.insert("I4AB", AV_PIX_FMT_YUV444P10BE);
180 | f.insert("UYVY", AV_PIX_FMT_UYVY422);
181 | f.insert("YUYV", AV_PIX_FMT_YUYV422);
182 | f.insert("YUY2", AV_PIX_FMT_YUYV422);
183 | }
184 | chroma = chroma.toUpper();
185 | if (f.contains(chroma)){
186 | }
187 | else if (chroma == "YV12"){
188 | chroma = "I420";
189 | }
190 | else if (chroma == "NV16"){
191 | chroma = "NV12";
192 | }
193 | else if (chroma == "NV61"){
194 | chroma = "NV21";
195 | }
196 | else if (chroma == "VYUY" ||
197 | chroma == "YVYU" ||
198 | chroma == "V422" ||
199 | chroma == "CYUV"){
200 | chroma = "UYVY";
201 | }
202 | else if (chroma == "V210"){
203 | chroma = "I0AL";
204 | }
205 | else{
206 | chroma = "I420";
207 | }
208 | return f[chroma];
209 | }
210 |
211 | void RasterRenderPrivate::drawData(QPainter *painter, QRect rect)
212 | {
213 | if (!srcFrame->isValid()){
214 | return;
215 | }
216 | QRect dest = fitRect(ARender::instance()->getPreferSize(), rect);
217 | QSize dstSize = dest.size()*painter->device()->devicePixelRatio();
218 | if (!dstFrame || dstFrame->size != dstSize){
219 | delete dstFrame;
220 | dstFrame = new Buffer(AV_PIX_FMT_RGB32, dstSize, 4);
221 | frame = QImage(*dstFrame->data, dstSize.width(), dstSize.height(), QImage::Format_RGB32);
222 | dirty = true;
223 | }
224 | if (dirty){
225 | swsctx = sws_getCachedContext(swsctx,
226 | srcFrame->size.width(), srcFrame->size.height(), srcFrame->format,
227 | dstFrame->size.width(), dstFrame->size.height(), dstFrame->format,
228 | SWS_FAST_BILINEAR, NULL, NULL, NULL);
229 | dataLock.lock();
230 | sws_scale(swsctx,
231 | srcFrame->data, srcFrame->width,
232 | 0, srcFrame->size.height(),
233 | dstFrame->data, dstFrame->width);
234 | dirty = false;
235 | dataLock.unlock();
236 | }
237 | painter->drawImage(dest, frame);
238 | }
239 |
240 | QList RasterRenderPrivate::getBuffer()
241 | {
242 | dataLock.lock();
243 | QList p;
244 | for (int i = 0; i < 4; ++i){
245 | if (srcFrame->width[i] == 0){
246 | break;
247 | }
248 | p.append(srcFrame->data[i]);
249 | }
250 | return p;
251 | }
252 |
253 | void RasterRenderPrivate::setBuffer(QString &chroma, QSize size, int alignment, QList *bufferSize)
254 | {
255 | delete srcFrame;
256 | srcFrame = new Buffer(getFormat(chroma), size, alignment);
257 | if (bufferSize){
258 | bufferSize->clear();
259 | }
260 | for (size_t i = 0; i < 4; ++i){
261 | int l = srcFrame->width[i];
262 | if (l == 0){
263 | break;
264 | }
265 | if (bufferSize){
266 | bufferSize->append(QSize(srcFrame->width[i], srcFrame->lines[i]));
267 | }
268 | }
269 | }
270 |
271 | void RasterRenderPrivate::releaseBuffer()
272 | {
273 | dirty = true;
274 | dataLock.unlock();
275 | }
276 |
277 | RasterRenderPrivate::~RasterRenderPrivate()
278 | {
279 | sws_freeContext(swsctx);
280 | delete srcFrame;
281 | delete dstFrame;
282 | }
283 |
--------------------------------------------------------------------------------
/src/Render/RasterRender/RasterRender.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../ARender.h"
4 |
5 | class ISprite;
6 | class RasterRenderPrivate;
7 |
8 | class RasterRender :public ARender
9 | {
10 | public:
11 | explicit RasterRender(QObject *parent = 0);
12 |
13 | private:
14 | Q_DECLARE_PRIVATE(RasterRender);
15 |
16 | public slots:
17 | virtual ISprite *getSprite(const Comment &comment) override;
18 | virtual quintptr getHandle() override;
19 | virtual void resize(QSize size) override;
20 | virtual QSize getActualSize() override;
21 | virtual QSize getBufferSize() override;
22 | virtual void draw(QRect rect = QRect()) override;
23 | };
24 |
--------------------------------------------------------------------------------
/src/Render/RasterRender/RasterRenderPrivate.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Common.h"
4 | #include "../ARenderPrivate.h"
5 | #include
6 |
7 | extern "C"
8 | {
9 | #include
10 | #include
11 | }
12 |
13 | class RasterRenderPrivate :public ARenderPrivate
14 | {
15 | public:
16 | class Buffer
17 | {
18 | public:
19 | quint8 *data[4];
20 | qint32 width[4];
21 | qint32 lines[4];
22 | AVPixelFormat format;
23 | QSize size;
24 |
25 | Buffer(AVPixelFormat format, QSize size, int alignment);
26 | ~Buffer();
27 | bool isValid();
28 | };
29 |
30 |
31 | class Widget :public QWidget
32 | {
33 | public:
34 | explicit Widget(RasterRenderPrivate *render);
35 |
36 | private:
37 | RasterRenderPrivate *const render;
38 |
39 | virtual void paintEvent(QPaintEvent *e) override;
40 | };
41 |
42 | QTimer *power;
43 | SwsContext *swsctx;
44 | Buffer *srcFrame;
45 | Buffer *dstFrame;
46 | Widget *widget;
47 | QImage frame;
48 | QMutex dataLock;
49 |
50 | RasterRenderPrivate();
51 | AVPixelFormat getFormat(QString &chroma);
52 | virtual void drawData(QPainter *painter, QRect rect) override;
53 | virtual QList getBuffer() override;
54 | virtual void setBuffer(QString &chroma, QSize size, int alignment, QList *bufferSize) override;
55 | virtual void releaseBuffer() override;
56 | virtual ~RasterRenderPrivate();
57 | };
58 |
--------------------------------------------------------------------------------
/src/UI/Editor.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 | #pragma once
28 |
29 | #include
30 | #include
31 | #include
32 | #include
33 |
34 | namespace UI
35 | {
36 | class Editor :public QDialog
37 | {
38 | Q_OBJECT
39 | public:
40 | enum Show
41 | {
42 | List = 0x1,
43 | Pool = 0x2,
44 | All = List | Pool
45 | };
46 |
47 | static void exec(QWidget *parent = 0, int show = All);
48 |
49 | private:
50 | QWidget *list;
51 | QWidget *pool;
52 | explicit Editor(QWidget *parent = 0);
53 | };
54 | }
55 |
--------------------------------------------------------------------------------
/src/UI/Info.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 | #pragma once
29 |
30 | #include
31 | #include
32 |
33 | namespace UI
34 | {
35 | class Info :public QWidget
36 | {
37 | Q_OBJECT
38 | public:
39 | explicit Info(QWidget *parent = 0);
40 |
41 | bool isShown()
42 | {
43 | return isPoped;
44 | }
45 |
46 | bool preferStay()
47 | {
48 | return isStay;
49 | }
50 |
51 | private:
52 | bool isStay;
53 | bool isPoped;
54 | bool updating;
55 | qint64 duration;
56 |
57 | QLabel *duraT;
58 | QLabel *timeT;
59 | QLabel *volmT;
60 | QLabel *plfmT;
61 | QSlider *timeS;
62 | QSlider *volmS;
63 | QLineEdit *plfmL;
64 | QTableView *danmV;
65 | QPushButton *playB;
66 | QPushButton *stopB;
67 | QAction *playA;
68 | QAction *stopA;
69 | QIcon playI, stopI, pausI;
70 | QPropertyAnimation *animation;
71 | void resizeEvent(QResizeEvent *e);
72 | void setTime(qint64 _time);
73 | void setDuration(qint64 _duration);
74 |
75 | public slots:
76 | void pop();
77 | void push(bool force = false);
78 | void terminate();
79 | void resizeHeader();
80 | };
81 | }
82 |
--------------------------------------------------------------------------------
/src/UI/Interface.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 | #pragma once
29 |
30 | #include
31 | #include
32 | #include
33 | #include
34 |
35 | class List;
36 | class Load;
37 | class Post;
38 | class Seek;
39 | class Sign;
40 | class APlayer;
41 | class Danmaku;
42 | class ARender;
43 |
44 | namespace UI
45 | {
46 | class Menu;
47 | class Info;
48 | class Jump;
49 | class Type;
50 | class Search;
51 | }
52 |
53 | class Interface :public QWidget
54 | {
55 | Q_OBJECT
56 | public:
57 | explicit Interface(QWidget *parent = 0);
58 | static Interface *ins;
59 | static Interface *instance();
60 |
61 | private:
62 | QTimer *timer;
63 | QTimer *delay;
64 |
65 | QAction *quitA;
66 | QAction *fullA;
67 | QAction *confA;
68 | QAction *toggA;
69 | QAction *listA;
70 | QAction *postA;
71 | QMenu *rat;
72 | QMenu *sca;
73 | QMenu *spd;
74 | QPointer msg;
75 |
76 | UI::Menu *menu;
77 | UI::Info *info;
78 | UI::Jump *jump;
79 | UI::Type *type;
80 | List *list;
81 | Load *load;
82 | Post *post;
83 | Seek *seek;
84 | Sign *sign;
85 | UI::Search *search;
86 | APlayer *aplayer;
87 | Danmaku *danmaku;
88 | ARender *arender;
89 |
90 | QPoint sta;
91 | QPoint wgd;
92 | QByteArray geo;
93 |
94 | bool showprg;
95 | bool sliding;
96 | bool twiceFlag;
97 |
98 | virtual void closeEvent(QCloseEvent *e) override;
99 | virtual void dragEnterEvent(QDragEnterEvent *e) override;
100 | virtual void dropEvent(QDropEvent *e) override;
101 | virtual void mouseDoubleClickEvent(QMouseEvent *e) override;
102 | virtual void mouseMoveEvent(QMouseEvent *e) override;
103 | virtual void mousePressEvent(QMouseEvent *e) override;
104 | virtual void mouseReleaseEvent(QMouseEvent *e) override;
105 | virtual void resizeEvent(QResizeEvent *e) override;
106 |
107 | signals:
108 | void windowFlagsChanged(QFlags);
109 |
110 | public slots:
111 | void tryLocal(QString path);
112 | void tryLocal(QStringList paths);
113 | void setWindowFlags();
114 | void percent(double degree);
115 | void warning(QString title, QString text);
116 |
117 | private slots:
118 | void checkForUpdate();
119 | void setCenter(QSize s, bool f);
120 | void showContextMenu(QPoint p);
121 | };
122 |
--------------------------------------------------------------------------------
/src/UI/Jump.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 "Common.h"
28 | #include "Jump.h"
29 | #include "../Local.h"
30 | #include "../Model/List.h"
31 | #include "../Player/APlayer.h"
32 |
33 | using namespace UI;
34 |
35 | Jump::Jump(QWidget *parent) :
36 | QWidget(parent)
37 | {
38 | setObjectName("Jump");
39 | setFixedSize(parent->minimumWidth(), 25);
40 |
41 | auto layout = new QHBoxLayout(this);
42 | layout->setMargin(0); layout->setSpacing(0);
43 |
44 | fileL = new QLineEdit(this);
45 | fileL->setReadOnly(true);
46 | fileL->setFocusPolicy(Qt::NoFocus);
47 | layout->addWidget(fileL);
48 |
49 | jumpB = new QPushButton(this);
50 | jumpB->setFixedWidth(55);
51 | connect(jumpB, &QPushButton::clicked, [this](){
52 | QStandardItem *c = List::instance()->getCurrent();
53 | APlayer::instance()->setTime(c->data(List::TimeRole).toDouble());
54 | hide();
55 | });
56 | layout->addWidget(jumpB);
57 |
58 | connect(APlayer::instance(), &APlayer::begin, [this](){
59 | QStandardItem *c = List::instance()->getCurrent();
60 | if (!c){
61 | return;
62 | }
63 | qint64 t = c->data(List::TimeRole).toDouble() / 1000;
64 | if (t <= 0){
65 | return;
66 | }
67 | fileL->setText(c->text());
68 | QString time("%1:%2");
69 | time = time.arg(t / 60, 2, 10, QChar('0'));
70 | time = time.arg(t % 60, 2, 10, QChar('0'));
71 | jumpB->setText(time);
72 | show();
73 | });
74 | hide();
75 | }
76 |
--------------------------------------------------------------------------------
/src/UI/Jump.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 | #pragma once
28 |
29 | #include
30 | #include
31 |
32 | namespace UI
33 | {
34 | class Jump :public QWidget
35 | {
36 | Q_OBJECT
37 | public:
38 | explicit Jump(QWidget *parent);
39 |
40 | private:
41 | QLineEdit * fileL;
42 | QPushButton * jumpB;
43 | };
44 | }
45 |
--------------------------------------------------------------------------------
/src/UI/Menu.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 | #pragma once
29 |
30 | #include
31 | #include
32 |
33 | namespace UI
34 | {
35 | class Menu :public QWidget
36 | {
37 | Q_OBJECT
38 | public:
39 | explicit Menu(QWidget *parent = 0);
40 |
41 | bool isShown()
42 | {
43 | return isPoped;
44 | }
45 |
46 | bool preferStay()
47 | {
48 | return isStay || !danmC->popup()->isHidden();
49 | }
50 |
51 | private:
52 | bool isStay;
53 | bool isPoped;
54 | QLineEdit *fileL;
55 | QLineEdit *pathL;
56 | QLineEdit *danmL;
57 | QLineEdit *sechL;
58 | QCompleter *fileC;
59 | QCompleter *danmC;
60 | QPushButton *fileB;
61 | QPushButton *danmB;
62 | QPushButton *sechB;
63 | QAction *fileA;
64 | QAction *danmA;
65 | QAction *sechA;
66 | QLabel *alphaT;
67 | QSlider *alphaS;
68 | QLabel *delayT;
69 | QLineEdit *delayL;
70 | QLabel *localT;
71 | QCheckBox *localC;
72 | QLabel *localFileT;
73 | QCheckBox *localFileC;
74 | QLabel *subT;
75 | QCheckBox *subC;
76 | QLabel *loopT;
77 | QCheckBox *loopC;
78 | QPropertyAnimation *animation;
79 | void resizeEvent(QResizeEvent *e);
80 | bool eventFilter(QObject *o, QEvent *e);
81 |
82 | public slots:
83 | void pop();
84 | void push(bool force = false);
85 | void terminate();
86 |
87 | };
88 | }
89 |
--------------------------------------------------------------------------------
/src/UI/Prefer.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 Lysine.
4 | *
5 | * Filename: Preference.h
6 | * Time: 2015/05/13
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 | #pragma once
28 |
29 | #include
30 | #include
31 | #include
32 |
33 | namespace UI
34 | {
35 | class Prefer :public QDialog
36 | {
37 | Q_OBJECT
38 | public:
39 | static void exec(QWidget *parent = 0, int index = 0);
40 |
41 | private:
42 | QTabWidget *tab;
43 | QWidget *widget[9];
44 |
45 | //Playing
46 | QGroupBox *box[7];
47 | QCheckBox *load[4];
48 | QCheckBox *fitted[2];
49 | QLineEdit *factor;
50 | QCheckBox *bold;
51 | QComboBox *dmfont;
52 | QComboBox *effect;
53 | QLineEdit *play[2];
54 |
55 | //Interface
56 | QGroupBox *ui[8];
57 | QComboBox *font;
58 | QComboBox *reop;
59 | QCheckBox *vers;
60 | QCheckBox *sens;
61 | QCheckBox *less;
62 | QCheckBox *upda;
63 | QComboBox *loca;
64 | QComboBox *stay;
65 | QLineEdit *jump;
66 | QLineEdit *size;
67 | QLineEdit *back;
68 | QPushButton *open;
69 |
70 | //Performance
71 | QGroupBox *opt[2];
72 | QComboBox *render;
73 | QComboBox *decode;
74 | QMultiMap option;
75 | QLabel *retext;
76 | QLabel *detext;
77 | QList relogo;
78 | QList delogo;
79 |
80 | //Shiled
81 | QLineEdit *edit;
82 | QCheckBox *check[8];
83 | QComboBox *type;
84 | QListView *regexp;
85 | QListView *sender;
86 | QStringListModel *rm;
87 | QStringListModel *sm;
88 | QAction *action[4];
89 | QPushButton *button[2];
90 | QSlider *same;
91 | QLineEdit *limit;
92 | QGroupBox *label[2];
93 |
94 | //Network
95 | QComboBox *sites;
96 | QLineEdit *sheet[3];
97 | QPushButton *click;
98 | QLabel *info;
99 | QGroupBox *login;
100 | QLabel *text;
101 | QPushButton *clear;
102 | QGroupBox *cache;
103 | QComboBox *arg;
104 | QLineEdit *input[4];
105 | QGroupBox *proxy;
106 |
107 | //Shortcut
108 | QTreeWidget *hotkey;
109 |
110 | //Plugin
111 | QTreeWidget *plugin;
112 |
113 | //Thanks
114 | QTextEdit *thanks;
115 |
116 | //License
117 | QTextEdit *license;
118 |
119 | //Shared
120 | QNetworkAccessManager *manager;
121 | QHash restart;
122 | QHash reparse;
123 |
124 | explicit Prefer(QWidget *parent = 0);
125 | QHash getRestart();
126 | QHash getReparse();
127 | void fillPicture(QLabel *label, QString url, QString error, QSize limit);
128 | QString getLogo(QString name);
129 | };
130 | }
131 |
--------------------------------------------------------------------------------
/src/UI/Search.cpp:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 Lysine.
4 | *
5 | * Filename: Search.cpp
6 | * Time: 2013/04/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 | #include "Common.h"
29 | #include "Search.h"
30 | #include "../Access/Seek.h"
31 | #include "../Utils.h"
32 | #include "../Local.h"
33 |
34 | using namespace UI;
35 |
36 | Search* Search::ins = nullptr;
37 |
38 | Search* Search::instance() {
39 | return ins ? ins : new Search(lApp->mainWidget());
40 | }
41 |
42 | Search::Search(QWidget *parent) : QDialog(parent)
43 | {
44 | ins = this;
45 | isWaiting = false;
46 | pageNum = pageCur = -1;
47 | /*
48 | *
49 | * !!!!! resultM is a child of Search Dialog
50 | * When Dialog is destroyed, all its child will be destroyed
51 | * From Menu.cpp, Search Dialog is living in the block of trigger function
52 | *
53 | */
54 | resultM = new QStandardItemModel(this);
55 | double x = logicalDpiX() / 72.0, y = logicalDpiY() / 72.0;
56 | auto outerLayout = new QVBoxLayout;
57 |
58 | //Head
59 | auto keywdLayout = new QHBoxLayout;
60 | keywE = new QLineEdit(this);
61 | keywdLayout->addWidget(keywE);
62 |
63 | orderC = new QComboBox(this);
64 | sitesC = new QComboBox(this);
65 | sitesC->addItems(Seek::instance()->modules());
66 | sitesC->setEditable(false);
67 | orderC->setEditable(false);
68 | orderC->setFixedWidth(60 * x);
69 | sitesC->setFixedWidth(60 * x);
70 | connect(orderC, &QComboBox::currentTextChanged, [this](){
71 | if (!isWaiting && resultM->rowCount()){
72 | startSearch();
73 | }
74 | });
75 | connect(sitesC, &QComboBox::currentTextChanged, [this](QString site){
76 | orderC->clear();
77 | orderC->addItems(Seek::instance()->getProc(site)->sort);
78 | if (!isWaiting && resultM->rowCount()){
79 | startSearch();
80 | }
81 | });
82 | sitesC->currentTextChanged(sitesC->currentText());
83 | keywdLayout->addWidget(orderC);
84 | keywdLayout->addWidget(sitesC);
85 |
86 | searchB = new QPushButton(this);
87 | searchB->setText(tr("Search"));
88 | connect(searchB, &QPushButton::clicked, [this](){
89 | if (isWaiting){
90 | QMessageBox::warning(this, tr("Warning"), tr("A request is pending."));
91 | return;
92 | }
93 | clearSearch();
94 | pageCur = 1;
95 | startSearch();
96 | });
97 | keywdLayout->addWidget(searchB);
98 | outerLayout->addLayout(keywdLayout);
99 |
100 | //Body
101 | resultV = new QTreeView(this);
102 | resultV->setIconSize(QSize(90 * x, 67.5*y));
103 | resultV->setModel(resultM);
104 | resultV->setSelectionMode(QAbstractItemView::SingleSelection);
105 | resultV->setIndentation(0);
106 | resultV->header()->setStretchLastSection(false);
107 | connect(resultV, &QTreeView::activated, this, &Search::accept);
108 | outerLayout->addWidget(resultV);
109 |
110 | //Tail
111 | auto pageLayout = new QHBoxLayout;
112 | statusL = new QLabel(tr("Ready"), this);
113 | pageLayout->addWidget(statusL);
114 | pageLayout->addStretch();
115 |
116 | pageT = new QLabel(tr("Page"), this);
117 | pageLayout->addWidget(pageT);
118 |
119 | pageE = new QLineEdit(this);
120 | pageE->setFixedWidth(30 * x);
121 | pageLayout->addWidget(pageE);
122 |
123 | pageL = new QLabel(this);
124 | pageL->setFixedWidth(30 * x);
125 | pageLayout->addWidget(pageL);
126 |
127 | pageGoB = new QPushButton(tr("Goto"), this);
128 | pageUpB = new QPushButton(tr("PgUp"), this);
129 | pageDnB = new QPushButton(tr("PgDn"), this);
130 | pageLayout->addWidget(pageGoB);
131 | pageLayout->addWidget(pageUpB);
132 | pageLayout->addWidget(pageDnB);
133 |
134 | auto jump = [this](int page){
135 | if (pageNum == -1) {
136 | QMessageBox::warning(this, tr("Warning"), tr("No search in progress."));
137 | }
138 | else if (isWaiting) {
139 | QMessageBox::warning(this, tr("Warning"), tr("A request is pending."));
140 | }
141 | else if (page < 1 || page > pageNum) {
142 | QMessageBox::warning(this, tr("Warning"), tr("Page num out of range."));
143 | }
144 | else{
145 | pageCur = page;
146 | startSearch();
147 | }
148 | };
149 |
150 | connect(pageGoB, &QPushButton::clicked, [jump, this](){jump(pageE->text().toInt()); });
151 | connect(pageUpB, &QPushButton::clicked, [jump, this](){jump(pageCur - 1); });
152 | connect(pageDnB, &QPushButton::clicked, [jump, this](){jump(pageCur + 1); });
153 | outerLayout->addLayout(pageLayout);
154 |
155 | auto responseLayout = new QHBoxLayout;
156 | okB = new QPushButton(tr("Confirm"), this);
157 | ccB = new QPushButton(tr("Cancel"), this);
158 | connect(okB, &QPushButton::clicked, this, &Search::accept);
159 | connect(ccB, &QPushButton::clicked, this, &Search::reject);
160 | responseLayout->addWidget(okB);
161 | responseLayout->addStretch();
162 | responseLayout->addWidget(ccB);
163 | outerLayout->addLayout(responseLayout);
164 |
165 | connect(Seek::instance(), &Seek::stateChanged, this, [=](int code){
166 | switch (code){
167 | case Seek::List:
168 | isWaiting = 1;
169 | statusL->setText(tr("Requesting"));
170 | break;
171 | case Seek::None:
172 | statusL->setText(tr("Finished"));
173 | case Seek::Data:
174 | isWaiting = 0;
175 | resultV->expandAll();
176 | case Seek::More:
177 | pageNum = Seek::instance()->getHead()->page.second;
178 | pageE->setText(QString::number(pageCur));
179 | pageL->setText(QString("/%1").arg(pageNum));
180 | resultV->setColumnWidth(0, resultV->iconSize().width() + 6);
181 | for (int i = 0;; ++i){
182 | QStandardItem *h = resultM->horizontalHeaderItem(i);
183 | if (!h){
184 | break;
185 | }
186 | switch (int s = h->data(Qt::UserRole).toInt())
187 | {
188 | case -1:
189 | resultV->setColumnWidth(i, resultV->iconSize().width() + 6);
190 | break;
191 | case 0:
192 | resultV->header()->setSectionResizeMode(i, QHeaderView::Stretch);
193 | break;
194 | default:
195 | resultV->setColumnWidth(i, s * x);
196 | break;
197 | }
198 | }
199 | break;
200 | }
201 | });
202 | connect(Seek::instance(), &Seek::errorOccured, this, [=](){
203 | clearSearch();
204 | isWaiting = false;
205 | });
206 | connect(this, &QWidget::destroyed, Seek::instance(), []()
207 | {
208 | if (Seek::instance()->getHead()){
209 | Seek::instance()->dequeue();
210 | }
211 | });
212 |
213 | setLayout(outerLayout);
214 | setWindowTitle(tr("Search"));
215 | setMinimumSize(450 * x, 300 * y);
216 | resize(675 * x, 390 * y);
217 | Utils::setCenter(this);
218 | }
219 |
220 | Search::~Search()
221 | {
222 | //qDebug() << "Destroying search dialog";
223 | }
224 |
225 | void Search::setKey(QString key)
226 | {
227 | this->key = key;
228 | keywE->setText(key);
229 | clearSearch();
230 | pageCur = 1;
231 | startSearch();
232 | }
233 |
234 | void Search::startSearch()
235 | {
236 | Seek::Task task;
237 | task.text = keywE->text();
238 | task.code = sitesC->currentText();
239 | if (0 > (task.sort = orderC->currentIndex())){
240 | return;
241 | }
242 | task.page.first = pageCur == -1 ? 1 : pageCur;
243 | task.cover = resultV->iconSize();
244 | task.model = resultM;
245 | task.processer = Seek::instance()->getProc(task.code);
246 | Seek::instance()->enqueue(task);
247 | }
248 |
249 | void Search::clearSearch()
250 | {
251 | resultM->clear();
252 | pageNum = -1;
253 | pageCur = -1;
254 | pageE->clear();
255 | pageL->clear();
256 | statusL->setText(tr("Ready"));
257 | }
258 |
259 | void Search::accept()
260 | {
261 | QModelIndex i = resultV->currentIndex();
262 | i = i.sibling(i.row(), 0);
263 | if (QStandardItem *item = resultM->itemFromIndex(i)){
264 | aid = item->data(Qt::UserRole).toString();
265 | if (aid.length()){
266 | QDialog::accept();
267 | }
268 | }
269 | else{
270 | QMessageBox::warning(this, tr("Warning"), tr("No video has been chosen."));
271 | }
272 | }
273 |
--------------------------------------------------------------------------------
/src/UI/Search.h:
--------------------------------------------------------------------------------
1 | /*=======================================================================
2 | *
3 | * Copyright (C) 2013-2015 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 | #pragma once
29 |
30 | #include
31 | #include