commit:     d64c66ff12b01644be4b24104ba1e2cb0c910ded
Author:     Martin Dummer <martin.dummer <AT> gmx <DOT> net>
AuthorDate: Sat Dec 28 19:58:12 2024 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Sat Sep 20 09:15:41 2025 +0000
URL:        https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=d64c66ff

media-video/vdr: add 2.7.3

introducing a subslot, reverse dependencies (media-plugins/vdr-*) will
receive the new subslot dependency later

Signed-off-by: Martin Dummer <martin.dummer <AT> gmx.net>
Part-of: https://github.com/gentoo/gentoo/pull/39879
Signed-off-by: Sam James <sam <AT> gentoo.org>

 media-video/vdr/Manifest                           |   2 +
 .../vdr/files/vdr-2.7.2-patch-for-permashift.patch | 520 +++++++++++++++++++++
 media-video/vdr/files/vdr-2.7.3_pinplugin.patch    | 435 +++++++++++++++++
 media-video/vdr/vdr-2.7.3.ebuild                   | 197 ++++++++
 4 files changed, 1154 insertions(+)

diff --git a/media-video/vdr/Manifest b/media-video/vdr/Manifest
index a37f62cdf35f..662139e1093c 100644
--- a/media-video/vdr/Manifest
+++ b/media-video/vdr/Manifest
@@ -2,4 +2,6 @@ DIST extpng-vdr-2.2.0-gentoo-edition-v1.patch.bz2 34664 BLAKE2B 
81b68ebe0ef4588c
 DIST vdr-2.2.0.tar.bz2 922708 BLAKE2B 
975e07d6d4c5bd13ee92be5d6a1826d6404b0c59e20fa2e30689b185a61e02d54782ad528e6a4f15e0d36806b30bcf48aa336d63adb3604e78056ff318e0fd2c
 SHA512 
183f58133915c6c0fe8ec2b88becbcb2a36418210e6dcf7931053d3771d727c3581593f9eb5c9693abf39e22e728f7b41c42079cd704610c3636ec05134ea93d
 DIST vdr-2.6.9.tbz2 949889 BLAKE2B 
25416907562b061a38fbe29478010d1d790695f1eab2ad8e7d58548986a84c494232a914f58bbfc00e1d99fc5dd915fa4f715706630c3e3f1d2708c86c548e26
 SHA512 
a28cd01be43825d8f3d1af076dcb3193fa2f66027d419e4da4fcbac094a966877f52133045488b2e4cd962a2828875f9bd6c582379c8b4fb5db82a737f128aee
 DIST vdr-2.6.9_ttxtsubs_v2.patch 40549 BLAKE2B 
525c05b72fa957372cc1ef91428428f664f42d92eebc06fd0b179afbe99e4ecc4919c69cef000cc15c8340c9a2506d38cbf755fd6665cde1708ce17d4320a35f
 SHA512 
590c43e63818de8be9637cb3b32bf3399b82a181ca151d67e2341232669619020ab78ba9934da3a9c58cdb3bac56fc2a332a5838a92ee0851e42c3707726eb49
+DIST vdr-2.7.3.tbz2 953575 BLAKE2B 
c2380c3ece50683faf63c0df09011859c61a66dbd684b87abe8deb60b0676937063271edc4c26809f4cc8fc95273386ce9ce8566244de1eb043c1e46842c9fa3
 SHA512 
a2e7421d94bdd5d994b7584115e3b297b069557b12a831363ab2fb4fe3a65117ec43fe24f988e290dd2fa33a50a6bc1fe33c1076b179a6fe1b5d24b786a0930d
+DIST vdr-2.7.3_ttxtsubs_v2.patch 40541 BLAKE2B 
5848009c6ef432a9852a0e86a448bb3d2c1a037523c5f1ce9563eb0e65ad4c174e4e1f290fd7f583cfa3915cad6297e1d4d7833b89883bb09c4dbf14d715656f
 SHA512 
d8123c91096ff9734cdc46bacd253b153627091a90aa94288dc60ea74792b5ab6e62cd48adc6b830d83ca81d7d6ad11d7b478aaad67d597d1141ffe8e29abbf8
 DIST vdr-menuorg-2.3.x.diff 8852 BLAKE2B 
19b98d51a69f52ecda5500f51ef1741a8397953b20c490055eab0393da5f56ff9598c3e1e8ed8b915f5877e08deeb9ba7a9ef8d9356ad3a1fa12e3778869174a
 SHA512 
7b41c3a529858a4953a57f21619ea01864e140cc1755ee0b03caf1c4de41e80c3f805653502bc8d39d02a4dfcddf720acd4a8c8bd91f4871eef31d86e8e915c0

