Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support passing URLs as cmdline arguments #15

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ qt_wrap_cpp(MOC_FILES
mpvwidget.h
playerwidget.h
playercontroller.h
program_arg.h
tracksmenu.h
autohidewidget.h # From SMPlayer
singleinstance.h
Expand Down Expand Up @@ -75,6 +76,7 @@ set(MAIN_SRC
mpvwidget.cpp
playerwidget.cpp
playercontroller.cpp
program_arg.cpp
tracksmenu.cpp
autohidewidget.cpp # From SMPlayer
config.cpp
Expand Down
17 changes: 13 additions & 4 deletions helper.cpp
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks really useful for achieving accepting URLs. Needs testing and fixing mentioned issue, but anyway.

Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,20 @@ void Helper::searchWithMaxDepth(QStringList &outList, const QStringList &filter,
const QList<QUrl> Helper::pathsToUrls(const QStringList &paths)
{
QList<QUrl> ret;
for (auto &arg : paths)
for (const auto &arg : paths)
{
QFileInfo f(arg);
if (f.exists())
ret.append(QUrl(f.absoluteFilePath()));
// FIXME: URLs with spaces don't work
QUrl url(arg);
//QUrl::isLocalFile() is not reliable if the file doesn't exist
if (url.isValid() && !url.isLocalFile() && !url.host().isEmpty())
ret.append(url);
else {
QFileInfo f(arg);
if (f.exists())
ret.append(QUrl(f.absoluteFilePath()));
else
qDebug() << "Path " << f.path() << "does not exist, skipping";;
}
}
return ret;
}
28 changes: 13 additions & 15 deletions kokovp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "config.h"
#include "cache.h"
#include "helper.h"
#include "program_arg.h"

#include "prefs/prefdialog.h"
#include "persistency/filesettingshash.h"
Expand All @@ -48,7 +49,7 @@ QString extfolderRewriteRule(const PlayerController::Track &t)
if (!t.isExternal)
return QString();

QFileInfo fI(t.filename);
QFileInfo fI(t.mediaUrl);
QString fName = fI.fileName();

if (fName==t.title)
Expand Down Expand Up @@ -77,8 +78,8 @@ KokoVP::KokoVP(QWidget *parent)
createPlaylistDock();

connect(player, &PlayerController::tracksUpdated, this, &KokoVP::handleTracks);
connect(player, &PlayerController::fileMetaUpdated, playlist, &Playlist::setCurrentRowMetainfo);
connect(player, &PlayerController::endFile, this, &KokoVP::handleEOF);
connect(player, &PlayerController::mediaMetaUpdated, playlist, &Playlist::setCurrentRowMetainfo);
connect(player, &PlayerController::endMediaRessource, this, &KokoVP::handleEOF);
connect(playerWidget, &PlayerWidget::draggedURLS, playlist, &Playlist::addURLs);
connect(playlist, &Playlist::playRequest, this, qOverload<QUrl>(&KokoVP::playFile));

Expand Down Expand Up @@ -154,18 +155,15 @@ KokoVP::KokoVP(QWidget *parent)

KokoVP::~KokoVP()
{
fileSettings->saveSettingsFor(player->lastOpenFile(), true); // Always save time-pos on exit
fileSettings->saveSettingsFor(player->lastOpenMediaUrl(), true); // Always save time-pos on exit
}

void KokoVP::handleNewMessage(QString msg)
void KokoVP::handleNewMessage(const ProgramArgument &msg)
{
int del = msg.indexOf(':');
QString cmd = msg.left(del);
QStringList args = msg.trimmed().mid(del+1).split(',');
if (cmd=="open")
playlist->addURLs(Helper::pathsToUrls(args));
else if (cmd=="playlast")
QTimer::singleShot(100, playlist, &Playlist::playLast); // Workaroun to wait until Qt event loop and libmpv will be ready
if (msg.cmd==ProgramCmd::OPEN)
playlist->addURLs(Helper::pathsToUrls(msg.args));
else if (msg.cmd==ProgramCmd::PLAYLAST)
QTimer::singleShot(100, playlist, &Playlist::playLast); // Workaround to wait until Qt event loop and libmpv will be ready
}

void KokoVP::toggleFullscreen(bool on)
Expand Down Expand Up @@ -481,13 +479,13 @@ void KokoVP::handleTracks()
};
}
if (Config::i().get("play_mode/keep_props", true).toBool())
fileSettings->loadSettingsFor(player->currentFile(), Config::i().get("play_mode/keep_timepos", true).toBool());
fileSettings->loadSettingsFor(player->currentMediaUrl(), Config::i().get("play_mode/keep_timepos", true).toBool());
}

