Вопрос

Я живу на другом конце света от своего дома (сейчас GMT + 1, дома GMT + 13), и я скучаю по своей старой наземной радиостанции.У него есть трансляция Shoutcast, и я хотел бы просто отложить ее на 12 часов, чтобы она всегда была доступна, когда я захочу ее прослушать, таким образом, чтобы ее часовой пояс был синхронизирован с моим часовым поясом.

Я представляю себе это как скрипт, запускаемый на моем сервере.

Наивным подходом было бы просто выделить достаточно оперативной памяти в кольцевом буфере для хранения всей 12-часовой задержки и передать выходные данные из streamripper.Но поток представляет собой mp3 со скоростью 128 кбит / с, что означало бы (128/8) * 60 * 60 = ~ 56 МБ в час, или 675 МБ для всего 12-часового буфера, что на самом деле не так практично.Кроме того, мне, возможно, придется иметь дело с тем, что хост моего сервера просто завершает процесс по истечении определенного времени ожидания.

Итак, каковы некоторые стратегии, которые действительно могут быть практичными?

Это было полезно?

Решение

Потоковый риппер был бы простым способом и, вероятно, правильным, но если вы хотите сделать это программистским способом....

  • Большинство машин для разработки имеют довольно большой объем оперативной памяти.Вы УВЕРЕНЫ, что не можете сэкономить 675 МБ?
  • Вместо того, чтобы хранить выходные данные в буфере, разве вы не можете хранить их в файле или файлах, скажем, по часу за раз?(по сути, вы бы написали свой собственный потоковый риппер)
  • Преобразуйте поток в более низкий битрейт, если вы можете допустить потерю качества

Другие советы

Почему бы вам просто не скачать его с потоковым риппером, например Ripshout или чем-то еще?

чтобы ответить на мой собственный вопрос, вот скрипт, который запускается как задание cron каждые 30 минут. он сбрасывает входящий поток за 5 минут (или задается с помощью FILE _ SECONDS) в конкретный каталог. границы блоков синхронизируются с часами, и запись не начинается до тех пор, пока конец текущего чанка времени не будет, поэтому выполняющиеся cronjobs могут перекрываться, не удваивая данные и не оставляя пробелов. файлы называются (время эпохи% количество секунд в 24 часах) .str.

Я еще не сделал игрока, но планировалось установить выходной каталог где-нибудь доступным через Интернет, и написать скрипт для локального запуска, который использует тот же код для вычисления метки времени, что и здесь, для последовательного доступа (метка времени 12 часов назад) .str, соберите их снова вместе, а затем локально установите в качестве сервера shoutcast. тогда я мог бы просто указать свой музыкальный проигрыватель на http: // localhost: port и получить его.

edit: новая версия с тайм-аутами и улучшенной проверкой состояния ошибок, а также красивый файл журнала. в настоящее время он работает без проблем на моем (дешевом) общем веб-хосте, без проблем.

#!/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()
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top