├── .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 | ![W](res/00.png) 28 | 29 | ![L](res/01.png) 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 32 | 33 | namespace UI 34 | { 35 | class Search :public QDialog 36 | { 37 | Q_OBJECT 38 | public: 39 | static Search* instance(); 40 | explicit Search(QWidget *parent = 0); 41 | ~Search(); 42 | 43 | private: 44 | static Search* ins; 45 | QLabel *statusL; 46 | QLabel *pageT; 47 | QLabel *pageL; 48 | QLineEdit *keywE; 49 | QLineEdit *pageE; 50 | QComboBox *orderC; 51 | QComboBox *sitesC; 52 | QPushButton *okB; 53 | QPushButton *ccB; 54 | QPushButton *searchB; 55 | QPushButton *pageUpB; 56 | QPushButton *pageDnB; 57 | QPushButton *pageGoB; 58 | QTreeView *resultV; 59 | QStandardItemModel *resultM; 60 | 61 | QString key; 62 | QString aid; 63 | 64 | int pageNum; 65 | int pageCur; 66 | bool isWaiting; 67 | 68 | public slots: 69 | void setKey(QString key); 70 | QString getKey(){ return key; } 71 | QString getAid(){ return aid; } 72 | void startSearch(); 73 | void clearSearch(); 74 | virtual void accept() override; 75 | }; 76 | } 77 | -------------------------------------------------------------------------------- /src/UI/Type.cpp: -------------------------------------------------------------------------------- 1 | /*======================================================================= 2 | * 3 | * Copyright (C) 2013-2015 Lysine. 4 | * 5 | * Filename: Type.cpp 6 | * Time: 2015/04/26 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 "Type.h" 29 | #include "../Local.h" 30 | #include "../Access/Post.h" 31 | #include "../Model/Danmaku.h" 32 | #include "../Player/APlayer.h" 33 | 34 | using namespace UI; 35 | 36 | namespace 37 | { 38 | QList getRecords() 39 | { 40 | QList list; 41 | for (const Record &r : Danmaku::instance()->getPool()){ 42 | if (Post::instance()->canPost(r.access)){ 43 | list.append(&r); 44 | } 45 | } 46 | return list; 47 | } 48 | } 49 | 50 | Type::Type(QWidget *parent) : 51 | QWidget(parent) 52 | { 53 | setObjectName("Type"); 54 | setFixedSize(parent->minimumWidth(), 25); 55 | 56 | auto layout = new QHBoxLayout(this); 57 | layout->setMargin(0); 58 | layout->setSpacing(0); 59 | commentM = new QComboBox(this); 60 | commentM->addItems({ tr("Top"), tr("Slide"), tr("Bottom") }); 61 | commentM->setCurrentIndex(1); 62 | commentM->setFixedWidth(commentM->sizeHint().width()); 63 | layout->addWidget(commentM); 64 | commentC = new QPushButton(this); 65 | commentC->setFixedWidth(25); 66 | setColor(Qt::white); 67 | connect(commentC, &QPushButton::clicked, [this](){ 68 | QColor color = QColorDialog::getColor(getColor(), lApp->mainWidget()); 69 | if (color.isValid()){ 70 | setColor(color); 71 | } 72 | }); 73 | layout->addWidget(commentC); 74 | commentL = new QLineEdit(this); 75 | commentL->setFocus(); 76 | layout->addWidget(commentL); 77 | commentS = new QComboBox(this); 78 | layout->addWidget(commentS); 79 | commentB = new QPushButton(tr("Post"), this); 80 | commentB->setDefault(true); 81 | commentB->setFixedWidth(55); 82 | commentB->setToolTip(tr("DA☆ZE!")); 83 | layout->addWidget(commentB); 84 | commentA = new QAction(this); 85 | commentA->setShortcut(QKeySequence("Ctrl+Enter")); 86 | connect(commentL, &QLineEdit::returnPressed, commentA, &QAction::trigger); 87 | connect(commentB, &QPushButton::clicked, commentA, &QAction::trigger); 88 | connect(commentA, &QAction::triggered, [this](){ 89 | if (!commentL->text().isEmpty()){ 90 | auto r = (const Record *)commentS->currentData().value(); 91 | auto c = getComment(); 92 | Post::instance()->postComment(r, &c); 93 | } 94 | }); 95 | connect(Post::instance(), &Post::stateChanged, [this](int code){ 96 | switch (code){ 97 | case Post::None: 98 | setEnabled(1); 99 | hide(); 100 | commentL->clear(); 101 | break; 102 | case Post::Code: 103 | setEnabled(0); 104 | break; 105 | default: 106 | setEnabled(1); 107 | break; 108 | } 109 | }); 110 | connect(Danmaku::instance(), &Danmaku::modelReset, [this](){ 111 | commentS->clear(); 112 | int w = 0; 113 | for (const Record *r : getRecords()){ 114 | commentS->addItem(r->string, (quintptr)r); 115 | w = qMax(w, commentS->fontMetrics().width(r->string)); 116 | } 117 | commentS->setVisible(commentS->count() >= 2); 118 | commentS->setFixedWidth(w + 30); 119 | }); 120 | hide(); 121 | } 122 | 123 | void Type::setVisible(bool visible) 124 | { 125 | QWidget::setVisible(visible); 126 | QWidget *fw = visible ? commentL : lApp->mainWidget(); 127 | fw->setFocus(); 128 | } 129 | 130 | QColor Type::getColor() 131 | { 132 | QString sheet = commentC->styleSheet(); 133 | return QColor(sheet.mid(sheet.indexOf('#'))); 134 | } 135 | 136 | void Type::setColor(QColor color) 137 | { 138 | commentC->setStyleSheet(QString("background-color:%1").arg(color.name())); 139 | } 140 | 141 | namespace 142 | { 143 | int translateMode(int i) 144 | { 145 | switch (i){ 146 | case 0: 147 | return 5; 148 | case 1: 149 | return 1; 150 | case 2: 151 | return 4; 152 | default: 153 | return 0; 154 | } 155 | } 156 | } 157 | 158 | Comment Type::getComment() 159 | { 160 | Comment c; 161 | c.mode = translateMode(commentM->currentIndex()); 162 | c.font = 25; 163 | c.time = qMax(0, APlayer::instance()->getTime()); 164 | c.color = getColor().rgb() & 0xFFFFFF; 165 | c.string = commentL->text(); 166 | return c; 167 | } 168 | -------------------------------------------------------------------------------- /src/UI/Type.h: -------------------------------------------------------------------------------- 1 | /*======================================================================= 2 | * 3 | * Copyright (C) 2013-2015 Lysine. 4 | * 5 | * Filename: Type.h 6 | * Time: 2015/04/26 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 | 33 | namespace UI 34 | { 35 | class Type :public QWidget 36 | { 37 | Q_OBJECT 38 | public: 39 | explicit Type(QWidget *parent); 40 | void setVisible(bool); 41 | 42 | private: 43 | QLineEdit * commentL; 44 | QComboBox * commentS; 45 | QComboBox * commentM; 46 | QAction * commentA; 47 | QPushButton * commentC; 48 | QPushButton * commentB; 49 | 50 | Comment getComment(); 51 | 52 | public slots: 53 | QColor getColor(); 54 | void setColor(QColor); 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /src/Utils.h: -------------------------------------------------------------------------------- 1 | /*======================================================================= 2 | * 3 | * Copyright (C) 2013-2015 Lysine. 4 | * 5 | * Filename: Utils.h 6 | * Time: 2013/05/10 7 | * Author: Lysine 8 | * 9 | * Lysine is a student majoring in Software Engineering 10 | * from the School of Software, SUN YAT-SEN UNIVERSITY. 11 | * 12 | * This program is free software: you can redistribute it and/or modify 13 | * it under the terms of the GNU General Public License as published by 14 | * the Free Software Foundation, either version 3 of the License, or 15 | * (at your option) any later version. 16 | * 17 | * This program is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU General Public License for more details. 21 | 22 | * You should have received a copy of the GNU General Public License 23 | * along with this program. If not, see . 24 | * 25 | =========================================================================*/ 26 | 27 | #pragma once 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | class Comment 34 | { 35 | public: 36 | int mode; 37 | int font; 38 | int color; 39 | qint64 time; 40 | qint64 date; 41 | QString sender; 42 | QString string; 43 | bool blocked; 44 | 45 | Comment() 46 | { 47 | mode = font = color = time = date = 0; 48 | blocked = false; 49 | } 50 | 51 | inline bool operator <(const Comment &o) const 52 | { 53 | return time < o.time; 54 | } 55 | 56 | inline bool operator==(const Comment &o) const 57 | { 58 | return mode == o.mode && font == o.font && color == o.color && qFuzzyCompare((float)time, (float)o.time) && date == o.date && sender == o.sender && string == o.string; 59 | } 60 | 61 | inline bool isLocal() const 62 | { 63 | return date == 0 && sender.isEmpty(); 64 | } 65 | 66 | inline bool isEmpty() const 67 | { 68 | return mode == 0 && font == 0 && color == 0 && time == 0 && date == 0 && sender.isEmpty() && string.isEmpty() && !blocked; 69 | } 70 | }; 71 | 72 | inline uint qHash(const Comment &c, uint seed = 0) 73 | { 74 | uint h = qHash(c.mode, seed); 75 | h = (h << 1) ^ qHash(c.font, seed); 76 | h = (h << 1) ^ qHash(c.color, seed); 77 | h = (h << 1) ^ qHash(c.date, seed); 78 | h = (h << 1) ^ qHash(c.sender, seed); 79 | h = (h << 1) ^ qHash(c.string, seed); 80 | return h; 81 | } 82 | 83 | class Record 84 | { 85 | public: 86 | bool full; 87 | qint64 delay; 88 | qint64 limit; 89 | QString source; 90 | QString string; 91 | QString access; 92 | QVector danmaku; 93 | 94 | Record() 95 | { 96 | full = false; 97 | delay = limit = 0; 98 | } 99 | }; 100 | 101 | 102 | // No need to be a class, like global function and constant value 103 | // but enclosed in a namespace 104 | namespace Utils 105 | { 106 | enum Site 107 | { 108 | Unknown, 109 | Bilibili, 110 | AcFun, 111 | Tudou, 112 | Letv, 113 | AcfunLocalizer, 114 | Niconico, 115 | TuCao, 116 | ASS 117 | }; 118 | 119 | enum Type 120 | { 121 | Video = 1, 122 | Audio = 2, 123 | Subtitle = 4, 124 | Danmaku = 8 125 | }; 126 | 127 | Site parseSite(QString url); 128 | void setCenter(QWidget *widget); 129 | void setGround(QWidget *widget, QColor color); 130 | QString defaultFont(bool monospace = false); 131 | QString customUrl(Site site); 132 | QString decodeTxt(const QByteArray &data); 133 | QString decodeXml(QString string, bool fast = false); 134 | QString decodeXml(QStringRef ref, bool fast = false); 135 | QStringList getSuffix(int type, QString format = QString()); 136 | double evaluate(QString expression); 137 | } 138 | --------------------------------------------------------------------------------