Frage

ich auf der anderen Seite der Welt von meinem Hause lebe (GMT + 1 jetzt, GMT + 13 ist zu Hause), und ich vermisse meine alten terrestrischen Radiosender. Es hat einen Shoutcast- Strom, und ich möchte es einfach um 12 Stunden verzögern, so dass es immer verfügbar ist, wenn ich es hören wollen, in einer Weise, dass seine Zeitzone auf meine Zeitzone synchronisiert machen würde.

Ich sehe dies als ein Skript auf meinem Server-Host ausgeführt wird.

Ein naiver Ansatz würde einfach sein, um genügend RAM in einem Ringpuffer zuzuweisen die gesamte 12 Stunden Verzögerung zu speichern, und das Rohr in der Ausgabe von Stream. Aber der Strom ist ein 128 kbps mp3, was bedeuten würde (128/8) * 60 * 60 = ~ 56MB pro Stunde oder 675MB für die ganzen 12 Stunden Puffer, die nicht wirklich so praktisch ist. Plus, ich könnte mit meiner Server-Host zu tun habe gerade nach einer gewissen Zeit, um den Prozess zu töten.

Also, was sind einige Strategien, die wirklich praktisch sein könnten?

War es hilfreich?

Lösung

Ein Stream-Ripper wäre der einfache Weg, und wahrscheinlich der richtige Weg, aber wenn Sie wollen, dass es die Programmierer Art und Weise zu tun ....

  • Die meisten Entwicklungsmaschinen haben ziemlich viel RAM. Sind Sie sicher, Sie können nicht 675 MB verschonen?
  • Anstatt speichern die Ausgabe in einem Puffer können Sie es nicht speichern, in einer oder mehreren Dateien (s), sagen eine Stunde in einer Zeit? (Im Wesentlichen, würden Sie Ihren eigenen Stream-Ripper schreiben)
  • Konvertieren des Stromes auf eine niedrigere Bitrate, wenn Sie den Verlust in der Qualität tolerieren können

Andere Tipps

Warum gehst du nicht einfach laden Sie es mit einem Strom-Ripper wie Ripshout oder etwas?

meine eigene Frage zu beantworten, hier ist ein Skript, das alle 30 Minuten als cron-Job gestartet. Dumps es den ankommenden Strom in 5-Minuten-Chunks (oder einen Satz von FILE _ Sekunden) auf ein bestimmtes Verzeichnis. Blockgrenzen sind mit dem Takt synchronisiert, und es beginnt erst das Schreiben von Ende der aktuellen Zeit Brocken, so dass der Lauf Cronjobs kann sie überlappen, ohne dass Daten zu verdoppeln oder Lücken zu verlassen. Dateien werden als (Epochenzeit% Anzahl der Sekunden in 24 Stunden) .str benannt.

Ich habe keinen Spieler noch, aber der Plan war, um das Ausgabeverzeichnis irgendwo Webzugriff, und schreiben Sie einen Skript aus lokal ausgeführt werden, die wie hier den gleichen Zeitstempel-Berechnung Code verwendet Zugriff auf sequentiell (Zeitstempel vor 12 Stunden) .str, heftet sie wieder zusammen, und dann als ein Shoutcast-Server lokal einrichten. dann konnte ich nur an meinem Musik-Player zeigen http: // localhost: port. und es bekommen

edit: Neue Version mit Timeouts und bessere Fehlerzustand Prüfung, sowie nette Protokolldatei. dies wird zur Zeit läuft reibungslos frei auf meinem (billig) geteilt Webhost, ohne Probleme.

#!/usr/bin/python
import time
import urllib
import datetime
import os
import socket

# number of seconds for each file
FILE_SECONDS = 300

# run for 30 minutes
RUN_TIME = 60*30

# size in bytes of each read block
# 16384 = 1 second
BLOCK_SIZE = 16384

MAX_TIMEOUTS = 10

# where to save the files
OUTPUT_DIRECTORY = "dir/"
# URL for original stream
URL = "http://url/path:port"

debug = True
log = None
socket.setdefaulttimeout(10)