void KokoVP::handleEOF(bool wasStopped)
{
setWindowTitle("KokoVP");
fileSettings->saveSettingsFor(player->lastOpenFile(), wasStopped); // If file is ended, then time-pos shouldn't be saved
fileSettings->saveSettingsFor(player->lastOpenMediaUrl(), wasStopped); // If file is ended, then time-pos shouldn't be saved
player->prop("pause")->set(true);
if (!wasStopped && Config::i().get("play_mode/next_on_eof", true).toBool())
playlist->next();
Expand Down Expand Up @@ -546,7 +544,7 @@ void KokoVP::setAudioDevice(QAction *audioDeviceAction)

void KokoVP::tryPlayCurrent()
{
if (player->currentFile().isEmpty())
if (player->currentMediaUrl().isEmpty())
playlist->playCurrent();
}

Expand Down
2 changes: 1 addition & 1 deletion kokovp.desktop
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[Desktop Entry]
Categories=Qt;AudioVideo;Player;Video;
Comment=A modern mpv-based player
Exec=kokovp %F
Exec=kokovp %U
GenericName=Media Player
MimeType=application/ogg;application/x-ogg;application/mxf;application/vnd.rn-realmedia;application/vnd.rn-realmedia-vbr;audio/aac;audio/x-aac;audio/vnd.dolby.heaac.1;audio/vnd.dolby.heaac.2;audio/aiff;audio/x-aiff;audio/m4a;audio/x-m4a;application/x-extension-m4a;audio/mp1;audio/x-mp1;audio/mp2;audio/x-mp2;audio/mp3;audio/x-mp3;audio/mpeg;audio/mpeg2;audio/mpeg3;audio/mpg;audio/x-mpg;audio/rn-mpeg;audio/x-musepack;audio/ogg;audio/vnd.rn-realaudio;audio/wav;audio/x-pn-wav;audio/x-pn-windows-pcm;audio/x-realaudio;audio/x-pn-realaudio;audio/x-ms-wma;audio/x-wav;video/mpeg;video/x-mpeg2;video/x-mpeg3;video/mp4v-es;video/x-m4v;video/mp4;application/x-extension-mp4;video/divx;video/vnd.divx;video/msvideo;video/x-msvideo;video/ogg;video/quicktime;video/vnd.rn-realvideo;video/x-ms-wmv;video/x-ms-wmx;video/x-ms-wvxvideo;video/x-avi;video/avi;video/x-flic;video/fli;video/x-flc;video/flv;video/x-flv;video/x-theora;video/x-theora+ogg;video/x-matroska;video/mkv;audio/x-matroska;application/x-matroska;video/webm;audio/webm;audio/vorbis;audio/x-vorbis;audio/x-vorbis+ogg;video/x-ogm;video/x-ogm+ogg;application/x-ogm;application/x-ogm-audio;application/x-ogm-video;application/x-shorten;audio/x-shorten;audio/x-ape;audio/x-wavpack;audio/x-tta;audio/AMR;audio/ac3;audio/eac3;audio/amr-wb;video/mp2t;audio/flac;audio/mp4;audio/x-pn-au;video/3gp;video/3gpp;video/3gpp2;audio/3gpp;audio/3gpp2;video/dv;audio/dv;audio/opus;audio/vnd.dts;audio/vnd.dts.hd;audio/x-adpcm;audio/vnd.wave;video/vnd.avi;
Name=KokoVP
Expand Down
3 changes: 2 additions & 1 deletion kokovp.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class Playlist;
class TracksMenu;
class AutohideWidget;
class FileSettingsHash;
struct ProgramArgument;
class QTableView;

using QActionMap = QMap<QString, QAction*>;
Expand All @@ -40,7 +41,7 @@ class KokoVP : public QMainWindow
~KokoVP();
static KokoVP *i() { return inst; }
QActionMap actionsMap() const { return p_actionsMap; }
void handleNewMessage(QString msg);
void handleNewMessage(const ProgramArgument &msg);
private:
void toggleFullscreen(bool on);

Expand Down
8 changes: 5 additions & 3 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <QDir>
#include <QCommandLineParser>

#include "program_arg.h"
#include "singleinstance.h"

int main(int argc, char *argv[])
Expand All @@ -36,6 +37,7 @@ int main(int argc, char *argv[])
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument("media", QCoreApplication::translate("KokoVP", "Media files to play"));
parser.addPositionalArgument("urls", QCoreApplication::translate("KokoVP", "URLs to play"));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How multiple position arguments lists should work at all? Maybe just accept media by local file paths and by urls?


// A boolean option with a single name (-p)
QCommandLineOption newInstanceOption(QStringList() << "n" << "new-instance", QCoreApplication::translate("KokoVP", "Force open in new instance"));
Expand All @@ -58,7 +60,7 @@ int main(int argc, char *argv[])
{
if (inst.connectServer())
{
inst.sendMessage("open:" + parser.positionalArguments().join(','));
inst.sendMessage(ProgramArgument(ProgramCmd::OPEN, parser.positionalArguments()));
inst.closeSocket();
return 0;
}
Expand All @@ -70,8 +72,8 @@ int main(int argc, char *argv[])
KokoVP w;
if (parser.positionalArguments().length()>0)
{
w.handleNewMessage("open:" + parser.positionalArguments().join(','));
w.handleNewMessage("playlast");
w.handleNewMessage(ProgramArgument(ProgramCmd::OPEN, parser.positionalArguments()));
w.handleNewMessage(ProgramArgument(ProgramCmd::PLAYLAST));
}
QObject::connect(&inst, &SingleInstance::newMessage, &w, &KokoVP::handleNewMessage);
w.showNormal();
Expand Down
40 changes: 20 additions & 20 deletions playercontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ PlayerController::PlayerController(PlayerWidget *parent)
prop("volume")->set(50);
prop("pause")->set(true);
p->setProp("audio-file-auto-exts", Extensions.audio());
connect(p, &PlayerWidget::fileLoaded, this, &PlayerController::handleFileLoad);
connect(p, &PlayerWidget::endFile, this, &PlayerController::endFile);
connect(p, &PlayerWidget::endFile, this, &PlayerController::handleFileEnd);
connect(p, &PlayerWidget::fileLoaded, this, &PlayerController::handleMediaLoad);
connect(p, &PlayerWidget::endFile, this, &PlayerController::endMediaRessource);
connect(p, &PlayerWidget::endFile, this, &PlayerController::handleMediaEnd);
}

PropertyObserver *PlayerController::prop(QString name)
Expand All @@ -51,31 +51,31 @@ void PlayerController::setOption(const QString &name, const QVariant &value)
p->setOption(name, value);
}

