2008-12-03 8 views
1

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

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

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

Итак, какие стратегии могут быть практическими?

+0

Почему нет 675 МБ оперативной памяти? С сегодняшней ценой ОЗУ, потратьте 25 долларов и получите решение ... проблема решена. – rmeador 2008-12-03 20:46:12

ответ

1

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

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

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

+0

Мне нравится разорвать поток, чтобы я мог слушать шоу всякий раз, когда не только ровно через 12 часов ... – Karl 2008-12-03 20:10:30

0

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

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

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

#!/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() 

 Смежные вопросы

  • Нет связанных вопросов^_^