1 #include <cmath>
2 #include "manager.h"
3 #include "mainwindow.h"
4 #include "mpvwidget.h"
5 #include "helpers.h"
6
7 using namespace Helpers;
8
9
PlaybackManager(QObject * parent)10 PlaybackManager::PlaybackManager(QObject *parent) :
11 QObject(parent)
12 {
13 }
14
setMpvObject(MpvObject * mpvObject,bool makeConnections)15 void PlaybackManager::setMpvObject(MpvObject *mpvObject, bool makeConnections)
16 {
17 mpvObject_ = mpvObject;
18
19 if (makeConnections) {
20 connect(mpvObject, &MpvObject::playTimeChanged,
21 this, &PlaybackManager::mpvw_playTimeChanged);
22 connect(mpvObject, &MpvObject::playLengthChanged,
23 this, &PlaybackManager::mpvw_playLengthChanged);
24 connect(mpvObject, &MpvObject::seekableChanged,
25 this, &PlaybackManager::mpvw_seekableChanged);
26 connect(mpvObject, &MpvObject::playbackLoading,
27 this, &PlaybackManager::mpvw_playbackLoading);
28 connect(mpvObject, &MpvObject::playbackStarted,
29 this, &PlaybackManager::mpvw_playbackStarted);
30 connect(mpvObject, &MpvObject::pausedChanged,
31 this, &PlaybackManager::mpvw_pausedChanged);
32 connect(mpvObject, &MpvObject::playbackIdling,
33 this, &PlaybackManager::mpvw_playbackIdling);
34 connect(mpvObject, &MpvObject::mediaTitleChanged,
35 this, &PlaybackManager::mpvw_mediaTitleChanged);
36 connect(mpvObject, &MpvObject::chapterDataChanged,
37 this, &PlaybackManager::mpvw_chapterDataChanged);
38 connect(mpvObject, &MpvObject::chaptersChanged,
39 this, &PlaybackManager::mpvw_chaptersChanged);
40 connect(mpvObject, &MpvObject::tracksChanged,
41 this, &PlaybackManager::mpvw_tracksChanged);
42 connect(mpvObject, &MpvObject::videoSizeChanged,
43 this, &PlaybackManager::mpvw_videoSizeChanged);
44 connect(mpvObject, &MpvObject::fpsChanged,
45 this, &PlaybackManager::mpvw_fpsChanged);
46 connect(mpvObject, &MpvObject::avsyncChanged,
47 this, &PlaybackManager::mpvw_avsyncChanged);
48 connect(mpvObject, &MpvObject::displayFramedropsChanged,
49 this, &PlaybackManager::mpvw_displayFramedropsChanged);
50 connect(mpvObject, &MpvObject::decoderFramedropsChanged,
51 this, &PlaybackManager::mpvw_decoderFramedropsChanged);
52 connect(mpvObject, &MpvObject::metaDataChanged,
53 this, &PlaybackManager::mpvw_metadataChanged);
54 connect(mpvObject, &MpvObject::playlistChanged,
55 this, &PlaybackManager::mpvw_playlistChanged);
56 connect(mpvObject, &MpvObject::audioBitrateChanged,
57 this, &PlaybackManager::mpvw_audioBitrateChanged);
58 connect(mpvObject, &MpvObject::videoBitrateChanged,
59 this, &PlaybackManager::mpvw_videoBitrateChanged);
60
61 connect(this, &PlaybackManager::hasNoVideo,
62 mpvObject, &MpvObject::setDrawLogo);
63 }
64 }
65
setPlaylistWindow(PlaylistWindow * playlistWindow)66 void PlaybackManager::setPlaylistWindow(PlaylistWindow *playlistWindow)
67 {
68 playlistWindow_ = playlistWindow;
69 connect(playlistWindow, &PlaylistWindow::itemDesired,
70 this, &PlaybackManager::playItem);
71 connect(this, &PlaybackManager::nowPlayingChanged,
72 playlistWindow, &PlaylistWindow::changePlaylistSelection);
73 }
74
nowPlaying()75 QUrl PlaybackManager::nowPlaying()
76 {
77 return nowPlaying_;
78 }
79
playbackState()80 PlaybackManager::PlaybackState PlaybackManager::playbackState()
81 {
82 return playbackState_;
83 }
84
openSeveralFiles(QList<QUrl> what,bool important)85 void PlaybackManager::openSeveralFiles(QList<QUrl> what, bool important)
86 {
87 if (important) {
88 playlistWindow_->setCurrentPlaylist(QUuid());
89 playlistWindow_->clearPlaylist(QUuid());
90 }
91 bool playAfterAdd = (playlistWindow_->isCurrentPlaylistEmpty()
92 && (important || nowPlayingItem == QUuid()))
93 || !playlistWindow_->isVisible();
94 auto info = playlistWindow_->addToCurrentPlaylist(what);
95 if (playAfterAdd && !info.second.isNull()) {
96 QUrl urlToPlay = playlistWindow_->getUrlOf(info.first, info.second);
97 startPlayWithUuid(urlToPlay, info.first, info.second, false);
98 }
99 }
100
openFile(QUrl what,QUrl with)101 void PlaybackManager::openFile(QUrl what, QUrl with)
102 {
103 auto info = playlistWindow_->urlToQuickPlaylist(what);
104 if (!info.second.isNull()) {
105 QUrl urlToPlay = playlistWindow_->getUrlOf(info.first, info.second);
106 startPlayWithUuid(urlToPlay, info.first, info.second, false, with);
107 }
108 }
109
playDiscFiles(QUrl where)110 void PlaybackManager::playDiscFiles(QUrl where)
111 {
112 if (playbackState_ != StoppedState) {
113 playbackState_ = StoppedState;
114 emit stateChanged(playbackState_);
115 mpvObject_->stopPlayback();
116 }
117 mpvStartTime = -1.0;
118 mpvObject_->discFilesOpen(where.toLocalFile());
119 mpvObject_->setPaused(false);
120 playbackStartState = PlayingState;
121 nowPlayingItem = QUuid();
122 nowPlayingList = QUuid();
123 emit nowPlayingChanged(where, QUuid(), QUuid());
124 }
125
playStream(QUrl stream)126 void PlaybackManager::playStream(QUrl stream)
127 {
128 openFile(stream);
129 }
130
playItem(QUuid playlist,QUuid item)131 void PlaybackManager::playItem(QUuid playlist, QUuid item)
132 {
133 auto url = playlistWindow_->getUrlOf(playlist, item);
134 startPlayWithUuid(url, playlist, item, false);
135 }
136
playDevice(QUrl device)137 void PlaybackManager::playDevice(QUrl device)
138 {
139 Q_UNUSED(device)
140 //FIXME: detect dvb dongles, and use a channel map (or make one?)
141 }
142
loadSubtitle(QUrl with)143 void PlaybackManager::loadSubtitle(QUrl with)
144 {
145 QString f = with.isLocalFile() ? with.toLocalFile()
146 : with.fromPercentEncoding(with.toEncoded());
147 mpvObject_->addSubFile(f);
148 }
149
playPlayer()150 void PlaybackManager::playPlayer()
151 {
152 unpausePlayer();
153 if (playbackState_ == StoppedState) {
154 startPlayer();
155 }
156 }
157
startPlayer()158 void PlaybackManager::startPlayer()
159 {
160 if (!playlistWindow_->playActiveItem())
161 playlistWindow_->playCurrentItem();
162 }
163
playPausePlayer()164 void PlaybackManager::playPausePlayer()
165 {
166 switch (playbackState_) {
167 case PausedState:
168 unpausePlayer();
169 break;
170 case StoppedState:
171 startPlayer();
172 break;
173 default:
174 pausePlayer();
175 }
176 }
177
pausePlayer()178 void PlaybackManager::pausePlayer()
179 {
180 if (playbackState_ == PlayingState)
181 mpvObject_->setPaused(true);
182 }
183
unpausePlayer()184 void PlaybackManager::unpausePlayer()
185 {
186 if (playbackState_ == PausedState)
187 mpvObject_->setPaused(false);
188 }
189
stopPlayer()190 void PlaybackManager::stopPlayer()
191 {
192 nowPlayingItem = QUuid();
193 mpvObject_->stopPlayback();
194 }
195
stepBackward()196 void PlaybackManager::stepBackward()
197 {
198 mpvObject_->stepBackward();
199 }
200
stepForward()201 void PlaybackManager::stepForward()
202 {
203 mpvObject_->stepForward();
204 }
205
navigateToNextChapter()206 void PlaybackManager::navigateToNextChapter()
207 {
208 int64_t nextChapter = mpvObject_->chapter() + 1;
209 if (nextChapter >= numChapters)
210 playNext();
211 else
212 navigateToChapter(nextChapter);
213 }
214
navigateToPrevChapter()215 void PlaybackManager::navigateToPrevChapter()
216 {
217 int64_t chapter = mpvObject_->chapter();
218 if (chapter > 0)
219 navigateToChapter(std::max(int64_t(0), chapter - 1));
220 else
221 playPrev();
222 }
223
playNext()224 void PlaybackManager::playNext()
225 {
226 if (folderFallback && playlistWindow_->isPlaylistSingularFile(nowPlayingList)) {
227 playNextFile();
228 } else {
229 playNextTrack();
230 }
231 }
232
playPrev()233 void PlaybackManager::playPrev()
234 {
235 if (folderFallback && playlistWindow_->isPlaylistSingularFile(nowPlayingList)) {
236 playPrevFile();
237 } else {
238 playPrevTrack();
239 }
240 }
241
repeatThisFile()242 void PlaybackManager::repeatThisFile()
243 {
244 startPlayWithUuid(nowPlaying_, nowPlayingList, nowPlayingItem, true);
245 }
246
deltaExtraPlaytimes(int delta)247 void PlaybackManager::deltaExtraPlaytimes(int delta)
248 {
249 playlistWindow_->deltaExtraPlayTimes(nowPlayingList, nowPlayingItem, delta);
250 }
251
navigateToChapter(int64_t chapter)252 void PlaybackManager::navigateToChapter(int64_t chapter)
253 {
254 if (!mpvObject_->setChapter(chapter)) {
255 // Out-of-bounds chapter navigation request. i.e. unseekable chapter
256 // from either past-the-end or invalid. So stop playback and continue
257 // on the next via the playback finished slot.
258 mpvObject_->setPaused(false);
259 mpvObject_->stopPlayback();
260 }
261 }
262
navigateToTime(double time)263 void PlaybackManager::navigateToTime(double time)
264 {
265 if (playbackState_ == WaitingState || playbackState_ == StoppedState)
266 mpvStartTime = time;
267 else
268 mpvObject_->setTime(time);
269 }
270
speedUp()271 void PlaybackManager::speedUp()
272 {
273 double speed = speedStepAdditive ? mpvSpeed + speedStep - 1.0
274 : mpvSpeed * speedStep;
275 setPlaybackSpeed(std::min(8.0, speed));
276 }
277
speedDown()278 void PlaybackManager::speedDown()
279 {
280 double speed = speedStepAdditive ? mpvSpeed - speedStep + 1.0
281 : mpvSpeed / speedStep;
282 setPlaybackSpeed(std::max(0.125, speed));
283 }
284
speedReset()285 void PlaybackManager::speedReset()
286 {
287 setPlaybackSpeed(1.0);
288 }
289
relativeSeek(bool forwards,bool isSmall)290 void PlaybackManager::relativeSeek(bool forwards, bool isSmall)
291 {
292 mpvObject_->seek((forwards ? 1.0 : -1.0) *
293 (isSmall ? stepTimeSmall : stepTimeLarge), isSmall);
294 }
295
setPlaybackSpeed(double speed)296 void PlaybackManager::setPlaybackSpeed(double speed)
297 {
298 mpvSpeed = speed;
299 mpvObject_->setSpeed(speed);
300 mpvObject_->showMessage(tr("Speed: %1%").arg(speed*100));
301 }
302
setSpeedStep(double step)303 void PlaybackManager::setSpeedStep(double step)
304 {
305 speedStep = step;
306 }
307
setSpeedStepAdditive(bool isAdditive)308 void PlaybackManager::setSpeedStepAdditive(bool isAdditive)
309 {
310 speedStepAdditive = isAdditive;
311 }
312
setStepTimeLarge(int largeMsec)313 void PlaybackManager::setStepTimeLarge(int largeMsec)
314 {
315 stepTimeLarge = largeMsec / 1000.0;
316 }
317
setStepTimeSmall(int smallMsec)318 void PlaybackManager::setStepTimeSmall(int smallMsec)
319 {
320 stepTimeSmall = smallMsec / 1000.0;
321 }
322
findSecondById(QList<QPair<int64_t,QString>> list,int64_t id)323 static QString findSecondById(QList<QPair<int64_t,QString>> list, int64_t id) {
324 // this *should* return the string at id-1
325 for (int i = 0; i < list.count(); ++i)
326 if (list.value(i).first == id)
327 return list.value(i).second;
328 return QString();
329 }
330
setAudioTrack(int64_t id)331 void PlaybackManager::setAudioTrack(int64_t id)
332 {
333 audioListSelected = findSecondById(audioList, id);
334 mpvObject_->setAudioTrack(id);
335 }
336
setSubtitleTrack(int64_t id)337 void PlaybackManager::setSubtitleTrack(int64_t id)
338 {
339 subtitleListSelected = findSecondById(subtitleList, id);
340 subtitleTrackSelected = id;
341 updateSubtitleTrack();
342 }
343
setVideoTrack(int64_t id)344 void PlaybackManager::setVideoTrack(int64_t id)
345 {
346 videoListSelected = findSecondById(videoList, id);
347 mpvObject_->setVideoTrack(id);
348 }
349
setSubtitleEnabled(bool enabled)350 void PlaybackManager::setSubtitleEnabled(bool enabled)
351 {
352 subtitleEnabled = enabled;
353 updateSubtitleTrack();
354 }
355
selectNextSubtitle()356 void PlaybackManager::selectNextSubtitle()
357 {
358 if (subtitleList.isEmpty())
359 return;
360 int64_t nextSubs = subtitleTrackSelected + 1;
361 if (nextSubs >= subtitleList.count())
362 nextSubs = 0;
363 setSubtitleTrack(nextSubs);
364 }
365
selectPrevSubtitle()366 void PlaybackManager::selectPrevSubtitle()
367 {
368 if (subtitleList.isEmpty())
369 return;
370 int64_t previousSubs = subtitleTrackSelected - 1;
371 if (previousSubs < 0)
372 previousSubs = subtitleList.count() - 1;
373 setSubtitleTrack(previousSubs);
374 }
375
setVolume(int64_t volume)376 void PlaybackManager::setVolume(int64_t volume)
377 {
378 static int64_t lastVol = -1;
379 if (lastVol == volume)
380 return;
381 lastVol = volume;
382 mpvObject_->setVolume(volume);
383 mpvObject_->showMessage(tr("Volume: %1%").arg(volume));
384 }
385
setMute(bool muted)386 void PlaybackManager::setMute(bool muted)
387 {
388 mpvObject_->setMute(muted);
389 mpvObject_->showMessage(muted ? tr("Mute: on") : tr("Mute: off"));
390 }
391
setAfterPlaybackOnce(AfterPlayback mode)392 void PlaybackManager::setAfterPlaybackOnce(AfterPlayback mode)
393 {
394 afterPlaybackOnce = mode;
395 }
396
setAfterPlaybackAlways(AfterPlayback mode)397 void PlaybackManager::setAfterPlaybackAlways(AfterPlayback mode)
398 {
399 afterPlaybackAlways = mode;
400 }
401
setSubtitlesPreferDefaultForced(bool forced)402 void PlaybackManager::setSubtitlesPreferDefaultForced(bool forced)
403 {
404 subtitlesPreferDefaultForced = forced;
405 }
406
setSubtitlesPreferExternal(bool external)407 void PlaybackManager::setSubtitlesPreferExternal(bool external)
408 {
409 subtitlesPreferExternal = external;
410 }
411
setSubtitlesIgnoreEmbedded(bool ignore)412 void PlaybackManager::setSubtitlesIgnoreEmbedded(bool ignore)
413 {
414 subtitlesIgnoreEmbedded = ignore;
415 }
416
setPlaybackPlayTimes(int times)417 void PlaybackManager::setPlaybackPlayTimes(int times)
418 {
419 this->playbackPlayTimes = times > 1 ? times : 1;
420 this->playbackStartPaused = times < 1;
421 }
422
setPlaybackForever(bool yes)423 void PlaybackManager::setPlaybackForever(bool yes)
424 {
425 this->playbackForever = yes;
426 }
427
setFolderFallback(bool yes)428 void PlaybackManager::setFolderFallback(bool yes)
429 {
430 folderFallback = yes;
431 }
432
sendCurrentTrackInfo()433 void PlaybackManager::sendCurrentTrackInfo()
434 {
435 QUrl url(playlistWindow_->getUrlOf(nowPlayingList, nowPlayingItem));
436 emit currentTrackInfo({url, nowPlayingList, nowPlayingItem,
437 nowPlayingTitle, mpvLength, mpvTime});
438 }
439
startPlayWithUuid(QUrl what,QUuid playlistUuid,QUuid itemUuid,bool isRepeating,QUrl with)440 void PlaybackManager::startPlayWithUuid(QUrl what, QUuid playlistUuid,
441 QUuid itemUuid, bool isRepeating,
442 QUrl with)
443 {
444 if (playbackState_ == WaitingState || what.isEmpty())
445 return;
446 emit stateChanged(playbackState_ = WaitingState);
447
448 mpvStartTime = -1.0;
449 nowPlaying_ = what;
450 mpvObject_->fileOpen(what.isLocalFile() ? what.toLocalFile()
451 : what.fromPercentEncoding(what.toEncoded()));
452 mpvObject_->setSubFile(with.toString());
453 mpvObject_->setPaused(playbackStartPaused);
454 playbackStartState = playbackStartPaused ? PausedState : PlayingState;
455 nowPlayingList = playlistUuid;
456 nowPlayingItem = itemUuid;
457
458 if (!isRepeating && playbackPlayTimes > 1
459 && playlistWindow_->extraPlayTimes(playlistUuid, itemUuid) <= 0) {
460 // On first play, when playing more than once, and when the extra
461 // play times has not been set, set the extra play times to the one
462 // configured in the settings dialog.
463 playlistWindow_->setExtraPlayTimes(playlistUuid, itemUuid, playbackPlayTimes - 1);
464 }
465 emit nowPlayingChanged(nowPlaying_, nowPlayingList, nowPlayingItem);
466 }
467
selectDesiredTracks()468 void PlaybackManager::selectDesiredTracks()
469 {
470 // search current tracks by mangled string of no id and no spaces
471 auto mangle = [](QString s) {
472 return QStringList(s.split(' ').mid(1)).join("");
473 };
474 auto findIdBySecond = [&](QList<QPair<int64_t,QString>> list,
475 QString needle) -> int64_t {
476 if (list.isEmpty() || (needle = mangle(needle)).isEmpty())
477 return -1;
478 for (int i = 0; i < list.count(); i++) {
479 if (mangle(list[i].second) == needle) {
480 return list[i].first;
481 }
482 }
483 return -1;
484 };
485 auto findSubIdByPreference = [&](void) -> int64_t {
486 if (subtitlesPreferExternal) {
487 for (auto it = subtitleListData.constBegin();
488 it != subtitleListData.constEnd(); it++) {
489 if (it.value().value("external").toBool())
490 return it.key();
491 }
492 }
493 if (subtitlesPreferDefaultForced) {
494 for (auto it = subtitleListData.constBegin();
495 it != subtitleListData.constEnd(); it++)
496 if (it.value().value("forced").toBool()
497 || it.value().value("default").toBool())
498 return it.key();
499 }
500 return -1;
501 };
502 int64_t videoId = findIdBySecond(videoList, videoListSelected);
503 int64_t audioId = findIdBySecond(audioList, audioListSelected);
504 int64_t subsId = findSubIdByPreference();
505 if (subsId < 0) subsId = findIdBySecond(subtitleList, subtitleListSelected);
506
507 // Set detected tracks; if no preferred track from a list could be found,
508 // clear user selection
509 if (videoId >= 0)
510 setVideoTrack(videoId);
511 else if (!videoList.isEmpty())
512 videoListSelected.clear();
513 if (audioId >= 0)
514 setAudioTrack(audioId);
515 else if (!audioList.isEmpty())
516 audioListSelected.clear();
517 if (subsId >= 0)
518 setSubtitleTrack(subsId);
519 else if (!subtitleList.isEmpty()) {
520 subtitleListSelected.clear();
521 setSubtitleTrack(1);
522 }
523 }
524
updateSubtitleTrack()525 void PlaybackManager::updateSubtitleTrack()
526 {
527 emit subtitlesVisibile(subtitleEnabled && subtitleTrackSelected != 0);
528 mpvObject_->setSubtitleTrack(subtitleEnabled ? subtitleTrackSelected : 0);
529 }
530
checkAfterPlayback(bool playlistMode)531 void PlaybackManager::checkAfterPlayback(bool playlistMode)
532 {
533 Helpers::AfterPlayback action = afterPlaybackOnce;
534 if (afterPlaybackOnce == Helpers::DoNothingAfter)
535 action = afterPlaybackAlways;
536
537 afterPlaybackOnce = Helpers::DoNothingAfter;
538 emit afterPlaybackReset();
539
540 switch (action) {
541 case Helpers::ExitAfter:
542 emit instanceShouldClose();
543 break;
544 case Helpers::StandByAfter:
545 emit systemShouldStandby();
546 break;
547 case Helpers::HibernateAfter:
548 emit systemShouldHibernate();
549 break;
550 case Helpers::ShutdownAfter:
551 emit systemShouldShutdown();
552 break;
553 case Helpers::LogOffAfter:
554 emit systemShouldLogOff();
555 break;
556 case Helpers::LockAfter:
557 emit systemShouldLock();
558 break;
559 case Helpers::RepeatAfter:
560 if (playlistMode)
561 repeatThisFile();
562 break;
563 case Helpers::PlayNextAfter:
564 if (!playNextFileUrl(nowPlaying_))
565 playNextTrack();
566 break;
567 case Helpers::DoNothingAfter:
568 if (playlistMode)
569 playNext();
570 }
571 }
572
playNextTrack()573 void PlaybackManager::playNextTrack()
574 {
575 QPair<QUuid, QUuid> next;
576 next = playlistWindow_->getItemAfter(nowPlayingList, nowPlayingItem);
577 QUrl url = playlistWindow_->getUrlOf(next.first, next.second);
578 if (url.isEmpty()) {
579 playHalt();
580 return;
581 }
582 startPlayWithUuid(url, next.first, next.second, false);
583 }
584
playPrevTrack()585 void PlaybackManager::playPrevTrack()
586 {
587 QUuid uuid = playlistWindow_->getItemBefore(nowPlayingList, nowPlayingItem);
588 QUrl url = playlistWindow_->getUrlOf(nowPlayingList, uuid);
589 if (url.isEmpty()) {
590 playHalt();
591 return;
592 }
593 startPlayWithUuid(url, nowPlayingList, uuid, false);
594 }
595
playNextFileUrl(QUrl url,int delta)596 bool PlaybackManager::playNextFileUrl(QUrl url, int delta)
597 {
598 QFileInfo info;
599 QDir dir;
600 QStringList files;
601 int index;
602 QString nextFile;
603
604
605 if (url.isEmpty())
606 return false;
607 info = QFileInfo(url.toLocalFile());
608 if (!info.exists())
609 return false;
610 dir = info.dir();
611 files = dir.entryList(QDir::Files, QDir::Name);
612 index = files.indexOf(info.fileName());
613 if (index == -1)
614 return false;
615 do {
616 index += delta;
617 if (index < 0 || index >= files.count())
618 return false;
619 nextFile = dir.filePath(files.value(index));
620 url = QUrl::fromLocalFile(nextFile);
621 } while (!Helpers::urlSurvivesFilter(url));
622 playlistWindow_->replaceItem(nowPlayingList, nowPlayingItem, { url });
623 startPlayWithUuid(url, nowPlayingList, nowPlayingItem, false);
624 return true;
625 }
626
playNextFile(int delta)627 void PlaybackManager::playNextFile(int delta)
628 {
629 QUrl url = playlistWindow_->getUrlOfFirst(nowPlayingList);
630 if (!playNextFileUrl(url, delta))
631 playHalt();
632 }
633
playPrevFile()634 void PlaybackManager::playPrevFile()
635 {
636 playNextFile(-1);
637 }
638
playHalt()639 void PlaybackManager::playHalt()
640 {
641 mpvObject_->stopPlayback();
642 nowPlaying_.clear();
643 nowPlayingItem = QUuid();
644 playbackState_ = StoppedState;
645 emit stateChanged(playbackState_);
646 }
647
mpvw_playTimeChanged(double time)648 void PlaybackManager::mpvw_playTimeChanged(double time)
649 {
650 // in case the duration property is not available, update the play length
651 // to indicate that the time is in fact available.
652 if (mpvLength < time)
653 mpvLength = time;
654 mpvTime = time;
655 emit timeChanged(time, mpvLength);
656 }
657
mpvw_playLengthChanged(double length)658 void PlaybackManager::mpvw_playLengthChanged(double length)
659 {
660 mpvLength = length;
661 }
662
mpvw_seekableChanged(bool yes)663 void PlaybackManager::mpvw_seekableChanged(bool yes)
664 {
665 if (yes && mpvStartTime > 0) {
666 mpvObject_->setTimeSync(mpvStartTime);
667 mpvStartTime = -1;
668 }
669 }
670
mpvw_playbackLoading()671 void PlaybackManager::mpvw_playbackLoading()
672 {
673 playbackState_ = BufferingState;
674 emit stateChanged(playbackState_);
675 }
676
mpvw_playbackStarted()677 void PlaybackManager::mpvw_playbackStarted()
678 {
679 playbackState_ = playbackStartState;
680 emit stateChanged(playbackState_);
681 emit playerSettingsRequested();
682 }
683
mpvw_pausedChanged(bool yes)684 void PlaybackManager::mpvw_pausedChanged(bool yes)
685 {
686 if (playbackState_ == StoppedState)
687 return;
688
689 playbackState_ = yes ? PausedState : PlayingState;
690 emit stateChanged(playbackState_);
691 }
692
mpvw_playbackIdling()693 void PlaybackManager::mpvw_playbackIdling()
694 {
695 if (nowPlayingItem.isNull()) {
696 nowPlaying_.clear();
697 playbackState_ = StoppedState;
698 emit stateChanged(playbackState_);
699 checkAfterPlayback(false);
700 return;
701 }
702
703 int extraTimes = playlistWindow_->extraPlayTimes(nowPlayingList, nowPlayingItem);
704 playlistWindow_->setExtraPlayTimes(nowPlayingList, nowPlayingItem, extraTimes - 1);
705
706 bool isRepeating = playbackForever || extraTimes > 0;
707 if (isRepeating)
708 repeatThisFile();
709 else
710 checkAfterPlayback(true);
711 }
712
mpvw_mediaTitleChanged(QString title)713 void PlaybackManager::mpvw_mediaTitleChanged(QString title)
714 {
715 nowPlayingTitle = title;
716 emit titleChanged(title);
717 }
718
mpvw_chapterDataChanged(QVariantMap metadata)719 void PlaybackManager::mpvw_chapterDataChanged(QVariantMap metadata)
720 {
721 emit chapterTitleChanged(metadata.value("title").toString());
722 }
723
mpvw_chaptersChanged(QVariantList chapters)724 void PlaybackManager::mpvw_chaptersChanged(QVariantList chapters)
725 {
726 QList<QPair<double,QString>> list;
727 for (QVariant &v : chapters) {
728 QMap<QString, QVariant> node = v.toMap();
729 QString text = QString("[%1] - %2").arg(
730 toDateFormat(node["time"].toDouble()),
731 node["title"].toString());
732 QPair<double,QString> item(node["time"].toDouble(), text);
733 list.append(item);
734 }
735 numChapters = list.count();
736 emit chaptersAvailable(list);
737 }
738
mpvw_tracksChanged(QVariantList tracks)739 void PlaybackManager::mpvw_tracksChanged(QVariantList tracks)
740 {
741 videoList.clear();
742 audioList.clear();
743 subtitleList.clear();
744 subtitleListData.clear();
745 QPair<int64_t,QString> item;
746
747 auto str = [](QVariantMap map, QString key) {
748 return map[key].toString();
749 };
750 auto formatter = [&str](QVariantMap track) {
751 QString output;
752 output.append(QString("%1: ").arg(str(track,"id")));
753 if (track.contains("codec"))
754 output.append(QString("[%1] ").arg(str(track,"codec")));
755 if (track.contains("lang"))
756 output.append(QString("%1 ").arg(str(track,"lang")));
757 if (track.contains("title"))
758 output.append(QString("- %1 ").arg(str(track,"title")));
759 return output;
760 };
761
762 for (QVariant &track : tracks) {
763 QVariantMap t = track.toMap();
764 item.first = t["id"].toLongLong();
765 item.second = formatter(t);
766 if (str(t,"type") == "video") {
767 videoList.append(item);
768 } else if (str(t,"type") == "audio") {
769 audioList.append(item);
770 } else if (str(t,"type") == "sub") {
771 if (!subtitlesIgnoreEmbedded || t.value("external").toBool()) {
772 subtitleList.append(item);
773 subtitleListData.insert(item.first, t);
774 }
775 }
776 }
777 if (!subtitleList.isEmpty()) {
778 subtitleList.append({0, tr("0: None")});
779 }
780
781 emit videoTracksAvailable(videoList);
782 emit audioTracksAvailable(audioList);
783 emit subtitleTracksAvailable(subtitleList);
784
785 selectDesiredTracks();
786
787 emit hasNoVideo(videoList.empty());
788 emit hasNoAudio(audioList.empty());
789 emit hasNoSubtitles(subtitleList.empty());
790 }
791
mpvw_videoSizeChanged(QSize size)792 void PlaybackManager::mpvw_videoSizeChanged(QSize size)
793 {
794 emit videoSizeChanged(size);
795 }
796
mpvw_fpsChanged(double fps)797 void PlaybackManager::mpvw_fpsChanged(double fps)
798 {
799 emit fpsChanged(fps);
800 }
801
mpvw_avsyncChanged(double sync)802 void PlaybackManager::mpvw_avsyncChanged(double sync)
803 {
804 emit avsyncChanged(sync);
805 }
806
mpvw_displayFramedropsChanged(int64_t count)807 void PlaybackManager::mpvw_displayFramedropsChanged(int64_t count)
808 {
809 emit displayFramedropsChanged(count);
810 }
811
mpvw_decoderFramedropsChanged(int64_t count)812 void PlaybackManager::mpvw_decoderFramedropsChanged(int64_t count)
813 {
814 emit decoderFramedropsChanged(count);
815 }
816
mpvw_audioBitrateChanged(double bitrate)817 void PlaybackManager::mpvw_audioBitrateChanged(double bitrate)
818 {
819 emit audioBitrateChanged(bitrate);
820 }
821
mpvw_videoBitrateChanged(double bitrate)822 void PlaybackManager::mpvw_videoBitrateChanged(double bitrate)
823 {
824 emit videoBitrateChanged(bitrate);
825 }
826
mpvw_metadataChanged(QVariantMap metadata)827 void PlaybackManager::mpvw_metadataChanged(QVariantMap metadata)
828 {
829 playlistWindow_->setMetadata(nowPlayingList, nowPlayingItem, metadata);
830 }
831
mpvw_playlistChanged(const QVariantList & playlist)832 void PlaybackManager::mpvw_playlistChanged(const QVariantList &playlist)
833 {
834 // replace current item with whatever we got, and trigger its playback
835 QList<QUrl> urls;
836 for (auto i : playlist)
837 urls.append(QUrl::fromUserInput(i.toMap()["filename"].toString()));
838 playlistWindow_->replaceItem(nowPlayingList, nowPlayingItem, urls);
839 playItem(nowPlayingList, nowPlayingItem);
840 }
841