void PlayerController::handleFileEnd()
void PlayerController::handleMediaEnd()
{
haveFile = false;
if (!queuedFile.isEmpty())
haveMediaUrl = false;
if (!queuedMediaUrl.isEmpty())
{
QUrl f = queuedFile;
queuedFile = QUrl();
open(f);
QUrl url = queuedMediaUrl;
queuedMediaUrl = QUrl();
open(url);
}
}

void PlayerController::open(const QUrl &file)
void PlayerController::open(const QUrl &url)
{
if (haveFile)
if (haveMediaUrl)
{
queuedFile = file;
queuedMediaUrl = url;
return stop();
}
p_tracks.clear();

// Here we need to scan siblings folder for possible external subtitles and audio
//, then set it to sub-file-paths and audio-file-paths OPTIONs (not properties)
if (file.isLocalFile())
if (url.isLocalFile())
{
QDir mediaDir = QFileInfo(file.toLocalFile()).absoluteDir();
QDir mediaDir = QFileInfo(url.toLocalFile()).absoluteDir();

if (p_extSubMaxDepth>=0 && p_extSubMode!="no")
{
Expand All @@ -94,7 +94,7 @@ void PlayerController::open(const QUrl &file)
}
}

p->command(QStringList{"loadfile", file.path()});
p->command(QStringList{"loadfile", url.toString()});
}

void PlayerController::stop()
Expand Down Expand Up @@ -164,10 +164,10 @@ bool PlayerController::isPlaying()
return !getProp("pause").toBool();
}

