تأخير تيار شوتكاست قبل 12 ساعة (لينكس/باش)
-
19-08-2019 - |
سؤال
أنا أعيش على الجانب الآخر من العالم من بيتي (GMT+1 الآن ، GMT+13 المنزل) ، أشتاق القديم الأرضية محطة إذاعية.وقد تيار شوتكاست, وأود أن مجرد تأخير ذلك قبل 12 ساعة بحيث يكون متاح دائما عندما أريد الاستماع إليها ، بطريقة من شأنها أن تجعل التوقيت تتم مزامنة التوقيت.
أتصور هذا البرنامج النصي التي يتم تشغيلها على الخادم المضيف.
ساذجة النهج سيكون ببساطة إلى تخصيص ما يكفي من ذاكرة الوصول العشوائي في ringbuffer لتخزين كامل 12 ساعة تأخير الأنابيب في الإخراج من streamripper.ولكن هو تيار 128kbps mp3, مما يعني (128/8) * 60 * 60 = ~56MB في الساعة ، أو 675MB طوال 12 ساعة العازلة التي ليس عملي جدا.بالإضافة إلى أنني قد تضطر إلى التعامل مع الخادم المضيف فقط قتل العملية بعد فترة معينة من المهلة.
إذا ، ما هي بعض الاستراتيجيات التي قد تكون في الواقع عملية ؟
المحلول
تيار السفاح سيكون بطريقة سهلة و ربما في الطريق الصحيح, ولكن إذا كنت تريد أن تفعل ذلك مبرمج الطريقة....
- معظم التنمية آلات قليلا جدا من ذاكرة الوصول العشوائي.هل أنت متأكد من أنك لا يمكن أن تدخر 675 MB ؟
- بدلا من تخزين الناتج في منطقة عازلة لا يمكنك تخزينه في ملف أو ملفات(s), أقول ساعة في المرة الواحدة ؟ (أساسا ، سيكون من الكتابة الخاصة بك تيار السفاح)
- تحويل التيار إلى انخفاض معدل البت ، إذا كنت يمكن أن يتسامح مع خسارة في الجودة
نصائح أخرى
لماذا لا فقط تحميل البرنامج مع الطاعن تيار مثل Ripshout أو شيء من هذا؟
وللإجابة على سؤالي الخاص، وهنا السيناريو الذي يبدأ العمل كمهمة كرون كل 30 دقيقة. انها مقالب الدفق الواردة في قطع مسافة 5 دقائق (أو مجموعة من FILE _ ثانية) إلى دليل معين. تتم مزامنة الحدود كتلة لعقارب الساعة، وأنها لا تبدأ الكتابة حتى نهاية م> من قطعة الزمنية الحالية، بحيث يمكن للتخصيص مواصفات المستعملين تشغيل تتداخل دون مضاعفة البيانات أو ترك الثغرات. تتم تسمية الملفات كما (وقت العصر عدد٪ الثواني في 24 ساعة) .str.
وأنا لم ارتكب لاعب حتى الآن، ولكن خطة لتعيين الدليل الإخراج إلى مكان ما على شبكة الانترنت يمكن الوصول إليها، وكتابة السيناريو ليتم تشغيلها محليا يستخدم نفس رمز حساب الطابع الزمني كما هنا لبالتسلسل وصول (الطابع الزمني قبل 12 ساعة) .str، تك لهم معا مرة أخرى، ثم قم بإعداد كخادم شوتكاست محليا. بعد ذلك فقط يمكن أن نشير مشغل الموسيقى الخاص بي في HTTP: // المضيف المحلي: ميناء وسهولة الحصول عليها
تحرير: نسخة جديدة مع مهلة وأفضل حالة خطأ التدقيق، بالإضافة إلى ملف السجل لطيفة. هذا قيد التشغيل حاليا خالية من عقبة في بلدي (رخيصة) الإستضافة المشتركة، مع أية مشاكل. م>
#!/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()