diff options
author | 2020-04-18 03:34:59 +0800 | |
---|---|---|
committer | 2020-04-18 03:46:27 +0800 | |
commit | 11f4549a67d2a005f0c5108d4759b152775d54f4 (patch) | |
tree | f8e52ec80be8f254d7bf37a7ffb79f9333ac6e37 /media-video/kikoplay | |
parent | dev-libs/qhttpengine: add live build (diff) | |
download | guru-11f4549a67d2a005f0c5108d4759b152775d54f4.tar.gz guru-11f4549a67d2a005f0c5108d4759b152775d54f4.tar.bz2 guru-11f4549a67d2a005f0c5108d4759b152775d54f4.zip |
media-video/kikoplay: new package
A Full-Featured Danmu Player based on mpv.
NOTE: this package is blocked by lua 5.3,
However, Gentoo is using the old 5.1.
It depends on gentoo slotted dev-lang/lua
versions and dependencies.
See also https://bugs.gentoo.org/657722
See also https://bugs.gentoo.org/671248
It takes many years.
Package-Manager: Portage-2.3.99, Repoman-2.3.22
Signed-off-by: Huang Rui <vowstar@gmail.com>
Diffstat (limited to 'media-video/kikoplay')
-rw-r--r-- | media-video/kikoplay/Manifest | 1 | ||||
-rw-r--r-- | media-video/kikoplay/files/kikoplay-0.6.0-desktop.patch | 16 | ||||
-rw-r--r-- | media-video/kikoplay/files/kikoplay-0.6.0-home.patch | 97 | ||||
-rw-r--r-- | media-video/kikoplay/files/kikoplay-0.6.0-install.patch | 1003 | ||||
-rw-r--r-- | media-video/kikoplay/kikoplay-0.6.0.ebuild | 78 | ||||
-rw-r--r-- | media-video/kikoplay/metadata.xml | 38 |
6 files changed, 1233 insertions, 0 deletions
diff --git a/media-video/kikoplay/Manifest b/media-video/kikoplay/Manifest new file mode 100644 index 000000000..b7a4138df --- /dev/null +++ b/media-video/kikoplay/Manifest @@ -0,0 +1 @@ +DIST kikoplay-0.6.0.tar.gz 7497254 BLAKE2B a23106151782477194d15712e9458171a0bc1dd53f8b6c8dbed12663be1c2c76204674c23eba61f2b8828be7acbd10449f51c766ab57be86cf21844591430b18 SHA512 9d8801f7c9b091f097d1edf9496a389718e81399a8d380d7763c1d12eafd1d4ce444e4df22a0e4a6c8eebbc7f1176e58a3cbac6bea60e87ccd44a5890927bf21 diff --git a/media-video/kikoplay/files/kikoplay-0.6.0-desktop.patch b/media-video/kikoplay/files/kikoplay-0.6.0-desktop.patch new file mode 100644 index 000000000..86b438213 --- /dev/null +++ b/media-video/kikoplay/files/kikoplay-0.6.0-desktop.patch @@ -0,0 +1,16 @@ +diff --git a/kikoplay.desktop b/kikoplay.desktop +new file mode 100644 +index 0000000..6171559 +--- /dev/null ++++ b/kikoplay.desktop +@@ -0,0 +1,10 @@ ++[Desktop Entry] ++Type=Application ++Name=KikoPlay ++Comment=KikoPlay is a full-featured danmu player! ++TryExec=KikoPlay ++Exec=KikoPlay ++Icon=/usr/share/pixmaps/kikoplay.png ++Terminal=false ++StartupNotify=true ++Categories=Qt;AudioVideo;Video; diff --git a/media-video/kikoplay/files/kikoplay-0.6.0-home.patch b/media-video/kikoplay/files/kikoplay-0.6.0-home.patch new file mode 100644 index 000000000..ec2eae551 --- /dev/null +++ b/media-video/kikoplay/files/kikoplay-0.6.0-home.patch @@ -0,0 +1,97 @@ +diff --git a/Download/Script/scriptmanager.cpp b/Download/Script/scriptmanager.cpp +index f99c261..8ede8e3 100644 +--- a/Download/Script/scriptmanager.cpp ++++ b/Download/Script/scriptmanager.cpp +@@ -163,7 +163,11 @@ QString ScriptManager::search(QString sid, const QString &keyword, int page, int + { + if(s.id==sid) + { ++#ifndef CONFIG_HOME_DATA + scriptPath=QCoreApplication::applicationDirPath()+"/script/"+s.fileName; ++#else ++ scriptPath=QDir::homePath()+"/.config/kikoplay/script/"+s.fileName; ++#endif + break; + } + } +@@ -270,7 +274,11 @@ void ScriptManager::removeScript(const QModelIndex &index) + else + normalScriptId=""; + } ++#ifndef CONFIG_HOME_DATA + QFileInfo fi(QCoreApplication::applicationDirPath()+"/script/"+script.fileName); ++#else ++ QFileInfo fi(QDir::homePath()+"/.config/kikoplay/script/"+script.fileName); ++#endif + if(fi.exists()) fi.dir().remove(fi.fileName()); + beginRemoveRows(QModelIndex(),index.row(),index.row()); + scriptList.removeAt(index.row()); +@@ -319,7 +327,11 @@ QVariant ScriptManager::headerData(int section, Qt::Orientation orientation, int + + void ScriptWorker::refreshScriptList() + { ++#ifndef CONFIG_HOME_DATA + QString scriptPath(QCoreApplication::applicationDirPath()+"/script/"); ++#else ++ QString scriptPath(QDir::homePath()+"/.config/kikoplay/script/"); ++#endif + QDir folder(scriptPath); + QList<ScriptInfo> sList; + for (QFileInfo fileInfo : folder.entryInfoList()) +diff --git a/Download/aria2jsonrpc.cpp b/Download/aria2jsonrpc.cpp +index 7999128..43bc63d 100644 +--- a/Download/aria2jsonrpc.cpp ++++ b/Download/aria2jsonrpc.cpp +@@ -1,4 +1,5 @@ + #include "aria2jsonrpc.h" ++#include <QFileInfo> + #include <QNetworkAccessManager> + #include <QNetworkRequest> + #include <QNetworkReply> +@@ -19,7 +20,13 @@ Aria2JsonRPC::Aria2JsonRPC(QObject *parent) : QObject(parent) + #ifdef Q_OS_WIN + process->start(QCoreApplication::applicationDirPath()+"\\aria2c.exe", args); + #else +- process->start(QCoreApplication::applicationDirPath()+"/aria2c", args); ++ QFileInfo check_file(QCoreApplication::applicationDirPath()+"/aria2c"); ++ /* check if file exists and if yes: Is it really a file and no directory? */ ++ if (check_file.exists() && check_file.isFile()) { ++ process->start(QCoreApplication::applicationDirPath()+"/aria2c", args); ++ } else { ++ process->start("aria2c", args); ++ } + + #endif + process->waitForStarted(-1); +diff --git a/LANServer/httpserver.cpp b/LANServer/httpserver.cpp +index 5b3fa08..d66a6ee 100644 +--- a/LANServer/httpserver.cpp ++++ b/LANServer/httpserver.cpp +@@ -127,7 +127,11 @@ namespace + HttpServer::HttpServer(QObject *parent) : QObject(parent) + { + MediaFileHandler *handler=new MediaFileHandler(&mediaHash,this); ++#ifndef CONFIG_HOME_DATA + handler->setDocumentRoot(QCoreApplication::applicationDirPath()+"/web"); ++#else ++ handler->setDocumentRoot(QDir::homePath()+"/.config/kikoplay/web"); ++#endif + handler->addRedirect(QRegExp("^$"), "/index.html"); + + QHttpEngine::QObjectHandler *apiHandler=new QHttpEngine::QObjectHandler(this); +diff --git a/globalobjects.cpp b/globalobjects.cpp +index 07bf674..32b82a2 100644 +--- a/globalobjects.cpp ++++ b/globalobjects.cpp +@@ -42,7 +42,11 @@ namespace { + } + void GlobalObjects::init() + { ++#ifndef CONFIG_HOME_DATA + dataPath=QCoreApplication::applicationDirPath()+"/data/"; ++#else ++ dataPath=QDir::homePath()+"/.config/kikoplay/data/"; ++#endif + QDir dir; + if(!dir.exists(dataPath)) + { diff --git a/media-video/kikoplay/files/kikoplay-0.6.0-install.patch b/media-video/kikoplay/files/kikoplay-0.6.0-install.patch new file mode 100644 index 000000000..0b90d54d8 --- /dev/null +++ b/media-video/kikoplay/files/kikoplay-0.6.0-install.patch @@ -0,0 +1,1003 @@ +diff --git a/Common/network.cpp b/Common/network.cpp +index c9bf952..ec62f69 100644 +--- a/Common/network.cpp ++++ b/Common/network.cpp +@@ -139,6 +139,25 @@ QByteArray Network::httpPost(const QString &url, QByteArray &data, const QString + request.setRawHeader(header[i].toUtf8(),header[i+1].toUtf8()); + } + request.setUrl(queryUrl); ++ QList<QNetworkCookie> cookies; ++ QNetworkAccessManager *manager = getManager(); ++ if(request.hasRawHeader("Cookie")) ++ { ++ auto cookieBytes = request.rawHeader("Cookie"); ++ auto rawList = cookieBytes.split(';'); ++ for (auto &bytes:rawList) ++ { ++ int pos =bytes.indexOf('='); ++ if(pos<=0) continue; ++ auto name = bytes.left(pos); ++ auto value = bytes.mid(pos+1); ++ QNetworkCookie cookie(name, value); ++ cookie.setDomain(queryUrl.host()); ++ cookie.setPath(queryUrl.path()); ++ cookies<<cookie; ++ manager->cookieJar()->insertCookie(cookie); ++ } ++ } + + bool hasError=false; + QString errorInfo; +@@ -147,7 +166,11 @@ QByteArray Network::httpPost(const QString &url, QByteArray &data, const QString + QTimer timer; + timer.setInterval(timeout); + timer.setSingleShot(true); +- QNetworkReply *reply = getManager()->post(request, data); ++ QNetworkReply *reply = manager->post(request, data); ++ for(auto &cookie:cookies) ++ { ++ manager->cookieJar()->deleteCookie(cookie); ++ } + QEventLoop eventLoop; + QObject::connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit); + QObject::connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit); +diff --git a/Play/Danmu/Provider/acfunprovider.cpp b/Play/Danmu/Provider/acfunprovider.cpp +index 6c1b371..7053c73 100644 +--- a/Play/Danmu/Provider/acfunprovider.cpp ++++ b/Play/Danmu/Provider/acfunprovider.cpp +@@ -110,7 +110,7 @@ QString AcfunProvider::downloadDanmu(DanmuSourceItem *item, QList<DanmuComment * + try + { + QString replyStr(Network::httpGet(baseUrl, QUrlQuery())); +- QRegExp re("\"videoId\":([0-9]+)"); ++ QRegExp re("\"(current)?(V|v)ideoId\":([0-9]+)"); + int pos = re.indexIn(replyStr); + if (pos == -1) + { +@@ -119,8 +119,16 @@ QString AcfunProvider::downloadDanmu(DanmuSourceItem *item, QList<DanmuComment * + else + { + QStringList captured = re.capturedTexts(); +- item->id = captured[1].toInt(); ++ item->id = captured[3].toInt(); + downloadAllDanmu(danmuList, item->id); ++ QRegExp reDuration("\"durationMillis\":([0-9]+)"); ++ int pos = reDuration.indexIn(replyStr); ++ if (pos != -1) ++ { ++ item->extra=reDuration.capturedTexts()[1].toInt()/1000; ++ } ++ ++ + } + } + catch (Network::NetworkError &error) +@@ -308,6 +316,42 @@ void AcfunProvider::downloadAllDanmu(QList<DanmuComment *> &danmuList, int video + { + try + { ++ QString baseUrl="https://www.acfun.cn/rest/pc-direct/new-danmaku/poll"; ++ QByteArray data(QString("videoId=%1&lastFetchTime=0").arg(videoId).toUtf8()); ++ ++ QString replyStr(Network::httpPost(baseUrl,data,{"Cookie","_did=web;"})); ++ QJsonDocument document(Network::toJson(replyStr)); ++ ++ QJsonArray added_dms(document.object().value("added").toArray()); ++ for(auto iter=added_dms.begin();iter!=added_dms.end();++iter) ++ { ++ QJsonObject dmObj=(*iter).toObject(); ++ DanmuComment *danmu=new DanmuComment(); ++ danmu->text=dmObj.value("body").toString(); ++ danmu->time =dmObj.value("position").toInt(); ++ danmu->originTime=danmu->time; ++ danmu->color=dmObj.value("color").toInt(); ++ danmu->setType(dmObj.value("mode").toInt()); ++ danmu->date = 0; ++ danmu->sender="[Acfun]"+QString::number(dmObj.value("userId").toInt()); ++ switch (dmObj.value("size").toInt()) ++ { ++ case 25: ++ danmu->fontSizeLevel=DanmuComment::Normal; ++ break; ++ case 18: ++ danmu->fontSizeLevel=DanmuComment::Small; ++ break; ++ case 36: ++ danmu->fontSizeLevel=DanmuComment::Large; ++ break; ++ default: ++ danmu->fontSizeLevel=DanmuComment::Normal; ++ } ++ if(danmu->type!=DanmuComment::UNKNOW)danmuList.append(danmu); ++ else delete danmu; ++ } ++ /* + int downloadCount=0; + QString timeStamp("4073558400000"); + do +@@ -350,6 +394,7 @@ void AcfunProvider::downloadAllDanmu(QList<DanmuComment *> &danmuList, int video + timeStamp=QString::number(danmuList.last()->date); + + }while(downloadCount>=1000); ++ */ + } + catch(Network::NetworkError &) + { +diff --git a/Play/Danmu/Provider/iqiyiprovider.cpp b/Play/Danmu/Provider/iqiyiprovider.cpp +index cc1f8f6..c6bc46c 100644 +--- a/Play/Danmu/Provider/iqiyiprovider.cpp ++++ b/Play/Danmu/Provider/iqiyiprovider.cpp +@@ -69,7 +69,7 @@ QString IqiyiProvider::downloadDanmu(DanmuSourceItem *item, QList<DanmuComment * + try + { + QString replyStr(Network::httpGet(item->strId,QUrlQuery())); +- QRegExp re("playPageInfo.*(\\{.*\\});"); ++ QRegExp re("playPageInfo\\s*=\\s*(\\{.*\\})"); + re.setMinimal(true); + int pos=re.indexIn(replyStr); + if(pos==-1) +@@ -114,56 +114,46 @@ QString IqiyiProvider::downloadBySourceURL(const QString &url, QList<DanmuCommen + + void IqiyiProvider::handleSearchReply(QString &reply, DanmuAccessResult *result) + { +- QRegExp re("(<ul class=\"mod_result_list\">)(.*)(<div class=\"mod-page\")"); ++ QRegExp re("<div class=\"layout-main\">(.*)<div class=\"layout-side j-search-aside\">"); + int pos=re.indexIn(reply); + if(pos!=-1) + { + QStringList list = re.capturedTexts(); +- HTMLParserSax parser(list.at(2)); ++ HTMLParserSax parser(list.at(1)); + DanmuSourceItem item; + item.extra=0; + bool itemStart=false; +- bool epStart=false; + while(!parser.atEnd()) + { +- if(parser.currentNodeProperty("class")=="list_item") ++ if(parser.currentNodeProperty("class")=="qy-search-result-tit") + { +- if(!itemStart)itemStart=true; +- else ++ do{ ++ parser.readNext(); ++ }while(parser.currentNodeProperty("class")!="main-tit"); ++ if(itemStart) + { +- if (!epStart && !item.title.trimmed().isEmpty())result->list.append(item); ++ result->list.append(item); + } +- epStart=false; +- item.title=parser.currentNodeProperty("data-widget-searchlist-tvname"); +- } +- else if(parser.currentNodeProperty("class")=="result_title") +- { +- parser.readNext(); +- item.strId=parser.currentNodeProperty("href"); +- } +- else if(parser.currentNodeProperty("class")=="info_play_btn") +- { ++ itemStart=true; ++ item.title=parser.currentNodeProperty("title"); + item.strId=parser.currentNodeProperty("href"); + } +- else if(parser.currentNodeProperty("class")=="result_info_txt") +- { +- item.description=parser.readContentText(); +- } +- else if(parser.currentNodeProperty("class")=="result_album clearfix" && +- parser.currentNodeProperty("data-tvlist-elem")=="list") +- { +- epStart=true; +- } +- else if(epStart && parser.currentNodeProperty("class")=="album_link") ++ else if(parser.currentNodeProperty("class")=="qy-search-result-album") + { +- if(!parser.currentNodeProperty("href").isEmpty()) ++ while(parser.currentNode()!="ul" || parser.isStartNode()) + { +- DanmuSourceItem epItem; +- epItem.title=item.title + " " + parser.currentNodeProperty("title"); +- epItem.strId=parser.currentNodeProperty("href"); +- epItem.extra=0; +- result->list.append(epItem); ++ parser.readNext(); ++ if(parser.currentNode()=="li" && parser.currentNodeProperty("class")=="album-item") ++ { ++ parser.readNext(); ++ DanmuSourceItem epItem; ++ epItem.title=item.title + " " + parser.currentNodeProperty("title"); ++ epItem.strId=parser.currentNodeProperty("href"); ++ epItem.extra=0; ++ result->list.append(epItem); ++ } + } ++ itemStart = false; + } + parser.readNext(); + } +diff --git a/Play/Video/mpv/client.h b/Play/Video/mpv/client.h +index 39df20a..2e8dcdc 100644 +--- a/Play/Video/mpv/client.h ++++ b/Play/Video/mpv/client.h +@@ -107,8 +107,11 @@ extern "C" { + * careful not accidentally interpret the mpv_event->reply_userdata if an + * event is not a reply. (For non-replies, this field is set to 0.) + * +- * Currently, asynchronous calls are always strictly ordered (even with +- * synchronous calls) for each client, although that may change in the future. ++ * Asynchronous calls may be reordered in arbitrarily with other synchronous ++ * and asynchronous calls. If you want a guaranteed order, you need to wait ++ * until asynchronous calls report completion before doing the next call. ++ * ++ * See also the section "Asynchronous command details" in the manpage. + * + * Multithreading + * -------------- +@@ -164,14 +167,14 @@ extern "C" { + * Embedding the video window + * -------------------------- + * +- * Using the opengl-cb API (in opengl_cb.h) is recommended. This API requires ++ * Using the render API (in render_cb.h) is recommended. This API requires + * you to create and maintain an OpenGL context, to which you can render + * video using a specific API call. This API does not include keyboard or mouse + * input directly. + * + * There is an older way to embed the native mpv window into your own. You have + * to get the raw window handle, and set it as "wid" option. This works on X11, +- * win32, and OSX only. It's much easier to use than the opengl-cb API, but ++ * win32, and OSX only. It's much easier to use than the render API, but + * also has various problems. + * + * Also see client API examples and the mpv manpage. There is an extensive +@@ -195,6 +198,20 @@ extern "C" { + * or change the underlying datatypes. It might be a good idea to prefer + * MPV_FORMAT_STRING over other types to decouple your code from potential + * mpv changes. ++ * ++ * Also see: DOCS/compatibility.rst ++ * ++ * Future changes ++ * -------------- ++ * ++ * This are the planned changes that will most likely be done on the next major ++ * bump of the library: ++ * ++ * - remove all symbols and include files that are marked as deprecated ++ * - reassign enum numerical values to remove gaps ++ * - remove the mpv_opengl_init_params.extra_exts field ++ * - change the type of mpv_event_end_file.reason ++ * - disabling all events by default + */ + + /** +@@ -210,7 +227,7 @@ extern "C" { + * relational operators (<, >, <=, >=). + */ + #define MPV_MAKE_VERSION(major, minor) (((major) << 16) | (minor) | 0UL) +-#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 102) ++#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 107) + + /** + * The API user is allowed to "#define MPV_ENABLE_DEPRECATED 0" before +@@ -427,12 +444,12 @@ mpv_handle *mpv_create(void); + + /** + * Initialize an uninitialized mpv instance. If the mpv instance is already +- * running, an error is retuned. ++ * running, an error is returned. + * + * This function needs to be called to make full use of the client API if the + * client API handle was created with mpv_create(). + * +- * Only the following options require to be set _before_ mpv_initialize(): ++ * Only the following options are required to be set _before_ mpv_initialize(): + * - options which are only read at initialization time: + * - config + * - config-dir +@@ -928,10 +945,25 @@ int mpv_command(mpv_handle *ctx, const char **args); + * + * Does not use OSD and string expansion by default. + * +- * @param[in] args mpv_node with format set to MPV_FORMAT_NODE_ARRAY; each entry +- * is an argument using an arbitrary format (the format must be +- * compatible to the used command). Usually, the first item is +- * the command name (as MPV_FORMAT_STRING). ++ * The args argument can have one of the following formats: ++ * ++ * MPV_FORMAT_NODE_ARRAY: ++ * Positional arguments. Each entry is an argument using an arbitrary ++ * format (the format must be compatible to the used command). Usually, ++ * the first item is the command name (as MPV_FORMAT_STRING). The order ++ * of arguments is as documented in each command description. ++ * ++ * MPV_FORMAT_NODE_MAP: ++ * Named arguments. This requires at least an entry with the key "name" ++ * to be present, which must be a string, and contains the command name. ++ * The special entry "_flags" is optional, and if present, must be an ++ * array of strings, each being a command prefix to apply. All other ++ * entries are interpreted as arguments. They must use the argument names ++ * as documented in each command description. Some commands do not ++ * support named arguments at all, and must use MPV_FORMAT_NODE_ARRAY. ++ * ++ * @param[in] args mpv_node with format set to one of the values documented ++ * above (see there for details) + * @param[out] result Optional, pass NULL if unused. If not NULL, and if the + * function succeeds, this is set to command-specific return + * data. You must call mpv_free_node_contents() to free it +@@ -941,6 +973,22 @@ int mpv_command(mpv_handle *ctx, const char **args); + */ + int mpv_command_node(mpv_handle *ctx, mpv_node *args, mpv_node *result); + ++/** ++ * This is essentially identical to mpv_command() but it also returns a result. ++ * ++ * Does not use OSD and string expansion by default. ++ * ++ * @param[in] args NULL-terminated list of strings. Usually, the first item ++ * is the command, and the following items are arguments. ++ * @param[out] result Optional, pass NULL if unused. If not NULL, and if the ++ * function succeeds, this is set to command-specific return ++ * data. You must call mpv_free_node_contents() to free it ++ * (again, only if the command actually succeeds). ++ * Not many commands actually use this at all. ++ * @return error code (the result parameter is not set on error) ++ */ ++int mpv_command_ret(mpv_handle *ctx, const char **args, mpv_node *result); ++ + /** + * Same as mpv_command, but use input.conf parsing for splitting arguments. + * This is slightly simpler, but also more error prone, since arguments may +@@ -954,14 +1002,11 @@ int mpv_command_string(mpv_handle *ctx, const char *args); + * Same as mpv_command, but run the command asynchronously. + * + * Commands are executed asynchronously. You will receive a +- * MPV_EVENT_COMMAND_REPLY event. (This event will also have an +- * error code set if running the command failed.) ++ * MPV_EVENT_COMMAND_REPLY event. This event will also have an ++ * error code set if running the command failed. For commands that ++ * return data, the data is put into mpv_event_command.result. + * +- * This has nothing to do with the "async" command prefix, although they might +- * be unified in the future. For now, calling this API means that the command +- * will be synchronously executed on the core, without blocking the API user. +- * +- * * Safe to be called from mpv render API threads. ++ * Safe to be called from mpv render API threads. + * + * @param reply_userdata the value mpv_event.reply_userdata of the reply will + * be set to (see section about asynchronous calls) +@@ -976,8 +1021,7 @@ int mpv_command_async(mpv_handle *ctx, uint64_t reply_userdata, + * function is to mpv_command_node() what mpv_command_async() is to + * mpv_command(). + * +- * See mpv_command_async() for details. Retrieving the result is not +- * supported yet. ++ * See mpv_command_async() for details. + * + * Safe to be called from mpv render API threads. + * +@@ -989,6 +1033,38 @@ int mpv_command_async(mpv_handle *ctx, uint64_t reply_userdata, + int mpv_command_node_async(mpv_handle *ctx, uint64_t reply_userdata, + mpv_node *args); + ++/** ++ * Signal to all async requests with the matching ID to abort. This affects ++ * the following API calls: ++ * ++ * mpv_command_async ++ * mpv_command_node_async ++ * ++ * All of these functions take a reply_userdata parameter. This API function ++ * tells all requests with the matching reply_userdata value to try to return ++ * as soon as possible. If there are multiple requests with matching ID, it ++ * aborts all of them. ++ * ++ * This API function is mostly asynchronous itself. It will not wait until the ++ * command is aborted. Instead, the command will terminate as usual, but with ++ * some work not done. How this is signaled depends on the specific command (for ++ * example, the "subprocess" command will indicate it by "killed_by_us" set to ++ * true in the result). How long it takes also depends on the situation. The ++ * aborting process is completely asynchronous. ++ * ++ * Not all commands may support this functionality. In this case, this function ++ * will have no effect. The same is true if the request using the passed ++ * reply_userdata has already terminated, has not been started yet, or was ++ * never in use at all. ++ * ++ * You have to be careful of race conditions: the time during which the abort ++ * request will be effective is _after_ e.g. mpv_command_async() has returned, ++ * and before the command has signaled completion with MPV_EVENT_COMMAND_REPLY. ++ * ++ * @param reply_userdata ID of the request to be aborted (see above) ++ */ ++void mpv_abort_async_command(mpv_handle *ctx, uint64_t reply_userdata); ++ + /** + * Set a property to a given value. Properties are essentially variables which + * can be queried or set at runtime. For example, writing to the pause property +@@ -1121,6 +1197,9 @@ int mpv_get_property_async(mpv_handle *ctx, uint64_t reply_userdata, + * event queue becomes empty (e.g. mpv_wait_event() would block or return + * MPV_EVENT_NONE), and then only one event per changed property is returned. + * ++ * You always get an initial change notification. This is meant to initialize ++ * the user's state to the current value of the property. ++ * + * Normally, change events are sent only if the property value changes according + * to the requested format. mpv_event_property will contain the property value + * as data member. +@@ -1133,7 +1212,7 @@ int mpv_get_property_async(mpv_handle *ctx, uint64_t reply_userdata, + * If the property is observed with the format parameter set to MPV_FORMAT_NONE, + * you get low-level notifications whether the property _may_ have changed, and + * the data member in mpv_event_property will be unset. With this mode, you +- * will have to determine yourself whether the property really changd. On the ++ * will have to determine yourself whether the property really changed. On the + * other hand, this mechanism can be faster and uses less resources. + * + * Observing a property that doesn't exist is allowed. (Although it may still +@@ -1202,7 +1281,8 @@ typedef enum mpv_event_id { + */ + MPV_EVENT_SET_PROPERTY_REPLY = 4, + /** +- * Reply to a mpv_command_async() request. ++ * Reply to a mpv_command_async() or mpv_command_node_async() request. ++ * See also mpv_event and mpv_event_command. + */ + MPV_EVENT_COMMAND_REPLY = 5, + /** +@@ -1276,15 +1356,16 @@ typedef enum mpv_event_id { + * removed in the far future. + */ + MPV_EVENT_UNPAUSE = 13, +-#endif + /** + * Sent every time after a video frame is displayed. Note that currently, + * this will be sent in lower frequency if there is no video, or playback + * is paused - but that will be removed in the future, and it will be + * restricted to video frames only. ++ * ++ * @deprecated Use mpv_observe_property() with relevant properties instead ++ * (such as "playback-time"). + */ + MPV_EVENT_TICK = 14, +-#if MPV_ENABLE_DEPRECATED + /** + * @deprecated This was used internally with the internal "script_dispatch" + * command to dispatch keyboard and mouse input for the OSC. +@@ -1416,7 +1497,6 @@ typedef struct mpv_event_property { + * + * Note that this is set to NULL if retrieving the property failed (the + * format will be MPV_FORMAT_NONE). +- * See mpv_event.error for the status. + */ + void *data; + } mpv_event_property; +@@ -1549,6 +1629,17 @@ typedef struct mpv_event_hook { + uint64_t id; + } mpv_event_hook; + ++// Since API version 1.102. ++typedef struct mpv_event_command { ++ /** ++ * Result data of the command. Note that success/failure is signaled ++ * separately via mpv_event.error. This field is only for result data ++ * in case of success. Most commands leave it at MPV_FORMAT_NONE. Set ++ * to MPV_FORMAT_NONE on failure. ++ */ ++ mpv_node result; ++} mpv_event_command; ++ + typedef struct mpv_event { + /** + * One of mpv_event. Keep in mind that later ABI compatible releases might +@@ -1575,6 +1666,7 @@ typedef struct mpv_event { + * MPV_EVENT_SET_PROPERTY_REPLY + * MPV_EVENT_COMMAND_REPLY + * MPV_EVENT_PROPERTY_CHANGE ++ * MPV_EVENT_HOOK + */ + uint64_t reply_userdata; + /** +@@ -1584,6 +1676,8 @@ typedef struct mpv_event { + * MPV_EVENT_LOG_MESSAGE: mpv_event_log_message* + * MPV_EVENT_CLIENT_MESSAGE: mpv_event_client_message* + * MPV_EVENT_END_FILE: mpv_event_end_file* ++ * MPV_EVENT_HOOK: mpv_event_hook* ++ * MPV_EVENT_COMMAND_REPLY* mpv_event_command* + * other: NULL + * + * Note: future enhancements might add new event structs for existing or new +diff --git a/Play/Video/mpv/render.h b/Play/Video/mpv/render.h +index 304a21a..293de3c 100644 +--- a/Play/Video/mpv/render.h ++++ b/Play/Video/mpv/render.h +@@ -94,6 +94,18 @@ extern "C" { + * - if the mpv_handle parameter refers to a different mpv core than the one + * you're rendering for (very obscure, but allowed) + * ++ * Note about old libmpv version: ++ * ++ * Before API version 1.105 (basically in mpv 0.29.x), simply enabling ++ * MPV_RENDER_PARAM_ADVANCED_CONTROL could cause deadlock issues. This can ++ * be worked around by setting the "vd-lavc-dr" option to "no". ++ * In addition, you were required to call all mpv_render*() API functions ++ * from the same thread on which mpv_render_context_create() was originally ++ * run (for the same the mpv_render_context). Not honoring it led to UB ++ * (deadlocks, use of invalid pthread_t handles), even if you moved your GL ++ * context to a different thread correctly. ++ * These problems were addressed in API version 1.105 (mpv 0.30.0). ++ * + * Context and handle lifecycle + * ---------------------------- + * +@@ -227,6 +239,13 @@ typedef enum mpv_render_param_type { + * - Rendering screenshots with the GPU API if supported by the backend + * (instead of using a suboptimal software fallback via libswscale). + * ++ * Warning: do not just add this without reading the "Threading" section ++ * above, and then wondering that deadlocks happen. The ++ * requirements are tricky. But also note that even if advanced ++ * control is disabled, not adhering to the rules will lead to ++ * playback problems. Enabling advanced controls simply makes ++ * violating these rules fatal. ++ * + * Type: int*: 0 for disable (default), 1 for enable + */ + MPV_RENDER_PARAM_ADVANCED_CONTROL = 10, +@@ -277,8 +296,7 @@ typedef enum mpv_render_param_type { + */ + MPV_RENDER_PARAM_SKIP_RENDERING = 13, + /** +- * DRM display, contains drm display handles. +- * Valid for mpv_render_context_create(). ++ * Deprecated. Not supported. Use MPV_RENDER_PARAM_DRM_DISPLAY_V2 instead. + * Type : struct mpv_opengl_drm_params* + */ + MPV_RENDER_PARAM_DRM_DISPLAY = 14, +@@ -288,6 +306,12 @@ typedef enum mpv_render_param_type { + * Type : struct mpv_opengl_drm_draw_surface_size* + */ + MPV_RENDER_PARAM_DRM_DRAW_SURFACE_SIZE = 15, ++ /** ++ * DRM display, contains drm display handles. ++ * Valid for mpv_render_context_create(). ++ * Type : struct mpv_opengl_drm_params_v2* ++ */ ++ MPV_RENDER_PARAM_DRM_DISPLAY_V2 = 16, + } mpv_render_param_type; + + /** +diff --git a/Play/Video/mpv/render_gl.h b/Play/Video/mpv/render_gl.h +index 690b126..cb141df 100644 +--- a/Play/Video/mpv/render_gl.h ++++ b/Play/Video/mpv/render_gl.h +@@ -107,11 +107,13 @@ typedef struct mpv_opengl_init_params { + /** + * This retrieves OpenGL function pointers, and will use them in subsequent + * operation. +- * Usually, GL context APIs do this for you (e.g. with glXGetProcAddressARB +- * or wglGetProcAddress), but some APIs do not always return pointers for +- * all standard functions (even if present); in this case you have to +- * compensate by looking up these functions yourself and returning them +- * from this callback. ++ * Usually, you can simply call the GL context APIs from this callback (e.g. ++ * glXGetProcAddressARB or wglGetProcAddress), but some APIs do not always ++ * return pointers for all standard functions (even if present); in this ++ * case you have to compensate by looking up these functions yourself when ++ * libmpv wants to resolve them through this callback. ++ * libmpv will not normally attempt to resolve GL functions on its own, nor ++ * does it link to GL libraries directly. + */ + void *(*get_proc_address)(void *ctx, const char *name); + /** +@@ -147,9 +149,33 @@ typedef struct mpv_opengl_fbo { + int internal_format; + } mpv_opengl_fbo; + ++/** ++ * Deprecated. For MPV_RENDER_PARAM_DRM_DISPLAY. ++ */ + typedef struct mpv_opengl_drm_params { ++ int fd; ++ int crtc_id; ++ int connector_id; ++ struct _drmModeAtomicReq **atomic_request_ptr; ++ int render_fd; ++} mpv_opengl_drm_params; ++ ++/** ++ * For MPV_RENDER_PARAM_DRM_DRAW_SURFACE_SIZE. ++ */ ++typedef struct mpv_opengl_drm_draw_surface_size { + /** +- * DRM fd (int). Set to a negative number if invalid. ++ * size of the draw plane surface in pixels. ++ */ ++ int width, height; ++} mpv_opengl_drm_draw_surface_size; ++ ++/** ++ * For MPV_RENDER_PARAM_DRM_DISPLAY_V2. ++ */ ++typedef struct mpv_opengl_drm_params_v2 { ++ /** ++ * DRM fd (int). Set to -1 if invalid. + */ + int fd; + +@@ -172,17 +198,11 @@ typedef struct mpv_opengl_drm_params { + + /** + * DRM render node. Used for VAAPI interop. +- * Set to a negative number if invalid. ++ * Set to -1 if invalid. + */ + int render_fd; +-} mpv_opengl_drm_params; ++} mpv_opengl_drm_params_v2; + +-typedef struct mpv_opengl_drm_draw_surface_size { +- /** +- * size of the draw plane surface in pixels. +- */ +- int width, height; +-} mpv_opengl_drm_draw_surface_size; + + /** + * For backwards compatibility with the old naming of mpv_opengl_drm_draw_surface_size +diff --git a/Play/Video/mpv/stream_cb.h b/Play/Video/mpv/stream_cb.h +index 01de470..63593d7 100644 +--- a/Play/Video/mpv/stream_cb.h ++++ b/Play/Video/mpv/stream_cb.h +@@ -91,7 +91,7 @@ extern "C" { + * Read callback used to implement a custom stream. The semantics of the + * callback match read(2) in blocking mode. Short reads are allowed (you can + * return less bytes than requested, and libmpv will retry reading the rest +- * with a nother call). If no data can be immediately read, the callback must ++ * with another call). If no data can be immediately read, the callback must + * block until there is new data. A return of 0 will be interpreted as final + * EOF, although libmpv might retry the read, or seek to a different position. + * +@@ -112,7 +112,7 @@ typedef int64_t (*mpv_stream_cb_read_fn)(void *cookie, char *buf, uint64_t nbyte + * is used to test whether the stream is seekable (since seekability might + * depend on the URI contents, not just the protocol). Return + * MPV_ERROR_UNSUPPORTED if seeking is not implemented for this stream. This +- * seek also servies to establish the fact that streams start at position 0. ++ * seek also serves to establish the fact that streams start at position 0. + * + * This callback can be NULL, in which it behaves as if always returning + * MPV_ERROR_UNSUPPORTED. +@@ -147,6 +147,22 @@ typedef int64_t (*mpv_stream_cb_size_fn)(void *cookie); + */ + typedef void (*mpv_stream_cb_close_fn)(void *cookie); + ++/** ++ * Cancel callback used to implement a custom stream. ++ * ++ * This callback is used to interrupt any current or future read and seek ++ * operations. It will be called from a separate thread than the demux ++ * thread, and should not block. ++ * ++ * This callback can be NULL. ++ * ++ * Available since API 1.106. ++ * ++ * @param cookie opaque cookie identifying the stream, ++ * returned from mpv_stream_cb_open_fn ++ */ ++typedef void (*mpv_stream_cb_cancel_fn)(void *cookie); ++ + /** + * See mpv_stream_cb_open_ro_fn callback. + */ +@@ -170,6 +186,7 @@ typedef struct mpv_stream_cb_info { + mpv_stream_cb_seek_fn seek_fn; + mpv_stream_cb_size_fn size_fn; + mpv_stream_cb_close_fn close_fn; ++ mpv_stream_cb_cancel_fn cancel_fn; /* since API 1.106 */ + } mpv_stream_cb_info; + + /** +diff --git a/Play/Video/mpvplayer.cpp b/Play/Video/mpvplayer.cpp +index 0e82958..4be26b4 100644 +--- a/Play/Video/mpvplayer.cpp ++++ b/Play/Video/mpvplayer.cpp +@@ -4,6 +4,8 @@ + #include <QOpenGLFramebufferObject> + #include <QOpenGLPaintDevice> + #include <QCoreApplication> ++#include <QApplication> ++#include <QDesktopWidget> + #include <QDebug> + #include <QMap> + #include <clocale> +@@ -59,12 +61,36 @@ const char *fShaderDanmu_Old = + " gl_FragColor.rgba = texture2D(u_SamplerD, v_vTexCoord).bgra;\n" + " gl_FragColor.a *= alpha;\n" + "}\n"; ++#ifdef Q_OS_WIN ++#pragma comment (lib,"user32.lib") ++#pragma comment (lib,"gdi32.lib") ++static QString get_color_profile(HWND hwnd) ++{ ++ HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); ++ MONITORINFOEXW mi; ++ mi.cbSize = sizeof mi; ++ GetMonitorInfo(monitor, (MONITORINFO*)&mi); ++ QString name; ++ ++ HDC ic = CreateICW(mi.szDevice, nullptr, nullptr, nullptr); ++ if(ic) ++ { ++ wchar_t wname[MAX_PATH + 1]; ++ DWORD bufSize(MAX_PATH); ++ if (GetICMProfile(ic, &bufSize, wname)) ++ name = QString::fromWCharArray(wname); ++ } ++ if (ic) ++ DeleteDC(ic); ++ return name; ++} ++#endif + } + MPVPlayer::MPVPlayer(QWidget *parent) : QOpenGLWidget(parent),state(PlayState::Stop), + mute(false),danmuHide(false),oldOpenGLVersion(false),currentDuration(0) + { + std::setlocale(LC_NUMERIC, "C"); +- mpv = mpv::qt::Handle::FromRawHandle(mpv_create()); ++ mpv = mpv_create(); + if (!mpv) + throw std::runtime_error("could not create mpv context"); + +@@ -83,8 +109,12 @@ MPVPlayer::MPVPlayer(QWidget *parent) : QOpenGLWidget(parent),state(PlayState::S + QString opt(option.trimmed()); + if(opt.startsWith('#'))continue; + int eqPos=opt.indexOf('='); +- mpv::qt::set_option_variant(mpv, opt.left(eqPos), opt.mid(eqPos+1)); ++ if(eqPos==-1) eqPos = opt.length(); ++ QString key(opt.left(eqPos)), val(opt.mid(eqPos+1)); ++ mpv::qt::set_option_variant(mpv, key, val); ++ optionsMap.insert(key, val); + } ++ + mpv_set_option_string(mpv, "terminal", "yes"); + mpv_set_option_string(mpv, "keep-open", "yes"); + // Make use of the MPV_SUB_API_OPENGL_CB API. +@@ -96,9 +126,6 @@ MPVPlayer::MPVPlayer(QWidget *parent) : QOpenGLWidget(parent),state(PlayState::S + mpv::qt::set_option_variant(mpv,"no-resume-playback",""); + */ + +- mpv_gl = (mpv_opengl_cb_context *)mpv_get_sub_api(mpv, MPV_SUB_API_OPENGL_CB); +- if (!mpv_gl) throw std::runtime_error("OpenGL not compiled in"); +- mpv_opengl_cb_set_update_callback(mpv_gl, MPVPlayer::on_update, (void *)this); + QObject::connect(this, &MPVPlayer::frameSwapped, this,&MPVPlayer::swapped); + + mpv_observe_property(mpv, 0, "duration", MPV_FORMAT_DOUBLE); +@@ -116,11 +143,8 @@ MPVPlayer::MPVPlayer(QWidget *parent) : QOpenGLWidget(parent),state(PlayState::S + MPVPlayer::~MPVPlayer() + { + makeCurrent(); +- if (mpv_gl) mpv_opengl_cb_set_update_callback(mpv_gl, nullptr, nullptr); +- // Until this call is done, we need to make sure the player remains +- // alive. This is done implicitly with the mpv::qt::Handle instance +- // in this class. +- mpv_opengl_cb_uninit_gl(mpv_gl); ++ if (mpv_gl) mpv_render_context_free(mpv_gl); ++ mpv_terminate_destroy(mpv); + } + + MPVPlayer::VideoSizeInfo MPVPlayer::getVideoSizeInfo() +@@ -188,6 +212,24 @@ QMap<QString, QMap<QString, QString> > MPVPlayer::getMediaInfo() + return mediaInfo; + } + ++void MPVPlayer::setOptions() ++{ ++ if(optionsMap.contains("icc-profile-auto")) ++ { ++#ifdef Q_OS_WIN ++ if(this->parent()) ++ { ++ QWidget *pWidget = dynamic_cast<QWidget *>(this->parent()); ++ if(pWidget) ++ { ++ QString iccProfile(get_color_profile((HWND)pWidget->winId())); ++ mpv::qt::set_option_variant(mpv, "icc-profile",iccProfile); ++ } ++ } ++#endif ++ } ++} ++ + void MPVPlayer::drawTexture(QList<const DanmuObject *> &objList, float alpha) + { + static QVector<GLfloat> vtx(6*2*64),tex(6*2*64),texId(6*64); +@@ -399,9 +441,20 @@ void MPVPlayer::screenshot(QString filename) + + void MPVPlayer::initializeGL() + { +- int r = mpv_opengl_cb_init_gl(mpv_gl, nullptr, MPVPlayer::get_proc_address, nullptr); +- if (r < 0) +- throw std::runtime_error("could not initialize OpenGL"); ++ mpv_opengl_init_params gl_init_params{get_proc_address, nullptr, nullptr}; ++ mpv_render_param params[]{ ++ {MPV_RENDER_PARAM_API_TYPE, const_cast<char *>(MPV_RENDER_API_TYPE_OPENGL)}, ++ {MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &gl_init_params}, ++ {MPV_RENDER_PARAM_INVALID, nullptr} ++ }; ++ ++ if (mpv_render_context_create(&mpv_gl, mpv, params) < 0) ++ throw std::runtime_error("failed to initialize mpv GL context"); ++ mpv_render_context_set_update_callback(mpv_gl, MPVPlayer::on_update, reinterpret_cast<void *>(this)); ++ ++ //int r = mpv_opengl_cb_init_gl(mpv_gl, nullptr, MPVPlayer::get_proc_address, nullptr); ++ //if (r < 0) ++ // throw std::runtime_error("could not initialize OpenGL"); + + QOpenGLFunctions *glFuns=context()->functions(); + const char *version = reinterpret_cast<const char*>(glFuns->glGetString(GL_VERSION)); +@@ -434,7 +487,17 @@ void MPVPlayer::initializeGL() + + void MPVPlayer::paintGL() + { +- mpv_opengl_cb_draw(mpv_gl, defaultFramebufferObject(), width(), -height()); ++ mpv_opengl_fbo mpfbo{static_cast<int>(defaultFramebufferObject()), width(), height(), 0}; ++ int flip_y{1}; ++ ++ mpv_render_param params[] = { ++ {MPV_RENDER_PARAM_OPENGL_FBO, &mpfbo}, ++ {MPV_RENDER_PARAM_FLIP_Y, &flip_y}, ++ {MPV_RENDER_PARAM_INVALID, nullptr} ++ }; ++ // See render_gl.h on what OpenGL environment mpv expects, and ++ // other API details. ++ mpv_render_context_render(mpv_gl, params); + if(!danmuHide) + { + QOpenGLFramebufferObject::bindDefault(); +@@ -448,7 +511,6 @@ void MPVPlayer::paintGL() + + void MPVPlayer::swapped() + { +- mpv_opengl_cb_report_flip(mpv_gl, 0); + if(state==PlayState::Play) + { + float step(0.f); +diff --git a/Play/Video/mpvplayer.h b/Play/Video/mpvplayer.h +index 1ccc9f9..e9e4d50 100644 +--- a/Play/Video/mpvplayer.h ++++ b/Play/Video/mpvplayer.h +@@ -5,7 +5,7 @@ + #include <QtCore> + #include <QtGui> + #include <mpv/client.h> +-#include <mpv/opengl_cb.h> ++#include <mpv/render_gl.h> + #include <mpv/qthelper.hpp> + #include "Play/Danmu/common.h" + class DanmuRender; +@@ -47,6 +47,7 @@ public: + + VideoSizeInfo getVideoSizeInfo(); + QMap<QString,QMap<QString,QString> > getMediaInfo(); ++ void setOptions(); + void drawTexture(QList<const DanmuObject *> &objList, float alpha); + signals: + void fileChanged(); +@@ -86,8 +87,8 @@ private: + QStringList desc_str; + QList<int> ids; + }; +- mpv::qt::Handle mpv; +- mpv_opengl_cb_context *mpv_gl; ++ mpv_handle *mpv; ++ mpv_render_context *mpv_gl; + void handle_mpv_event(mpv_event *event); + static void on_update(void *ctx); + static void wakeup(void *ctx); +@@ -103,6 +104,7 @@ private: + QOpenGLShaderProgram danmuShader; + QTimer refreshTimer; + QElapsedTimer elapsedTimer; ++ QMap<QString, QString> optionsMap; + + int currentDuration; + TrackInfo audioTrack,subtitleTrack; +diff --git a/UI/about.cpp b/UI/about.cpp +index 9fbda30..927baef 100644 +--- a/UI/about.cpp ++++ b/UI/about.cpp +@@ -13,7 +13,7 @@ About::About(QWidget *parent) : CFramelessDialog("",parent) + QJsonObject curVersionObj = QJsonDocument::fromJson(version.readAll()).object(); + QString versionStr=curVersionObj.value("Version").toString(); + QLabel *info=new QLabel(tr("KikoPlay - A Full-featured Danmu Player<br/>" +- "%1 (C) 2019 Kikyou <a href=\"https://protostars.github.io/KikoPlay/\">homepage</a> <a href=\"https://github.com/Protostars/KikoPlay\">github</a><br/>" ++ "%1 (C) 2020 Kikyou <a href=\"https://protostars.github.io/KikoPlay/\">homepage</a> <a href=\"https://github.com/Protostars/KikoPlay\">github</a><br/>" + "Exchange & BUG Report: 874761809(QQ Group)").arg(versionStr),this); + info->setOpenExternalLinks(true); + info->setAlignment(Qt::AlignCenter); +diff --git a/UI/animedetailinfo.h b/UI/animedetailinfo.h +index 5bab9b7..206f4e4 100644 +--- a/UI/animedetailinfo.h ++++ b/UI/animedetailinfo.h +@@ -2,6 +2,7 @@ + #define ANIMEDETAILINFO_H + + #include "framelessdialog.h" ++#include <QMap> + struct Anime; + struct Character; + class CharacterItem : public QWidget +diff --git a/UI/captureview.cpp b/UI/captureview.cpp +index 754c70c..15008ae 100644 +--- a/UI/captureview.cpp ++++ b/UI/captureview.cpp +@@ -7,6 +7,8 @@ + #include <QApplication> + #include <QClipboard> + #include <QFileDialog> ++#include <QMouseEvent> ++#include <QWheelEvent> + CaptureView::CaptureView(CaptureListModel *captureModel, int curRow, QWidget *parent) : CFramelessDialog("",parent,false,true,false) + { + this->curRow=curRow; +diff --git a/UI/mpvlog.cpp b/UI/mpvlog.cpp +index 155efa1..fee6590 100644 +--- a/UI/mpvlog.cpp ++++ b/UI/mpvlog.cpp +@@ -8,7 +8,7 @@ MPVLog::MPVLog(QWidget *parent) : CFramelessDialog(tr("MPV Log"),parent,false,tr + { + QPlainTextEdit *logView=new QPlainTextEdit(this); + logView->setReadOnly(true); +- logView->setMaximumBlockCount(256); ++ logView->setMaximumBlockCount(1024); + QObject::connect(GlobalObjects::mpvplayer,&MPVPlayer::showLog,[logView](const QString &log){ + logView->appendPlainText(log.trimmed()); + QTextCursor cursor = logView->textCursor(); +diff --git a/UI/player.cpp b/UI/player.cpp +index 2de7449..1c029d0 100644 +--- a/UI/player.cpp ++++ b/UI/player.cpp +@@ -213,6 +213,7 @@ PlayerWindow::PlayerWindow(QWidget *parent) : QMainWindow(parent),autoHideContro + setCentralWidget(GlobalObjects::mpvplayer); + GlobalObjects::mpvplayer->setMouseTracking(true); + setContentsMargins(0,0,0,0); ++ GlobalObjects::mpvplayer->setOptions(); + + logDialog=new MPVLog(this); + +diff --git a/UI/tip.cpp b/UI/tip.cpp +index a80b5d5..216490a 100644 +--- a/UI/tip.cpp ++++ b/UI/tip.cpp +@@ -1,6 +1,7 @@ + #include "tip.h" + #include <QLabel> + #include <QVBoxLayout> ++#include <QFile> + Tip::Tip(QWidget *parent) : CFramelessDialog (tr("Tip"),parent) + { + QLabel *tipContent=new QLabel(this); +diff --git a/kikoplay.rc b/kikoplay.rc +index 48fc00b..608f9a6 100644 +Binary files a/kikoplay.rc and b/kikoplay.rc differ +diff --git a/lib/x64/libmpv.dll.lib b/lib/x64/libmpv.dll.lib +index 503fe77..79ead29 100644 +Binary files a/lib/x64/libmpv.dll.lib and b/lib/x64/libmpv.dll.lib differ +diff --git a/res/about b/res/about +index 7166e66..1c596bb 100644 +--- a/res/about ++++ b/res/about +@@ -1,8 +1,8 @@ + KikoPlay is based on the following projects: + Qt 5.12.3 +-libmpv 0.29.1 ++libmpv 0.31.0 + aria2 1.34 + Qt-Nice-Frameless-Window + zlib 1.2.11 + QHttpEngine 1.01 +-Lua 5.3 +\ No newline at end of file ++Lua 5.3 diff --git a/media-video/kikoplay/kikoplay-0.6.0.ebuild b/media-video/kikoplay/kikoplay-0.6.0.ebuild new file mode 100644 index 000000000..17438e0e3 --- /dev/null +++ b/media-video/kikoplay/kikoplay-0.6.0.ebuild @@ -0,0 +1,78 @@ +# Copyright 1999-2020 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=7 + +GIT_PN="KikoPlay" + +inherit qmake-utils xdg + +DESCRIPTION="KikoPlay is a full-featured danmu player" +HOMEPAGE=" + https://kikoplay.fun + https://github.com/Protostars/KikoPlay +" + +if [[ ${PV} == "9999" ]] ; then + inherit git-r3 + EGIT_REPO_URI="https://github.com/Protostars/${GIT_PN}.git" +else + SRC_URI="https://github.com/Protostars/${GIT_PN}/archive/${PV}.tar.gz -> ${P}.tar.gz" + KEYWORDS="~amd64 ~arm ~arm64 ~hppa ~m68k ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" + S="${WORKDIR}/${GIT_PN}-${PV}" +fi + +LICENSE="GPL-3" +SLOT="0" + +RDEPEND=" + dev-lang/lua:5.3 + dev-libs/qhttpengine:5 + dev-qt/qtconcurrent:5 + dev-qt/qtcore:5 + dev-qt/qtgui:5 + dev-qt/qtnetwork:5 + dev-qt/qtsql:5 + dev-qt/qtwidgets:5 + media-video/mpv[libmpv,-luajit] + net-misc/aria2 +" + +DEPEND=" + ${RDEPEND} +" + +BDEPEND=" + media-gfx/imagemagick + virtual/pkgconfig +" + +PATCHES=( + "${FILESDIR}"/${PN}-0.6.0-install.patch # Fix install problem + "${FILESDIR}"/${PN}-0.6.0-desktop.patch # Add a desktop file + "${FILESDIR}"/${PN}-0.6.0-home.patch # Add a desktop file +) + +src_prepare() { + default + # Fix lua link problem, link to lua5.3 to fix bug + sed -i "s/-llua/-llua5.3/" KikoPlay.pro || die "Could not fix lua link" + echo "target.path += /usr/bin" >> KikoPlay.pro || die "Could not fix install path" + echo "INSTALLS += target icons desktop" >> KikoPlay.pro || die "Could not fix install target" + echo "unix:icons.path = /usr/share/pixmaps" >> KikoPlay.pro || die "Could not fix install icon PATH" + echo "unix:desktop.path = /usr/share/applications" >> KikoPlay.pro || die "Could not fix install desktop PATH" + echo "unix:icons.files = kikoplay.png kikoplay.xpm" >> KikoPlay.pro || die "Could not fix install desktop PATH" + echo "unix:desktop.files = kikoplay.desktop" >> KikoPlay.pro || die "Could not fix install desktop PATH" + echo "DEFINES += CONFIG_HOME_DATA" >> KikoPlay.pro || die "Could not set defines" + convert kikoplay.ico kikoplay.png || die "Could not create PNG icon" + convert kikoplay.ico kikoplay.xpm || die "Could not create XPM icon" +} + +src_configure() { + eqmake5 PREFIX="${D}"/usr +} + +src_install() { + # Can't use default, set INSTALL_ROOT + emake INSTALL_ROOT="${D}" install +} diff --git a/media-video/kikoplay/metadata.xml b/media-video/kikoplay/metadata.xml new file mode 100644 index 000000000..514daa85b --- /dev/null +++ b/media-video/kikoplay/metadata.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<pkgmetadata> + <maintainer type="person"> + <email>vowstar@gmail.com</email> + <name>Huang Rui</name> + </maintainer> + <upstream> + <remote-id type="github">Protostars/KikoPlay</remote-id> + </upstream> + <longdescription> + KikoPlay - A Full-Featured Danmu Player. + OpenGL rendering, smooth barrage experience. The libmpv playback kernel + supports multiple media file formats, retaining flexible parameter settings + for mpv. + Tree playlist, you can organize your fan play at will. + Support all major video sites for barrage search and download: + AcFun, Bilibili, Tucao, 5dm, Bahamut, iQiyi, Youku, Tencent Video, PPTV + Flexible barrage shielding rule setting, support for automatically merging + similar barrage and barrage event analysis annotations to enhance the + viewing experience. + Support batch management of the barrage pool, support the adjustment of the + barrage timeline, and better handle the inconsistency between the local + video and the video on the website. + The database can record and organize the dramas you have watched, and you + can get detailed information from Bangumi LAN service, you can watch it on + other devices through the webpage, and now there is an Android side to + choose from. + Integrated aria2 download function. Daily broadcast function: you can + quickly browse the new fan list and add followers. + Based on the resource search function of Lua script, you can also write + scripts for KikoPlay, script repository. + Support automatic downloading, by setting rules, KikoPlay can automatically + search for download resources. + Unique KikoPlay resource code and barrage pool code, can directly share + resource links containing barrage pool information. + </longdescription> +</pkgmetadata> |