class DatestampedWriter:

    # output_path MUST have trailing '/'
    def __init__(self, output_path, run_seconds ):
        self.path = output_path
        self.file = None
        # needs to be -1 to avoid issue when 0 is a real timestamp
        self.curr_timestamp = -1
        self.running = False
        # don't start until the _end_ of the current time block
        # so calculate an initial timestamp as (now+FILE_SECONDS)
        self.initial_timestamp = self.CalcTimestamp( FILE_SECONDS )
        self.final_timestamp = self.CalcTimestamp( run_seconds )
        if debug:
            log = open(OUTPUT_DIRECTORY+"log_"+str(self.initial_timestamp)+".txt","w")
            log.write("initial timestamp "+str(self.initial_timestamp)+", final "+str(self.final_timestamp)+" (diff "+str(self.final_timestamp-self.initial_timestamp)+")\n")

        self.log = log

    def Shutdown(self):
        if self.file != None:
            self.file.close()

    # write out buf
    # returns True when we should stop
    def Write(self, buf):
        # check that we have the correct file open

        # get timestamp
        timestamp = self.CalcTimestamp()

        if not self.running :
            # should we start?
            if timestamp == self.initial_timestamp:
                if debug:
                    self.log.write( "starting running now\n" )
                    self.log.flush()
                self.running = True

        # should we open a new file?
        if self.running and timestamp != self.curr_timestamp:
            if debug:
                self.log.write( "new timestamp "+str(timestamp)+"\n" )
                self.log.flush()
            # close old file
            if ( self.file != None ):
                self.file.close()
            # time to stop?
            if ( self.curr_timestamp == self.final_timestamp ):
                if debug:
                    self.log.write( " -- time to stop\n" )
                    self.log.flush()
                self.running = False
                return True
            # open new file
            filename = self.path+str(timestamp)+".str"
            #if not os.path.exists(filename):
            self.file = open(filename, "w")
            self.curr_timestamp = int(timestamp)
            #else:
                # uh-oh
            #   if debug:
            #       self.log.write(" tried to open but failed, already there\n")
            #   self.running = False

        # now write bytes
        if self.running:
            #print("writing "+str(len(buf)))
            self.file.write( buf )

        return False

    def CalcTimestamp(self, seconds_offset=0):
        t = datetime.datetime.now()
        seconds = time.mktime(t.timetuple())+seconds_offset
        # FILE_SECONDS intervals, 24 hour days
        timestamp = seconds - ( seconds % FILE_SECONDS )
        timestamp = timestamp % 86400
        return int(timestamp)


writer = DatestampedWriter(OUTPUT_DIRECTORY, RUN_TIME)

writer_finished = False

# while been running for < (RUN_TIME + 5 minutes)
now = time.mktime(datetime.datetime.now().timetuple())
stop_time = now + RUN_TIME + 5*60
while not writer_finished and time.mktime(datetime.datetime.now().timetuple())<stop_time:

    now = time.mktime(datetime.datetime.now().timetuple())

    # open the stream
    if debug:
        writer.log.write("opening stream... "+str(now)+"/"+str(stop_time)+"\n")
        writer.log.flush()
    try:
        u = urllib.urlopen(URL)
    except socket.timeout:
        if debug:
            writer.log.write("timed out, sleeping 60 seconds\n")
            writer.log.flush()
        time.sleep(60)
        continue
    except IOError:
        if debug:
            writer.log.write("IOError, sleeping 60 seconds\n")
            writer.log.flush()
        time.sleep(60)
        continue
        # read 1 block of input
    buf = u.read(BLOCK_SIZE)

    timeouts = 0
    while len(buf) > 0 and not writer_finished and now<stop_time and timeouts<MAX_TIMEOUTS:
        # write to disc
        writer_finished = writer.Write(buf)

        # read 1 block of input
        try:
            buf = u.read(BLOCK_SIZE)
        except socket.timeout:
            # catch exception but do nothing about it
            if debug:
                writer.log.write("read timed out ("+str(timeouts)+")\n")
                writer.log.flush()
            timeouts = timeouts+1

        now = time.mktime(datetime.datetime.now().timetuple())
    # stream has closed,
    if debug:
        writer.log.write("read loop bailed out: timeouts "+str(timeouts)+", time "+str(now)+"\n")
        writer.log.flush()
    u.close();
    # sleep 1 second before trying to open the stream again
    time.sleep(1)

    now = time.mktime(datetime.datetime.now().timetuple())

writer.Shutdown()
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top