diff --git a/media-video/vdr/files/vdr-2.7.2-patch-for-permashift.patch 
b/media-video/vdr/files/vdr-2.7.2-patch-for-permashift.patch
new file mode 100644
index 000000000000..e3b654404280
--- /dev/null
+++ b/media-video/vdr/files/vdr-2.7.2-patch-for-permashift.patch
@@ -0,0 +1,520 @@
+updated patch for vdr-2.7.2
+downloaded from 
https://www.vdr-portal.de/forum/index.php?thread/136461-announce-vdr-version-2-7-2-freigegeben/&postID=1374957#post1374957
+
+diff --git a/device.c b/device.c
+index b9c52190..15f650b2 100644
+--- a/device.c
++++ b/device.c
+@@ -1917,6 +1917,17 @@ void cDevice::DetachAllReceivers(void)
+   ReleaseCamSlot();
+ }
+ 
++cRecorder* cDevice::GetPreRecording(const cChannel *Channel)
++{
++  cMutexLock MutexLock(&mutexReceiver);
++  for (int i = 0; i < MAXRECEIVERS; i++) {
++      if (receiver[i])
++        if (receiver[i]->IsPreRecording(Channel))
++                return (cRecorder*)receiver[i];
++      }
++  return NULL;
++}
++
+ // --- cTSBuffer -------------------------------------------------------------
+ 
+ cTSBuffer::cTSBuffer(int File, int Size, int DeviceNumber)
+diff --git a/device.h b/device.h
+index fe60b3ef..4076f38e 100644
+--- a/device.h
++++ b/device.h
+@@ -85,6 +85,7 @@ struct tTrackId {
+ 
+ class cPlayer;
+ class cReceiver;
++class cRecorder;
+ class cLiveSubtitle;
+ 
+ class cDeviceHook : public cListObject {
+@@ -867,6 +868,8 @@ public:
+        ///< Returns true if we are currently receiving. The parameter has no 
meaning (for backwards compatibility only).
+   bool AttachReceiver(cReceiver *Receiver);
+        ///< Attaches the given receiver to this device.
++  cRecorder* GetPreRecording(const cChannel *Channel);
++       ///< Get precocious recording for the channel if there is one.
+   void Detach(cReceiver *Receiver, bool ReleaseCam = true);
+        ///< Detaches the given receiver from this device.
+        ///< If ReleaseCam is true, the CAM slot will be released if it
+diff --git a/dvbplayer.c b/dvbplayer.c
+index c36fac70..9a0be3f6 100644
+--- a/dvbplayer.c
++++ b/dvbplayer.c
+@@ -249,13 +249,14 @@ private:
+   cUnbufferedFile *replayFile;
+   double framesPerSecond;
+   bool isPesRecording;
+-  bool pauseLive;
++  ReplayState replayState;
+   bool eof;
+   bool firstPacket;
+   ePlayModes playMode;
+   ePlayDirs playDir;
+   int trickSpeed;
+   int readIndex;
++  int startIndex;
+   bool readIndependent;
+   cFrame *readFrame;
+   cFrame *playFrame;
+@@ -271,6 +272,8 @@ protected:
+   virtual void Action(void);
+ public:
+   cDvbPlayer(const char *FileName, bool PauseLive);
++  cDvbPlayer(const char *FileName, ReplayState newReplayState);
++  void Construct(const char *FileName, ReplayState newReplayState);
+   virtual ~cDvbPlayer();
+   void SetMarks(const cMarks *Marks);
+   bool Active(void) { return cThread::Running(); }
+@@ -298,6 +301,17 @@ int cDvbPlayer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 
0 };
+ cDvbPlayer::cDvbPlayer(const char *FileName, bool PauseLive)
+ :cThread("dvbplayer")
+ {
++  Construct(FileName, PauseLive? restPauseLive : restNormal);
++}
++
++cDvbPlayer::cDvbPlayer(const char *FileName, ReplayState newReplayState)
++:cThread("dvbplayer")
++{
++  Construct(FileName, newReplayState);
++}
++
++void cDvbPlayer::Construct(const char *FileName, ReplayState newReplayState)
++{  
+   nonBlockingFileReader = NULL;
+   ringBuffer = NULL;
+   marks = NULL;
+@@ -305,7 +319,8 @@ cDvbPlayer::cDvbPlayer(const char *FileName, bool 
PauseLive)
+   cRecording Recording(FileName);
+   framesPerSecond = Recording.FramesPerSecond();
+   isPesRecording = Recording.IsPesRecording();
+-  pauseLive = PauseLive;
++  replayState = newReplayState;
++  bool reuse = (replayState == restReusePause || replayState == 
restReuseRewind);
+   eof = false;
+   firstPacket = true;
+   playMode = pmPlay;
+@@ -324,15 +339,21 @@ cDvbPlayer::cDvbPlayer(const char *FileName, bool 
PauseLive)
+      return;
+   ringBuffer = new cRingBufferFrame(PLAYERBUFSIZE);
+   // Create the index file:
+-  index = new cIndexFile(FileName, false, isPesRecording, pauseLive);
++  index = new cIndexFile(FileName, false, isPesRecording, replayState == 
restPauseLive);
+   if (!index)
+      esyslog("ERROR: can't allocate index");
+   else if (!index->Ok()) {
+      delete index;
+      index = NULL;
+      }
+-  else if (PauseLive)
++  else if (reuse)
+      framesPerSecond = cRecording(FileName).FramesPerSecond(); // the fps 
rate might have changed from the default
++  startIndex = 0;
++  if (replayState == restReuseRewind || replayState == restReusePause) {
++     int Current, Total;
++     GetIndex(Current, Total, false);
++     startIndex = max(Total - 1, 0);
++     }     
+ }
+ 
+ cDvbPlayer::~cDvbPlayer()
+@@ -482,8 +503,21 @@ void cDvbPlayer::Action(void)
+   bool CutIn = false;
+   bool AtLastMark = false;
+ 
+-  if (pauseLive)
+-     Goto(0, true);
++  if (replayState == restPauseLive) {
++    Goto(0, true);
++    }
++  else if (replayState == restReuseRewind || replayState == restReusePause) {
++    readIndex = startIndex;
++    Goto(readIndex, true);
++    playMode = pmPlay;
++    if (replayState == restReuseRewind) {
++      Backward();
++        }
++    else if (replayState == restReusePause) {
++      Pause();
++        }
++    }
++  
+   while (Running()) {
+         if (WaitingForData)
+            WaitingForData = !nonBlockingFileReader->WaitForDataMs(3); // this 
keeps the CPU load low, but reacts immediately on new data
+@@ -995,6 +1029,11 @@ cDvbPlayerControl::cDvbPlayerControl(const char 
*FileName, bool PauseLive)
+   SetPlayer(player);
+ }
+ 
++cDvbPlayerControl::cDvbPlayerControl(const char *FileName, ReplayState 
replayState)
++:cControl(player = new cDvbPlayer(FileName, replayState))
++{
++}
++
+ cDvbPlayerControl::~cDvbPlayerControl()
+ {
+   Stop();
+diff --git a/dvbplayer.h b/dvbplayer.h
+index bac5b0c4..32a155b1 100644
+--- a/dvbplayer.h
++++ b/dvbplayer.h
+@@ -16,6 +16,14 @@
+ 
+ class cDvbPlayer;
+ 
++enum ReplayState
++{
++      restNormal,
++      restPauseLive,
++      restReusePause,
++      restReuseRewind
++};
++
+ class cDvbPlayerControl : public cControl {
+ private:
+   cDvbPlayer *player;
+@@ -25,6 +33,8 @@ public:
+        // If PauseLive is true, special care is taken to make sure the index
+        // file of the recording is long enough to allow the player to display
+        // the first frame in still picture mode.
++  cDvbPlayerControl(const char *FileName, ReplayState replayState);
++       // Sets up a player for the given file. replayState represents the 
initial state.
+   virtual ~cDvbPlayerControl();
+   void SetMarks(const cMarks *Marks);
+   bool Active(void);
+diff --git a/menu.c b/menu.c
+index a5c429e3..a33915f6 100644
+--- a/menu.c
++++ b/menu.c
+@@ -5311,6 +5311,16 @@ eOSState cDisplaySubtitleTracks::ProcessKey(eKeys Key)
+ // --- cRecordControl --------------------------------------------------------
+ 
+ cRecordControl::cRecordControl(cDevice *Device, cTimers *Timers, cTimer 
*Timer, bool Pause)
++{
++  Construct(Device, Timers, Timer, Pause, NULL);
++}
++
++cRecordControl::cRecordControl(cDevice *Device, cTimers *Timers, cTimer 
*Timer, bool Pause, bool* reused)
++{
++  Construct(Device, Timers, Timer, Pause, reused);
++}
++
++void cRecordControl::Construct(cDevice *Device, cTimers *Timers, cTimer 
*Timer, bool Pause, bool* reused)
+ {
+   const char *LastReplayed = cReplayControl::LastReplayed(); // must do this 
before locking schedules!
+   // Whatever happens here, the timers will be modified in some way...
+@@ -5340,6 +5350,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimers 
*Timers, cTimer *Timer,
+   timer->SetPending(true);
+   timer->SetRecording(true);
+   event = timer->Event();
++  if (reused != NULL) *reused = false;
+ 
+   if (event || GetEvent())
+      dsyslog("Title: '%s' Subtitle: '%s'", event->Title(), 
event->ShortText());
+@@ -5369,8 +5380,21 @@ cRecordControl::cRecordControl(cDevice *Device, cTimers 
*Timers, cTimer *Timer,
+   if (MakeDirs(fileName, true)) {
+      Recording.WriteInfo(); // we write this *before* attaching the recorder 
to the device, to make sure the info file is present when the recorder needs to 
update the fps value!
+      const cChannel *ch = timer->Channel();
+-     recorder = new cRecorder(fileName, ch, timer->Priority());
+-     if (device->AttachReceiver(recorder)) {
++
++     if (!Timer) {
++        recorder = device->GetPreRecording(ch);
++        if (recorder != NULL) {
++           recorder->ActivatePreRecording(fileName, timer->Priority());
++           if (reused != NULL) *reused = true;
++           }
++        }
++
++     if (recorder == NULL) {
++        recorder = new cRecorder(fileName, ch, timer->Priority());
++        if (!device->AttachReceiver(recorder)) DELETENULL(recorder);
++        }
++
++     if (recorder != NULL) {
+         cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), 
true);
+         if (!Timer && !LastReplayed) // an instant recording, maybe from 
cRecordControls::PauseLiveVideo()
+            cReplayControl::SetRecording(fileName);
+@@ -5380,8 +5404,6 @@ cRecordControl::cRecordControl(cDevice *Device, cTimers 
*Timers, cTimer *Timer,
+         Recordings->AddByName(fileName);
+         return;
+         }
+-     else
+-        DELETENULL(recorder);
+      }
+   else
+      timer->SetDeferred(DEFERTIMER);
+@@ -5461,7 +5483,7 @@ bool cRecordControl::Process(time_t t)
+ cRecordControl *cRecordControls::RecordControls[MAXRECORDCONTROLS] = { NULL };
+ int cRecordControls::state = 0;
+ 
+-bool cRecordControls::Start(cTimers *Timers, cTimer *Timer, bool Pause)
++bool cRecordControls::Start(cTimers *Timers, cTimer *Timer, bool Pause, bool* 
reused)
+ {
+   static time_t LastNoDiskSpaceMessage = 0;
+   int FreeMB = 0;
+@@ -5499,7 +5521,7 @@ bool cRecordControls::Start(cTimers *Timers, cTimer 
*Timer, bool Pause)
+         if (!Timer || Timer->Matches()) {
+            for (int i = 0; i < MAXRECORDCONTROLS; i++) {
+                if (!RecordControls[i]) {
+-                  RecordControls[i] = new cRecordControl(device, Timers, 
Timer, Pause);
++                  RecordControls[i] = new cRecordControl(device, Timers, 
Timer, Pause, reused);
+                   return RecordControls[i]->Process(time(NULL));
+                   }
+                }
+@@ -5523,6 +5545,11 @@ bool cRecordControls::Start(bool Pause)
+   return Start(Timers, NULL, Pause);
+ }
+ 
++bool cRecordControls::Start(cTimers *Timers, cTimer *Timer, bool Pause)
++{
++  return Start(Timers, Timer, Pause, NULL);
++}
++
+ void cRecordControls::Stop(const char *InstantId)
+ {
+   LOCK_TIMERS_WRITE;
+@@ -5557,11 +5584,18 @@ void cRecordControls::Stop(cTimer *Timer)
+ }
+ 
+ bool cRecordControls::PauseLiveVideo(void)
++{
++  return PauseLiveVideo(false);
++}
++
++bool cRecordControls::PauseLiveVideo(bool rewind)
+ {
+   Skins.Message(mtStatus, tr("Pausing live video..."));
++  bool reused = false;  
+   cReplayControl::SetRecording(NULL); // make sure the new cRecordControl 
will set cReplayControl::LastReplayed()
+-  if (Start(true)) {
+-     cReplayControl *rc = new cReplayControl(true);
++  LOCK_TIMERS_WRITE;
++  if (Start(Timers, NULL, true, &reused)) {
++     cReplayControl *rc = new cReplayControl(rewind? restReuseRewind : 
reused? restReusePause : restPauseLive);
+      cControl::Launch(rc);
+      cControl::Attach();
+      Skins.Message(mtStatus, NULL);
+@@ -5704,7 +5738,18 @@ cString cReplayControl::fileName;
+ cReplayControl::cReplayControl(bool PauseLive)
+ :cDvbPlayerControl(fileName, PauseLive)
+ {
+-  cDevice::PrimaryDevice()->SetKeepTracks(PauseLive);
++  Construct(PauseLive? restPauseLive : restNormal);
++}
++
++cReplayControl::cReplayControl(ReplayState replayState)
++:cDvbPlayerControl(fileName, replayState)
++{
++  Construct(replayState);
++}
++
++void cReplayControl::Construct(ReplayState replayState)
++{
++  cDevice::PrimaryDevice()->SetKeepTracks(replayState == restPauseLive);
+   currentReplayControl = this;
+   displayReplay = NULL;
+   marksModified = false;
+diff --git a/menu.h b/menu.h
+index 96c55e62..9446a70d 100644
+--- a/menu.h
++++ b/menu.h
+@@ -245,6 +245,8 @@ private:
+   bool GetEvent(void);
+ public:
+   cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer = NULL, bool 
Pause = false);
++  cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer, bool Pause, 
bool* reused);
++  void Construct(cDevice *Device, cTimers *Timers, cTimer *Timer, bool Pause, 
bool* reused);
+   virtual ~cRecordControl();
+   bool Process(time_t t);
+   cDevice *Device(void) { return device; }
+@@ -260,10 +262,12 @@ private:
+   static int state;
+ public:
+   static bool Start(cTimers *Timers, cTimer *Timer, bool Pause = false);
++  static bool Start(cTimers *Timers, cTimer *Timer, bool Pause, bool* reused);
+   static bool Start(bool Pause = false);
+   static void Stop(const char *InstantId);
+   static void Stop(cTimer *Timer);
+   static bool PauseLiveVideo(void);
++  static bool PauseLiveVideo(bool rewind);
+   static const char *GetInstantId(const char *LastInstantId);
+   static cRecordControl *GetRecordControl(const char *FileName);
+   static cRecordControl *GetRecordControl(const cTimer *Timer);
+@@ -320,6 +324,8 @@ private:
+   void EditTest(void);
+ public:
+   cReplayControl(bool PauseLive = false);
++  cReplayControl(ReplayState replayState);
++  void Construct(ReplayState replayState);
+   virtual ~cReplayControl();
+   void Stop(void);
+   virtual cOsdObject *GetInfo(void);
+diff --git a/receiver.h b/receiver.h
+index 9bbc6bdb..b76969bb 100644
+--- a/receiver.h
++++ b/receiver.h
+@@ -85,6 +85,10 @@ public:
+                ///< case the device is needed otherwise, so code that uses a 
cReceiver
+                ///< should repeatedly check whether it is still attached, and 
if
+                ///< it isn't, delete it (or take any other appropriate 
measures).
++  virtual bool IsPreRecording(const cChannel *Channel) { return false; }
++               ///< prerecords given channel; may be turned into a disc 
recording.
++  virtual bool ActivatePreRecording(const char* fileName, int Priority) { 
return false; }
++                         ///< turn prerecording into a disc recording
+   };
+ 
+ #endif //__RECEIVER_H
+diff --git a/recorder.c b/recorder.c
+index 0b3fdab1..dc5976c2 100644
+--- a/recorder.c
++++ b/recorder.c
+@@ -24,9 +24,19 @@
+ cRecorder::cRecorder(const char *FileName, const cChannel *Channel, int 
Priority)
+ :cReceiver(Channel, Priority)
+ ,cThread("recording")
++,ringBuffer(NULL), frameDetector(NULL), fileName(NULL), recordingInfo(NULL), 
index(NULL), recordFile(NULL), recordingName(NULL)
++{
++  if (FileName != NULL) {
++     InitializeFile(FileName, Channel);
++     }
++}
++
++void cRecorder::InitializeFile(const char *FileName, const cChannel *Channel)
+ {
+   recordingName = strdup(FileName);
+-  recordingInfo = new cRecordingInfo(recordingName);
++  if (recordingInfo == NULL) {
++     recordingInfo = new cRecordingInfo(recordingName);
++     }
+   recordingInfo->Read();
+   oldErrors = max(0, recordingInfo->Errors()); // in case this is a 
re-started recording
+   errors = 0;
+@@ -51,7 +61,9 @@ cRecorder::cRecorder(const char *FileName, const cChannel 
*Channel, int Priority
+      Pid = Channel->Dpid(0);
+      Type = 0x06;
+      }
+-  frameDetector = new cFrameDetector(Pid, Type);
++  if (frameDetector == NULL) {
++     frameDetector = new cFrameDetector(Pid, Type);
++     }
+   index = NULL;
+   fileSize = 0;
+   lastDiskSpaceCheck = time(NULL);
+diff --git a/recorder.h b/recorder.h
+index a1858635..caf067f3 100644
+--- a/recorder.h
++++ b/recorder.h
+@@ -16,8 +16,8 @@
+ #include "ringbuffer.h"
+ #include "thread.h"
+ 
+-class cRecorder : public cReceiver, cThread {
+-private:
++class cRecorder : public cReceiver, protected cThread {
++protected:
+   cRingBufferLinear *ringBuffer;
+   cFrameDetector *frameDetector;
+   cPatPmtGenerator patPmtGenerator;
+@@ -36,7 +36,6 @@ private:
+   bool RunningLowOnDiskSpace(void);
+   bool NextFile(void);
+   void HandleErrors(bool Force = false);
+-protected:
+   virtual void Activate(bool On);
+        ///< If you override Activate() you need to call Detach() (which is a
+        ///< member of the cReceiver class) from your own destructor in order
+@@ -44,6 +43,9 @@ protected:
+        ///< destroyed.
+   virtual void Receive(const uchar *Data, int Length);
+   virtual void Action(void);
++  void InitializeFile(const char *FileName, const cChannel *Channel);
++       ///< Starts recording to file.
++       ///< Called in constructor if file name has been given.
+ public:
+   cRecorder(const char *FileName, const cChannel *Channel, int Priority);
+        ///< Creates a new recorder for the given Channel and
+diff --git a/ringbuffer.c b/ringbuffer.c
+index 902c8878..89247d60 100644
+--- a/ringbuffer.c
++++ b/ringbuffer.c
+@@ -368,6 +368,25 @@ uchar *cRingBufferLinear::Get(int &Count)
+   return NULL;
+ }
+ 
++uchar *cRingBufferLinear::GetRest(int &Count)
++{
++  int Head = head;
++  if (getThreadTid <= 0)
++     getThreadTid = cThread::ThreadId();
++  int rest = Size() - tail;
++  int diff = Head - tail;
++  int cont = (diff >= 0) ? diff : Size() + diff - margin;
++  if (cont > rest)
++     cont = rest;
++  uchar *p = buffer + tail;
++  if (cont > 0) {
++     Count = gotten = cont;
++     return p;
++     }
++  WaitForGet();
++  return NULL;
++}
++
+ void cRingBufferLinear::Del(int Count)
+ {
+   if (Count > gotten) {
+diff --git a/ringbuffer.h b/ringbuffer.h
+index 746fc51e..6dfe6654 100644
+--- a/ringbuffer.h
++++ b/ringbuffer.h
+@@ -98,6 +98,12 @@ public:
+     ///< The data will remain in the buffer until a call to Del() deletes it.
+     ///< Returns a pointer to the data, and stores the number of bytes
+     ///< actually available in Count. If the returned pointer is NULL, Count 
has no meaning.
++  uchar *GetRest(int &Count);
++  ///< Gets data from the ring buffer disregarding the margin.
++  ///< Might have to be called several times to get all data.
++  ///< The data will remain in the buffer until a call to Del() deletes it.
++  ///< Returns a pointer to the data, and stores the number of bytes
++  ///< actually available in Count. If the returned pointer is NULL, Count 
has no meaning.
+   void Del(int Count);
+     ///< Deletes at most Count bytes from the ring buffer.
+     ///< Count must be less or equal to the number that was returned by a 
previous
+diff --git a/vdr.c b/vdr.c
+index 6056e2f0..08eaaaae 100644
+--- a/vdr.c
++++ b/vdr.c
+@@ -1359,13 +1359,24 @@ int main(int argc, char *argv[])
+                key = kNone;
+                break;
+           // Pausing live video:
++          case kFastRew:
++               if (cOsd::IsOpen())
++                  break;
++               {
++               // test if there's a live buffer to rewind into...
++               LOCK_CHANNELS_READ;
++               if 
(cDevice::ActualDevice()->GetPreRecording(Channels->GetByNumber(cDevice::CurrentChannel()))
 == NULL) {
++                  break;
++                  }
++               }
++               // fall through to pause
+           case kPlayPause:
+           case kPause:
+                if (!Control) {
+                   DELETE_MENU;
+                   if (Setup.PauseKeyHandling) {
+                      if (Setup.PauseKeyHandling > 1 || 
Interface->Confirm(tr("Pause live video?"))) {
+-                        if (!cRecordControls::PauseLiveVideo())
++                        if (!cRecordControls::PauseLiveVideo(int(key) == 
kFastRew))
+                            Skins.QueueMessage(mtError, tr("No free DVB device 
to record!"));
+                         }
+                      }

diff --git a/media-video/vdr/files/vdr-2.7.3_pinplugin.patch 
b/media-video/vdr/files/vdr-2.7.3_pinplugin.patch
new file mode 100644
index 000000000000..b4f8757cb445
--- /dev/null
+++ b/media-video/vdr/files/vdr-2.7.3_pinplugin.patch
@@ -0,0 +1,435 @@
+original vdr-pinplugin_vdr-2.3.1.diff
+rebased for media-video/vdr-2.6.7
+
+Signed-off-by: Christian Kunkel <[email protected]> ( 2021 Feb 12 )
+Reviewed-by: Martin Dummer <[email protected]> ( 2024-06-18 )
+diff -Naur vdr-2.6.7.orig/device.c vdr-2.6.7/device.c
+--- vdr-2.6.7.orig/device.c    2024-04-02 09:05:33.000000000 +0200
++++ vdr-2.6.7/device.c 2024-06-18 22:38:53.727925721 +0200
+@@ -847,6 +847,7 @@
+      const cChannel *Channel;
+      while ((Channel = Channels->GetByNumber(n, Direction)) != NULL) {
+            // try only channels which are currently available
++           if (!cStatus::MsgChannelProtected(0, Channel))      // PIN PATCH
+            if (GetDevice(Channel, LIVEPRIORITY, true, true))
+               break;
+            n = Channel->Number() + Direction;
+@@ -868,6 +869,12 @@
+ 
+ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
+ {
++  // I hope 'LiveView = false' indicates a channel switch for recording, // 
PIN PATCH
++  // I really don't know, but it works ...                               // 
PIN PATCH
++
++  if (LiveView && cStatus::MsgChannelProtected(this, Channel))           // 
PIN PATCH
++     return scrNotAvailable;                                             // 
PIN PATCH
++
+   cMutexLock MutexLock(&mutexChannel); // to avoid a race between SVDRP CHAN 
and HasProgramme()
+   cStatus::MsgChannelSwitch(this, 0, LiveView);
+ 
+diff -Naur vdr-2.6.7.orig/menu.c vdr-2.6.7/menu.c
+--- vdr-2.6.7.orig/menu.c      2024-04-02 09:05:33.000000000 +0200
++++ vdr-2.6.7/menu.c   2024-06-18 22:38:53.727925721 +0200
+@@ -1035,6 +1035,18 @@
+      Add(new cMenuEditBitItem( tr("VPS"),          &data.flags, tfVps));
+      Add(new cMenuEditIntItem( tr("Priority"),     &data.priority, 0, 
MAXPRIORITY));
+      Add(new cMenuEditIntItem( tr("Lifetime"),     &data.lifetime, 0, 
MAXLIFETIME));
++
++     // PIN PATCH
++     if (cOsd::pinValid || !data.fskProtection) Add(new 
cMenuEditBoolItem(tr("Childlock"),&data.fskProtection));
++     else {
++        char* buf = 0;
++        int res = 0;
++        res = asprintf(&buf, "%s\t%s", tr("Childlock"), data.fskProtection ? 
tr("yes") : tr("no"));
++        if (res < 0) ; // memory problems :o
++        Add(new cOsdItem(buf));
++        free(buf);
++        }
++
+      Add(file = new cMenuEditStrItem( tr("File"),   data.file, 
sizeof(data.file)));
+      SetFirstDayItem();
+      SetPatternItem(true);
+@@ -3129,7 +3141,8 @@
+                       }
+                    }
+                }
+-            if (*Item->Text() && !LastDir) {
++            if (*Item->Text() && !LastDir
++                && (!cStatus::MsgReplayProtected(Item->Recording(), 
Item->Name(), base, Item->IsDirectory(), true))) { // PIN PATCH
+                Add(Item);
+                LastItem = Item;
+                if (Item->IsDirectory())
+@@ -3200,6 +3213,9 @@
+ {
+   cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
+   if (ri) {
++     if (cStatus::MsgReplayProtected(ri->Recording(), ri->Name(), base,
++                                     ri->IsDirectory()) == true)    // PIN 
PATCH
++        return osContinue;
+      if (ri->IsDirectory())
+         Open();
+      else {
+@@ -4515,28 +4531,32 @@
+ 
+   // Basic menu items:
+ 
+-  Add(new cOsdItem(hk(tr("Schedule")),   osSchedule));
+-  Add(new cOsdItem(hk(tr("Channels")),   osChannels));
+-  Add(new cOsdItem(hk(tr("Timers")),     osTimers));
+-  Add(new cOsdItem(hk(tr("Recordings")), osRecordings));
++  // PIN PATCH
++  if (!cStatus::MsgMenuItemProtected("Schedule", true))   Add(new 
cOsdItem(hk(tr("Schedule")),   osSchedule));
++  if (!cStatus::MsgMenuItemProtected("Channels", true))   Add(new 
cOsdItem(hk(tr("Channels")),   osChannels));
++  if (!cStatus::MsgMenuItemProtected("Timers", true))     Add(new 
cOsdItem(hk(tr("Timers")),     osTimers));
++  if (!cStatus::MsgMenuItemProtected("Recordings", true)) Add(new 
cOsdItem(hk(tr("Recordings")), osRecordings));
+ 
+   // Plugins:
+ 
+   for (int i = 0; ; i++) {
+       cPlugin *p = cPluginManager::GetPlugin(i);
+       if (p) {
++         if (!cStatus::MsgPluginProtected(p, true)) {          // PIN PATCH
+          const char *item = p->MainMenuEntry();
+          if (item)
+             Add(new cMenuPluginItem(hk(item), i));
+          }
++      }
+       else
+          break;
+       }
+ 
+   // More basic menu items:
+ 
+-  Add(new cOsdItem(hk(tr("Setup")),      osSetup));
++  if (!cStatus::MsgMenuItemProtected("Setup", true)) Add(new 
cOsdItem(hk(tr("Setup")), osSetup));  // PIN PATCH
+   if (Commands.Count())
++     if (!cStatus::MsgMenuItemProtected("Commands", true))     // PIN PATCH
+      Add(new cOsdItem(hk(tr("Commands")),  osCommands));
+ 
+   Update(true);
+@@ -4609,6 +4629,14 @@
+   eOSState state = cOsdMenu::ProcessKey(Key);
+   HadSubMenu |= HasSubMenu();
+ 
++  // > PIN PATCH
++  cOsdItem* item = Get(Current());
++
++  if (item && item->Text() && state != osContinue && state != osUnknown && 
state != osBack)
++     if (cStatus::MsgMenuItemProtected(item->Text()))
++        return osContinue;
++  // PIN PATCH <
++
+   switch (state) {
+     case osSchedule:   return AddSubMenu(new cMenuSchedule);
+     case osChannels:   return AddSubMenu(new cMenuChannels);
+@@ -4633,6 +4661,7 @@
+                          if (item) {
+                             cPlugin *p = 
cPluginManager::GetPlugin(item->PluginIndex());
+                             if (p) {
++                            if (!cStatus::MsgPluginProtected(p)) {  // PIN 
PATCH
+                                cOsdObject *menu = p->MainMenuAction();
+                                if (menu) {
+                                   if (menu->IsMenu())
+@@ -4644,6 +4673,7 @@
+                                   }
+                                }
+                             }
++                         }
+                          state = osEnd;
+                        }
+                        break;
+@@ -4823,6 +4853,7 @@
+            Channel = Direction > 0 ? Channels->Next(Channel) : 
Channels->Prev(Channel);
+            if (!Channel && Setup.ChannelsWrap)
+               Channel = Direction > 0 ? Channels->First() : Channels->Last();
++           if (!cStatus::MsgChannelProtected(0, Channel))                   
// PIN PATCH
+            if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, 
LIVEPRIORITY, true, true))
+               return Channel;
+            }
+@@ -5500,6 +5531,7 @@
+            for (int i = 0; i < MAXRECORDCONTROLS; i++) {
+                if (!RecordControls[i]) {
+                   RecordControls[i] = new cRecordControl(device, Timers, 
Timer, Pause);
++                  cStatus::MsgRecordingFile(RecordControls[i]->FileName());  
// PIN PATCH
+                   return RecordControls[i]->Process(time(NULL));
+                   }
+                }
+diff -Naur vdr-2.6.7.orig/osd.c vdr-2.6.7/osd.c
+--- vdr-2.6.7.orig/osd.c       2024-04-02 09:05:33.000000000 +0200
++++ vdr-2.6.7/osd.c    2024-06-18 22:38:53.731925707 +0200
+@@ -1907,6 +1907,7 @@
+ cSize cOsd::maxPixmapSize(INT_MAX, INT_MAX);
+ cVector<cOsd *> cOsd::Osds;
+ cMutex cOsd::mutex;
++bool cOsd::pinValid = false;   // PIN PATCH
+ 
+ cOsd::cOsd(int Left, int Top, uint Level)
+ {
+diff -Naur vdr-2.6.7.orig/osd.h vdr-2.6.7/osd.h
+--- vdr-2.6.7.orig/osd.h       2024-04-02 09:05:33.000000000 +0200
++++ vdr-2.6.7/osd.h    2024-06-18 22:38:53.731925707 +0200
+@@ -994,6 +994,7 @@
+        ///<
+        ///< If a plugin uses a derived cPixmap implementation, it needs to 
use that
+        ///< type instead of cPixmapMemory.
++  static bool pinValid;   // PIN PATCH
+   };
+ 
+ #define MAXOSDIMAGES 64
+diff -Naur vdr-2.6.7.orig/status.c vdr-2.6.7/status.c
+--- vdr-2.6.7.orig/status.c    2024-04-02 09:05:33.000000000 +0200
++++ vdr-2.6.7/status.c 2024-06-18 22:38:53.731925707 +0200
+@@ -136,3 +136,55 @@
+   for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
+       sm->OsdProgramme(PresentTime, PresentTitle, PresentSubtitle, 
FollowingTime, FollowingTitle, FollowingSubtitle);
+ }
++
++bool cStatus::MsgChannelProtected(const cDevice* Device, const cChannel* 
Channel)     // PIN PATCH
++{
++  for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
++      if (sm->ChannelProtected(Device, Channel) == true)
++       return true;
++
++  return false;
++}
++
++bool cStatus::MsgReplayProtected(const cRecording* Recording, const char* 
Name,
++                                 const char* Base, bool isDirectory, int 
menuView)    // PIN PATCH
++{
++  for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
++     if (sm->ReplayProtected(Recording, Name, Base, isDirectory, menuView) == 
true)
++         return true;
++      return false;
++}
++
++void cStatus::MsgRecordingFile(const char* FileName)
++{
++  for (cStatus *sm = statusMonitors.First(); sm; sm = 
statusMonitors.Next(sm))   // PIN PATCH
++      sm->RecordingFile(FileName);
++}
++
++void cStatus::MsgTimerCreation(cTimer* Timer, const cEvent *Event)
++{
++  for (cStatus *sm = statusMonitors.First(); sm; sm = 
statusMonitors.Next(sm))   // PIN PATCH
++     sm->TimerCreation(Timer, Event);
++}
++
++bool cStatus::MsgPluginProtected(cPlugin* Plugin, int menuView)               
   // PIN PATCH
++{
++  for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
++     if (sm->PluginProtected(Plugin, menuView) == true)
++         return true;
++      return false;
++}
++
++void cStatus::MsgUserAction(const eKeys key)                                  
   // PIN PATCH
++{
++  for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
++     sm->UserAction(key);
++}
++
++bool cStatus::MsgMenuItemProtected(const char* Name, int menuView)            
   // PIN PATCH
++{
++  for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
++     if (sm->MenuItemProtected(Name, menuView) == true)
++         return true;
++      return false;
++}
+diff -Naur vdr-2.6.7.orig/status.h vdr-2.6.7/status.h
+--- vdr-2.6.7.orig/status.h    2024-04-02 09:05:33.000000000 +0200
++++ vdr-2.6.7/status.h 2024-06-18 22:38:53.731925707 +0200
+@@ -14,6 +14,7 @@
+ #include "device.h"
+ #include "player.h"
+ #include "tools.h"
++#include "plugin.h"
+ 
+ // Several member functions of the following classes are called with a 
pointer to
+ // an object from a global list (cTimer, cChannel, cRecording or cEvent). In 
these
+@@ -99,6 +100,22 @@
+                // The OSD displays the single line Text with the current 
channel information.
+   virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, 
const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, 
const char *FollowingSubtitle) {}
+                // The OSD displays the given programme information.
++  virtual bool ChannelProtected(const cDevice *Device, const cChannel* 
Channel)  { return false; }         // PIN PATCH
++               // Checks if a channel is protected.
++  virtual bool ReplayProtected(const cRecording* Recording, const char* Name,
++                               const char* Base, bool isDirectory, int 
menuView = false) { return false; } // PIN PATCH
++               // Checks if a recording is protected.
++  virtual void RecordingFile(const char* FileName) {}                         
                             // PIN PATCH
++               // The given DVB device has started recording to FileName. 
FileName is the name of the
++               // recording directory
++  virtual void TimerCreation(cTimer* Timer, const cEvent *Event) {}           
                             // PIN PATCH
++               // The given timer is created
++  virtual bool PluginProtected(cPlugin* Plugin, int menuView = false)  { 
return false; }                   // PIN PATCH
++               // Checks if a plugin is protected.
++  virtual void UserAction(const eKeys key) {}                                 
                             // PIN PATCH
++               // report user action
++  virtual bool MenuItemProtected(const char* Name, int menuView = false)  { 
return false; }                // PIN PATCH
++
+ public:
+   cStatus(void);
+   virtual ~cStatus();
+@@ -122,6 +139,14 @@
+   static void MsgOsdTextItem(const char *Text,  bool Scroll = false);
+   static void MsgOsdChannel(const char *Text);
+   static void MsgOsdProgramme(time_t PresentTime, const char *PresentTitle, 
const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, 
const char *FollowingSubtitle);
++  static bool MsgChannelProtected(const cDevice* Device, const cChannel* 
Channel);                 // PIN PATCH
++  static bool MsgReplayProtected(const cRecording* Recording, const char* 
Name,
++                                 const char* Base, bool isDirectory, int 
menuView = false);        // PIN PATCH
++  static void MsgRecordingFile(const char* FileName);                         
                     // PIN PATCH
++  static void MsgTimerCreation(cTimer* Timer, const cEvent *Event);           
                     // PIN PATCH
++  static bool MsgPluginProtected(cPlugin* Plugin, int menuView = false);      
                     // PIN PATCH
++  static void MsgUserAction(const eKeys key);                                 
                     // PIN PATCH
++  static bool MsgMenuItemProtected(const char* Name, int menuView = false);   
                     // PIN PATCH
+   };
+ 
+ #endif //__STATUS_H
+diff -Naur vdr-2.6.7.orig/timers.c vdr-2.6.7/timers.c
+--- vdr-2.6.7.orig/timers.c    2024-04-02 09:05:33.000000000 +0200
++++ vdr-2.6.7/timers.c 2024-06-18 22:41:36.147349313 +0200
+@@ -85,6 +85,7 @@
+      stop -= 2400;
+   priority = Pause ? Setup.PausePriority : Setup.DefaultPriority;
+   lifetime = Pause ? Setup.PauseLifetime : Setup.DefaultLifetime;
++  fskProtection = 0;                                        // PIN PATCH
+   if (Instant && channel)
+      snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", 
*Setup.NameInstantRecord ? Setup.NameInstantRecord : channel->Name());
+ }
+@@ -218,11 +219,13 @@
+      stop -= 2400;
+   priority = PatternTimer ? PatternTimer->Priority() : Setup.DefaultPriority;
+   lifetime = PatternTimer ? PatternTimer->Lifetime() : Setup.DefaultLifetime;
++  fskProtection = 0;                                        // PIN PATCH
+   if (!FileName)
+      FileName = Event->Title();
+   if (!isempty(FileName))
+      Utf8Strn0Cpy(file, FileName, sizeof(file));
+   SetEvent(Event);
++  cStatus::MsgTimerCreation(this, Event);                   // PIN PATCH
+ }
+ 
+ cTimer::cTimer(const cTimer &Timer)
+@@ -261,6 +264,7 @@
+      stop         = Timer.stop;
+      priority     = Timer.priority;
+      lifetime     = Timer.lifetime;
++     fskProtection = Timer.fskProtection;    // PIN PATCH
+      vpsNotRunning = 0;
+      vpsActive    = false;
+      strncpy(pattern, Timer.pattern, sizeof(pattern));
+@@ -492,6 +496,7 @@
+         result = false;
+         }
+      }
++  fskProtection = aux && strstr(aux, 
"<pin-plugin><protected>yes</protected></pin-plugin>");  // PIN PATCH
+   free(channelbuffer);
+   free(daybuffer);
+   free(filebuffer);
+@@ -1069,6 +1074,36 @@
+   Matches(); // refresh start and end time
+ }
+ 
++void cTimer::SetFskProtection(int aFlag)      // PIN PATCH
++{
++   char* p;
++   char* tmp = 0;
++   int res = 0;
++
++   fskProtection = aFlag;
++
++   if (fskProtection && (!aux || !strstr(aux, 
"<pin-plugin><protected>yes</protected></pin-plugin>")))
++   {
++      // add protection info to aux
++
++      if (aux) { tmp = strdup(aux); free(aux); }
++      res = asprintf(&aux, 
"%s<pin-plugin><protected>yes</protected></pin-plugin>", tmp ? tmp : "");
++   }
++   else if (!fskProtection && aux && (p = strstr(aux, 
"<pin-plugin><protected>yes</protected></pin-plugin>")))
++   {
++      // remove protection info from aux
++
++      res = asprintf(&tmp, "%.*s%s", (int)(p-aux), aux, 
p+strlen("<pin-plugin><protected>yes</protected></pin-plugin>"));
++      free(aux);
++      aux = strdup(tmp);
++   }
++
++   if (res < 0) ; // memory problems :o
++
++   if (tmp)
++      free(tmp);
++}
++
+ // --- cTimers ---------------------------------------------------------------
+ 
+ cTimers cTimers::timers;
+diff -Naur vdr-2.6.7.orig/timers.h vdr-2.6.7/timers.h
+--- vdr-2.6.7.orig/timers.h    2024-04-02 09:05:33.000000000 +0200
++++ vdr-2.6.7/timers.h 2024-06-18 22:38:53.731925707 +0200
+@@ -47,6 +47,7 @@
+   int start;          ///< the start and stop time of this timer as given by 
the user,
+   int stop;           ///< in the form hhmm, with hh (00..23) and mm (00..59) 
added as hh*100+mm
+   int priority;
++  int fskProtection;                                               // PIN 
PATCH
+   int lifetime;
+   mutable char pattern[NAME_MAX * 2 + 1]; // same size as 'file', to be able 
to initially fill 'pattern' with 'file' in the 'Edit timer' menu
+   mutable char file[NAME_MAX * 2 + 1]; // *2 to be able to hold 'title' and 
'episode', which can each be up to 255 characters long
+@@ -72,6 +73,7 @@
+   int Start(void) const { return start; }
+   int Stop(void) const { return stop; }
+   int Priority(void) const { return priority; }
++  int FskProtection(void) const { return fskProtection; }          // PIN 
PATCH
+   int Lifetime(void) const { return lifetime; }
+   const char *Pattern(void) const { return pattern; }
+   const char *File(void) const { return file; }
+@@ -122,6 +124,7 @@
+   void SetRemote(const char *Remote);
+   void SetDeferred(int Seconds);
+   void SetFlags(uint Flags);
++  void SetFskProtection(int aFlag);                                // PIN 
PATCH
+   void ClrFlags(uint Flags);
+   void InvFlags(uint Flags);
+   bool HasFlags(uint Flags) const;
+diff -Naur vdr-2.6.7.orig/vdr.c vdr-2.6.7/vdr.c
+--- vdr-2.6.7.orig/vdr.c       2024-04-02 09:05:33.000000000 +0200
++++ vdr-2.6.7/vdr.c    2024-06-18 22:38:53.735925694 +0200
+@@ -72,6 +72,7 @@
+ #include "tools.h"
+ #include "transfer.h"
+ #include "videodir.h"
++#include "status.h"     // PIN PATCH
+ 
+ #define MINCHANNELWAIT        10 // seconds to wait between failed channel 
switchings
+ #define ACTIVITYTIMEOUT       60 // seconds before starting housekeeping
+@@ -1217,6 +1218,7 @@
+         if (!Menu)
+            Interact = Control = cControl::Control(ControlMutexLock);
+         if (ISREALKEY(key)) {
++           cStatus::MsgUserAction(key);           // PIN PATCH
+            EITScanner.Activity();
+            // Cancel shutdown countdown:
+            if (ShutdownHandler.countdown)
+@@ -1289,10 +1291,12 @@
+                      Control->Hide();
+                   cPlugin *plugin = cPluginManager::GetPlugin(PluginName);
+                   if (plugin) {
++                     if (!cStatus::MsgPluginProtected(plugin)) {  // PIN PATCH
+                      Menu = plugin->MainMenuAction();
+                      if (Menu)
+                         Menu->Show();
+                      }
++                  }
+                   else
+                      esyslog("ERROR: unknown plugin '%s'", PluginName);
+                   }
+@@ -1512,9 +1516,11 @@
+              case kPlay:
+                   if (cReplayControl::LastReplayed()) {
+                      Control = NULL;
++                     if (cStatus::MsgReplayProtected(0, 
cReplayControl::LastReplayed(), 0, false) == false) {  // PIN PATCH
+                      cControl::Shutdown();
+                      cControl::Launch(new cReplayControl);
+                      }
++                  }
+                   else
+                      DirectMainFunction(osRecordings); // no last viewed 
recording, so enter the Recordings menu
+                   break;

diff --git a/media-video/vdr/vdr-2.7.3.ebuild b/media-video/vdr/vdr-2.7.3.ebuild
new file mode 100644
index 000000000000..bf5158e8e8cc
--- /dev/null
+++ b/media-video/vdr/vdr-2.7.3.ebuild
@@ -0,0 +1,197 @@
+# Copyright 2021-2024 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=8
+
+inherit flag-o-matic strip-linguas toolchain-funcs user-info
+
+DESCRIPTION="Video Disk Recorder - turns a pc into a powerful set top box for 
DVB"
+HOMEPAGE="https://www.tvdr.de/";
+SRC_URI="https://git.tvdr.de/?p=vdr.git;a=snapshot;h=refs/tags/${PV};sf=tbz2 
-> ${P}.tbz2
+       menuorg? ( 
https://github.com/vdr-projects/vdr-plugin-menuorg/raw/master/vdr-patch/vdr-menuorg-2.3.x.diff
 )
+       ttxtsubs? ( https://md11.it.cx/download/${PN}/${P}_ttxtsubs_v2.patch )"
+
+LICENSE="GPL-2+"
+SLOT="0/5" # config.h: APIVERSION "5"
+KEYWORDS="~amd64 ~arm ~arm64 ~ppc ~x86"
+IUSE="bidi debug demoplugins keyboard mainmenuhooks menuorg naludump 
permashift pinplugin systemd ttxtsubs verbose"
+
+COMMON_DEPEND="
+       acct-group/vdr
+       acct-user/vdr
+       media-libs/fontconfig
+       media-libs/freetype
+       media-libs/libjpeg-turbo:=
+       sys-libs/libcap"
+DEPEND="${COMMON_DEPEND}
+       sys-kernel/linux-headers"
+RDEPEND="${COMMON_DEPEND}
+       dev-lang/perl
+       media-tv/gentoo-vdr-scripts
+       media-fonts/corefonts
+       bidi? ( dev-libs/fribidi )
+       systemd? ( sys-apps/systemd )"
+BDEPEND="
+       sys-devel/gettext
+       virtual/pkgconfig"
+
+REQUIRED_USE="permashift? ( !naludump !pinplugin )"
+
+CONF_DIR="/etc/vdr"
+CAP_FILE="${S}/capabilities.sh"
+CAPS="# Capabilities of the vdr-executable for use by startscript etc."
+
+pkg_setup() {
+       use debug && append-flags -g
+
+       PLUGIN_LIBDIR="/usr/$(get_libdir)/vdr/plugins"
+       VIDEO_DIR="$(egethome vdr)/video"
+
+       tc-export CC CXX AR
+}
+
+add_cap() {
+       local arg
+       for arg; do
+               CAPS="${CAPS}\n${arg}=1"
+       done
+}
+
+lang_po() {
+       LING_PO=$( ls "${S}"/po | sed -e "s:.po::g" | cut -d_ -f1 | tr \\\012 ' 
' )
+}
+
+src_prepare() {
+       # apply maintenance-patches
+       ebegin "Changing paths for gentoo"
+
+       local DVBDIR=/usr/include
+       local i
+       for i in ${DVB_HEADER_PATH} /usr/include/v4l-dvb-hg /usr/include; do
+               [[ -d ${i} ]] || continue
+               if [[ -f ${i}/linux/dvb/dmx.h ]]; then
+                       einfo "Found DVB header files in ${i}"
+                       DVBDIR=${i}
+                       break
+               fi
+       done
+
+       # checking for s2api headers
+       local api_version
+       api_version=$(awk -F' ' '/define DVB_API_VERSION / {print $3}' 
"${DVBDIR}"/linux/dvb/version.h)
+       api_version=${api_version}*$(awk -F' ' '/define DVB_API_VERSION_MINOR / 
{print $3}' "${DVBDIR}"/linux/dvb/version.h)
+
+       if [[ ${api_version:-0} -lt 5*3 ]]; then
+               eerror "DVB header files do not contain s2api support or too 
old for ${P}"
+               eerror "You cannot compile VDR against old dvb-header"
+               die "DVB headers too old"
+       fi
+
+       cat > Make.config <<-EOT || die "cannot write to Make.config"
+               #
+               # Generated by ebuild ${PF}
+               #
+               PREFIX                  = /usr
+               DVBDIR                  = ${DVBDIR}
+               PLUGINLIBDIR    = ${PLUGIN_LIBDIR}
+               CONFDIR                 = ${CONF_DIR}
+               ARGSDIR                 = \$(CONFDIR)/conf.d
+               VIDEODIR                = ${VIDEO_DIR}
+               LOCDIR                  = \$(PREFIX)/share/locale
+               INCDIR                  = \$(PREFIX)/include
+
+               DEFINES                 += -DCONFDIR=\"\$(CONFDIR)\"
+               INCLUDES                += -I\$(DVBDIR)
+
+               # >=vdr-1.7.36-r1; parameter only used for compiletime on vdr
+               # PLUGINLIBDIR (plugin Makefile old) = LIBDIR (plugin Makefile 
new)
+               LIBDIR                  = ${PLUGIN_LIBDIR}
+               PCDIR                   = /usr/$(get_libdir)/pkgconfig
+
+       EOT
+       eend 0
+
+       eapply "${FILESDIR}/vdr-2.6.6_gentoo.patch"
+       use demoplugins || eapply "${FILESDIR}/vdr-2.4_remove_plugins.patch"
+       eapply "${FILESDIR}/${PN}-2.4.6_makefile-variables.patch"
+
+       # fix clang/LLVM compile
+       eapply "${FILESDIR}/${PN}-2.4.6_clang.patch"
+
+       use naludump && eapply "${FILESDIR}/${PN}-2.6.1_naludump.patch"
+       use permashift && eapply 
"${FILESDIR}/${PN}-2.7.2-patch-for-permashift.patch"
+       use pinplugin && eapply "${FILESDIR}/${PN}-2.7.3_pinplugin.patch"
+       use ttxtsubs && eapply "${DISTDIR}/${P}_ttxtsubs_v2.patch"
+       use menuorg && eapply "${DISTDIR}/vdr-menuorg-2.3.x.diff"
+       use mainmenuhooks && eapply 
"${FILESDIR}/${PN}-2.4.1_mainmenuhook-1.0.1.patch"
+
+       add_cap CAP_UTF8 \
+               CAP_IRCTRL_RUNTIME_PARAM \
+               CAP_VFAT_RUNTIME_PARAM \
+               CAP_CHUID \
+               CAP_SHUTDOWN_AUTO_RETRY
+
+       echo -e ${CAPS} > "${CAP_FILE}" || die "cannot write to CAP_FILE"
+
+       # LINGUAS support
+       einfo "\n \t VDR supports the LINGUAS values"
+
+       lang_po
+
+       einfo "\t Please set one of this values in your sytem make.conf"
+       einfo "\t LINGUAS=\"${LING_PO}\"\n"
+
+       if [[ -z ${LINGUAS} ]]; then
+               einfo "\n \t No values in LINGUAS="
+               einfo "\t You will get only english text on OSD \n"
+       fi
+
+       strip-linguas ${LING_PO} en
+
+       default
+}
+
+src_configure() {
+       # support languages, written from right to left
+       export "BIDI=$(usex bidi 1 0)"
+       # systemd notification support
+       export "SDNOTIFY=$(usex systemd 1 0)"
+       # with/without keyboard
+       export "USE_KBD=$(usex keyboard 1 0)"
+       # detailed compile output for debug
+       export "VERBOSE=$(usex verbose 1 0)"
+}
+
+src_install() {
+       # trick the makefile to not create a VIDEODIR by supplying it with an
+       # existing directory
+       emake VIDEODIR="/" DESTDIR="${ED}" install
+
+       keepdir "${PLUGIN_LIBDIR}"
+
+       # backup for plugins they don't be able to create this dir
+       keepdir "${CONF_DIR}/plugins"
+
+       local HTML_DOCS=( *.html )
+       local DOCS=( MANUAL INSTALL README* HISTORY CONTRIBUTORS UPDATE-2* )
+       einstalldocs
+
+       insinto /usr/share/vdr
+       doins "${CAP_FILE}"
+
+       fowners vdr:vdr "${CONF_DIR}" -R
+}
+
+pkg_postinst() {
+       elog "Please read the /usr/share/doc/${PF}/UPDATE-2.4"
+       elog "for major changes in this version\n"
+
+       elog "It is a good idea to run vdrplugin-rebuild now.\n"
+
+       elog "To get nice symbols in OSD we recommend to install"
+       elog "\t1. emerge media-fonts/vdrsymbols-ttf"
+       elog "\t2. select font VDRSymbolsSans in Setup\n"
+
+       elog "To get an idea how to proceed now, have a look at our vdr-guide:"
+       elog "\thttps://wiki.gentoo.org/wiki/VDR";
+}


Reply via email to