문제

나는 집에서 세계 반대편에 살고 있습니다 (GMT+1, GMT+13은 집입니다). 그것은 외침 스트림이 있으며, 시간대를 내 시간대와 동기화하는 방식으로 듣고 싶을 때 항상 사용할 수 있도록 12 시간을 단순히 지연시키고 싶습니다.

나는 이것을 서버 호스트에서 실행중인 스크립트로 구상합니다.

순진한 접근 방식은 단순히 12 시간 지연을 저장하기 위해 Ringbuffer에 충분한 RAM을 할당하고 StreamRipper의 출력에 파이프를 할당하는 것입니다. 그러나 스트림은 128kbps mp3로, 시간당 (128/8) * 60 * 60 = ~ 56MB 또는 전체 12 시간 버퍼의 경우 675MB를 의미합니다. 또한 특정 시간 초과 후 프로세스를 죽이는 서버 호스트를 처리해야 할 수도 있습니다.

그렇다면 실제로 실용적 일 수있는 몇 가지 전략은 무엇입니까?

도움이 되었습니까?

해결책

스트림 리퍼는 쉬운 방법이자 아마도 올바른 방법 일 것입니다. 그러나 당신이 그것을하고 싶다면 프로그래머 방법입니다 ....

  • 대부분의 개발 기계에는 약간의 RAM이 있습니다. 675MB를 절약 할 수 없습니까?
  • 버퍼에 출력을 저장하는 대신 파일이나 파일에 저장할 수는 없습니다. 한 번에 한 시간 씩 말하십시오. (본질적으로, 당신은 자신의 스트림 리퍼를 쓸 것입니다)
  • 품질 손실을 견딜 수 있다면 스트림을 낮은 비트 전송률로 변환하십시오.

다른 팁

Ripshout 같은 스트림 리퍼로 다운로드하지 않겠습니까?

내 질문에 대답하기 위해 여기에 30 분마다 Cron 작업으로 시작하는 대본이 있습니다. 5 분 덩어리로 들어오는 스트림을 특정 디렉토리에 5 분 덩어리로 덤프합니다. 블록 경계는 시계와 동기화되며 현재 시간 청크의 경우, 실행중인 크론 조브는 데이터를 두 배로 늘리거나 갭을 남기지 않고 겹칠 수 있습니다. 파일은 (24 시간에 epoch time % %) .str로 명명되었습니다.

아직 플레이어를 만들지 않았지만 계획은 출력 디렉토리를 웹에 액세스 할 수있는 곳으로 설정하고 여기와 동일한 타임 스탬프 계산 코드를 사용하여 순차적으로 액세스하기 위해 로컬로 실행하도록 스크립트를 작성하는 것이 었습니다 (12 시간 전). ) .Str, 다시 함께 다시 태어난 다음 로컬로 외침 서버로 설정하십시오. 그런 다음 음악 연주자를 가리킬 수있었습니다 http : // localhost : 포트 그리고 그것을 얻으십시오.

편집 : 타임 아웃 및 더 나은 오류 조건 확인과 새로운 로그 파일이있는 새 버전. 이것은 현재 (저렴한) 공유 웹 호스트에서 문제없이 히치 프리를 실행하고 있습니다.

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