void PlayerController::handleFileLoad()
void PlayerController::handleMediaLoad()
{
lastFile = currentFile();
haveFile = true;
lastMediaUrl = currentMediaUrl();
haveMediaUrl = true;
bool ok;
int tracksCount = getProp("track-list/count").toInt(&ok);
assert(ok);
Expand All @@ -188,7 +188,7 @@ void PlayerController::handleFileLoad()
t.type = Track::TRACK_TYPE_SUB;

if (t.isExternal)
t.filename = p->getProp(trackAddr + "external-filename").toString();
t.mediaUrl = p->getProp(trackAddr + "external-mediaUrl").toString();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wont work. external-filename is the mpv's keyword.


p_tracks.append(t);
}
Expand All @@ -200,5 +200,5 @@ void PlayerController::handleFileLoad()

p->setProp("pause", false); // Previous file can be paused, when new file is loaded, it's time to de-pause player
emit tracksUpdated();
emit fileMetaUpdated(p->getProp("media-title").toString(), prop("duration")->get().toDouble());
emit mediaMetaUpdated(p->getProp("media-title").toString(), prop("duration")->get().toDouble());
}
22 changes: 11 additions & 11 deletions playercontroller.h
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Massive rename without exact purpose. file can be accessed by url as well.

Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ class PlayerController : public QObject
TrackType type;
QString title;
QString lang;
QString filename;
QString mediaUrl;
bool isExternal;
};

explicit PlayerController(PlayerWidget *parent = nullptr);

QString currentFile() { return getProp("path").toString(); }
QString lastOpenFile() { return lastFile; }
QString currentMediaUrl() { return getProp("path").toString(); }
QString lastOpenMediaUrl() { return lastMediaUrl; }

PropertyObserver *prop(QString name);
void setProp(const QString& name, const QVariant& value);
Expand All @@ -58,7 +58,7 @@ class PlayerController : public QObject
void setExtSubOptions(QString mode, int depth) { p_extSubMode = mode; p_extSubMaxDepth = depth; }
void setExtAudioOptions(QString mode, int depth) { p_extAudioMode = mode; p_extAudioMaxDepth = depth; }

void open(const QUrl &file);
void open(const QUrl &url);
void stop();

void togglePlayback();
Expand All @@ -82,11 +82,11 @@ class PlayerController : public QObject

signals:
void tracksUpdated();
void fileMetaUpdated(QString label, double duration);
void endFile(bool wasStopped);
void mediaMetaUpdated(QString label, double duration);
void endMediaRessource(bool wasStopped);
private:
void handleFileEnd();
void handleFileLoad();
void handleMediaEnd();
void handleMediaLoad();

PlayerWidget *p;

Expand All @@ -98,9 +98,9 @@ class PlayerController : public QObject

QList<Track> p_tracks;

QUrl queuedFile;
QString lastFile;
bool haveFile = false;
QUrl queuedMediaUrl;
QString lastMediaUrl;
bool haveMediaUrl = false;
};

#endif // PLAYERCONTROLLER_H
20 changes: 20 additions & 0 deletions program_arg.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include <QDataStream>

#include "program_arg.h"

ProgramArgument::ProgramArgument(const ProgramCmd &cmd, const QStringList &args)
: cmd{cmd}, args{args}
{
}

QDataStream &operator>>(QDataStream &istream, ProgramArgument &pa)
{
istream >> pa.cmd >> pa.args;
return istream;
}

QDataStream &operator<<(QDataStream &ostream, const ProgramArgument &pa)
{
ostream << pa.cmd << pa.args;
return ostream;
}
27 changes: 27 additions & 0 deletions program_arg.h
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

program_arg is over-engineering. SingleInstance is designed to be as simple as possible stream communication and doesn't require additional structure.

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef PROGRAM_ARG_H
#define PROGRAM_ARG_H

#include <QString>
#include <QStringList>

class QDataStream;

enum class ProgramCmd
{
NONE,
OPEN,
PLAYLAST,
};

struct ProgramArgument
{
explicit ProgramArgument(const ProgramCmd &cmd = ProgramCmd::NONE, const QStringList &args = QStringList());

ProgramCmd cmd;
QStringList args;

friend QDataStream &operator>>(QDataStream &istream, ProgramArgument &pa);
friend QDataStream &operator<<(QDataStream &ostream, const ProgramArgument &pa);
};

#endif
Loading