インターネットラジオの音楽を保存する問題を解決する



こんにちは、%ユーザー名%!

友人の会社とインターネットラジオを作ることに決めたが、判明したように、VPSの割り当てられたスペースは音楽の大きなアーカイブには十分ではなく、さらにギガバイトの追加購入は本当の強盗です。



優れたableevの記事「ファイルシステムとしての Yandex.Disk に突然出会ったとき、私は長い間解決策を探していました。 Yandexディスクに音楽を保存してみませんか? ここではライセンスと著作権の問題を省略します-これはまったく異なる話ですが、技術的な部分に興味があります。 判明したように、IceCastは常にYandexディスクから音楽を読み込むことができないため、放送が途切れたり中断したりします。 この問題は私を捕らえ、解決策を見つけました-現在ラジオで何が再生されているかを判別し、次のトラックをプリロードし、失われたトラックをサーバーから削除します。 これはトラフィックを生成しますが、私は同意しますが、現時点では、トラフィックが無制限のVPSは満杯で、ディスクスペースは無制限です。



私は少なくとも言語からC#を話すので、モノラルに頼り、Python、PHP、bashでいくつかの補助スクリプトを書く必要がありました。



スタジオのヘルパースクリプト!



id3.pyは、引数を指定して呼び出されると、タグを取得してテキストファイルに書き込むトラックを受け取ります。

id3.py
#!/usr/bin/env python class Unbuffered(object): def __init__(self, stream): self.stream = stream def write(self, data): self.stream.write(data) self.stream.flush() def __getattr__(self, attr): return getattr(self.stream, attr) import eyeD3 import sys import argparse def createParser (): parser = argparse.ArgumentParser() parser.add_argument('-f', '--file') return parser if __name__ == '__main__': parser = createParser() namespace = parser.parse_args(sys.argv[1:]) tag = eyeD3.Tag() tag.link(namespace.file) sys.stdout = Unbuffered(sys.stdout) s = tag.getArtist()+" - "+tag.getTitle() f = open('tag.txt','w') f.write(s) f.close()
      
      









getCurrent.phpは、現在のトラックに関する情報でIceCastページを解析し、再生中のトラックの名前を提供します。

getCurrent.php
 <?php error_reporting(0); header("Content-Type: text/html; charset=UTF-8"); $file_name="http://localhost:8000/status.xsl?mount=/stream"; $r=fopen($file_name,'r'); $text=fread($r,10000); fclose($r); $mas=explode('<tr>', $text); $name = explode(':', $mas[3]); $q = explode ('</td>',$name[1]); $q2 = explode ('<td class="streamdata">',$q[1]); $rj = $q2[1]; if($rj == "0" or $rj == ""){ echo " Nonstop"; }else { $fl = file_get_contents('http://localhost:8000/status.xsl?mount=/stream'); function antara($string, $start, $end){ $string = " ".$string; $ini = strpos($string,$start); if ($ini == 0) return ""; $ini += strlen($start); $len = strpos($string,$end,$ini) - $ini; return substr($string,$ini,$len); } $stream = antara($fl,"<td>Stream Title:</td>\n<td class=\"streamdata\">","</td>"); $description = antara($fl, "<td>Stream Description:</td>\n<td class=\"streamdata\">", "</td>"); $listeners = antara($fl, "<td>Current Listeners:</td>\n<td class=\"streamdata\">", "</td>"); $max = antara($fl, "<td>Peak Listeners:</td>\n<td class=\"streamdata\">", "</td>"); $song = antara($fl, "<td>Current Song:</td>\n<td class=\"streamdata\">", "</td>"); echo $song; ?>
      
      









小さなbashスクリプトisOnline.shは、ラジオスクリプトが実行されているかどうかを確認し、ステータス情報をテキストファイルに書き込みます。

isOnline.sh
 #!/bin/bash rm isOnline.txt ps ax | grep -v grep | grep radio.sh > isOnline.txt
      
      









liquidsoap radio.shラジオのスクリプトはラジオそのものです。

radio.sh
 #!/usr/bin/liquidsoap #          #      out = output.icecast( #   icecast host = "127.0.0.1", #   port = 8000, #  user = "source", #   password = "password", #  name = "Radio Name", #  genre = "Various", #    url = "http://www.host.local" #  encoding = "UTF-8" ) #  telnet- #set("server.telnet.bind_addr","127.0.0.1") #set("server.telnet",true) # _____________________________________ #     . #    ,       ,       ,       .   ,   . #      #wd = "/home/admin/radio" #      #pl = "#{wd}/collection" #   #tech = "#{wd}/technical" #  set("log.file.append",true) set("log.file",true) set("log.file.path","/var/data/liquidsoap.log") #     set("log.level", 3) #   #set("buffering.kind","disk_manyfiles") #set("decoding.buffer_length",30.) #set("buffering.path","/tmp/radio") #     #promo_dir = "#{pl}/promo" #    #progr_dir = "#{pl}/programs" #     #ef = "#{pl}/efir" #    #ni = "#{ef}/night" #    mus_ni_dir = "loc.playlist.txt" #    jin_ni_dir = "/mnt/username.yadisk/RT/jingles" #promo promo_dir = "/mnt/username.yadisk/RT/promo" mus_ni = playlist (reload = 86400, "#{mus_ni_dir}", mode = "normal") jin_ni = playlist (reload = 86400, "#{jin_ni_dir}", mode = "normal") promo = playlist (reload = 86400, "#{promo_dir}") ni = rotate (weights = [1, 10, 1, 5], [jin_ni, mus_ni, promo, mus_ni]) radio = switch (track_sensitive = true, [ #({ (2w16h10m - 2w16h20m) or (3w14h - 3w14h5m) or (4w16h - 4w16h5m)}, spekt), ({ (3w23h - 3w23h5m) or (4w10h - 4w10h5m)}, pozdr), ({ (2w18h - 2w18h5m) or #(3w18h - 3w18h5m)}, xmas_trad), ({ (6w14h - 6w14h10m) or (6w18h - 6w18h10m)}, prog1), ({ (6w0h - 7w18h)}, xmas_mus_prog), ({ 1w0h - 7w23h59m }, ni) ]) radio = mksafe(radio) radio = crossfade(start_next=2., fade_out=2., fade_in=2., radio) out( %mp3(bitrate = 128, id3v2 = true), description = "Radio Name 128kbps", mount = "stream", mksafe(radio) )
      
      









プレイリストジェネレータgenerator.shは、マウントされたドライブにファイルのリストを作成し、リストをシャッフルし、テキストファイルに書き込みます。 このスクリプトは、多くのディスクを追加し、1つのプレイリストですべてを収集できるという点で注目に値します。

generator.sh
 #!/bin/sh find "/mnt/username.yadisk/RT/music" -name '*.mp3' -print > "disk.playlist.txt" shuf -n 500 "disk.playlist.txt" -o "disk.playlist.txt" sed 's/\/mnt\/username.yadisk\/RT\/music/\/home\/admin\/rt\/tmp/g' disk.playlist.txt > loc.playlist.txt
      
      









今では、ラジオスクリプトが落ちたかどうかを監視し、クラッシュの場合に実行し、プレイリストを監視し、トラックをロードおよび削除する制御スクリプトを作成します。

radio_control.cs
 using System; using System.Collections.Generic; using System.IO; using System.Collections; using System.Diagnostics; namespace radio_control { class song { string filename; string tagname; string prepared; System.Diagnostics.Process getTag; public song() { getTag = new System.Diagnostics.Process(); getTag.EnableRaisingEvents = false; getTag.StartInfo.FileName = "./id3.py"; } public string FileName { get { return filename; } set { filename = value; } } public string Tag { get { return tagname; } set { tagname = value; } } public string Prepared { get { return prepared; } set { prepared = value; } } /// <summary> ///     ,        Prepared /// </summary> /// <param name="tmpDir"></param> public void Prepare(string tmpDir) { File.Copy(FileName, tmpDir+Path.GetFileName(FileName), true); Prepared = tmpDir + Path.GetFileName(FileName); Tag = _getTag().Replace(Environment.NewLine,""); } //     public void Destroy() { File.Delete(Prepared); } //    string _getTag() { getTag.StartInfo.Arguments = "-f " + this.Prepared; getTag.Start(); getTag.WaitForExit(); StreamReader str = new StreamReader("tag.txt"); string tag = str.ReadToEnd(); str.Close(); return tag; } } class Program { static void Main(string[] args) { //,       int count = 0; string pl_file = "/home/admin/rt/disk.playlist.txt"; //  string tmpDir = "/home/admin/rt/tmp/"; //     string newplTime = "23:30"; //    List<song> songs = new List<song>(); //      icecast System.Diagnostics.Process getCurrent = new System.Diagnostics.Process(); getCurrent.EnableRaisingEvents = false; getCurrent.StartInfo.RedirectStandardOutput = true; getCurrent.StartInfo.FileName = "/usr/bin/php"; getCurrent.StartInfo.UseShellExecute = false; getCurrent.StartInfo.Arguments = "getCurrent.php"; // ,     System.Diagnostics.Process isRadio = new System.Diagnostics.Process(); isRadio.EnableRaisingEvents = false; getCurrent.StartInfo.UseShellExecute = false; getCurrent.StartInfo.RedirectStandardOutput = true; isRadio.StartInfo.FileName = "isOnline.sh"; //   System.Diagnostics.Process radio = new System.Diagnostics.Process(); radio.EnableRaisingEvents = false; getCurrent.StartInfo.UseShellExecute = false; getCurrent.StartInfo.RedirectStandardOutput = true; radio.StartInfo.FileName = "screen"; radio.StartInfo.Arguments = "-dmS radio liquidsoap --verbose radiotera.sh"; //   radio System.Diagnostics.Process killRadio = new System.Diagnostics.Process(); killRadio.EnableRaisingEvents = false; getCurrent.StartInfo.UseShellExecute = false; getCurrent.StartInfo.RedirectStandardOutput = true; killRadio.StartInfo.FileName = "screen"; killRadio.StartInfo.Arguments = "-X -S radio quit"; //    Process genPl = new Process(); genPl.EnableRaisingEvents = false; genPl.StartInfo.UseShellExecute = false; genPl.StartInfo.FileName = "generator.sh"; //   ,  -    first in - first out Queue queue = new Queue(3); //     string[] playlist = (System.IO.File.ReadAllLines(pl_file)); log("Loading playlist"); // ID3       song sng; foreach (string value in playlist) { sng = new song(); sng.FileName = value; songs.Add(sng); } log("Playlist loaded.", ConsoleColor.Green); //  3     songs[0].Prepare(tmpDir); count++; songs[1].Prepare(tmpDir); count++; songs[2].Prepare(tmpDir); count++; //    queue.Enqueue(songs[0]); queue.Enqueue(songs[1]); queue.Enqueue(songs[2]); log("First 3 tracks prepared:\n"+songs[0].Tag+"\n"+songs[1].Tag+"\n"+songs[2].Tag, ConsoleColor.Green); //   song tmp = new song(); StreamReader rdr; string online = ""; while (true) { log("Check time to change playlist"); //    if (DateTime.Now.ToString("HH:mm") == newplTime) { log("Its time to change playlist!", ConsoleColor.Red); genPl.Start(); //  genPl.WaitForExit(); log("Playlist generated", ConsoleColor.Green); log("Loading playlist"); playlist = (System.IO.File.ReadAllLines(pl_file)); songs.Clear(); foreach (string value in playlist) //  { sng = new song(); sng.FileName = value; songs.Add(sng); } log("Playlist loaded", ConsoleColor.Green); } log("Check the availability of radio"); isRadio.Start(); isRadio.WaitForExit(); rdr = new StreamReader("isOnline.txt"); online=rdr.ReadToEnd(); rdr.Close(); //  ? if (online == "") { log("Radio is offline!\nClearing screen", ConsoleColor.Red); killRadio.Start(); killRadio.WaitForExit(); log("Starting the radio"); radio.Start(); log("Waiting for 10 seconds"); System.Threading.Thread.Sleep(10000); } log("Get current song"); //   getCurrent.Start(); getCurrent.WaitForExit(); string curr = getCurrent.StandardOutput.ReadToEnd(); if (curr == "") continue; //    tmp = new song(); tmp = (song)queue.Peek(); //,      log("Now playing: " + curr, ConsoleColor.Cyan); log("Checking queue tag: "+tmp.Tag, ConsoleColor.Cyan); if (tmp.Tag != curr) { //   ,    —   . //           if ((curr == "Radio TERA - Radio TERA") || (curr=="Unknown") || (curr=="NonstopS")) { log("Now playing radio jingle, move on to the next iteration"); continue; } log("The current track is different from the queue!!!\nMove the queue", ConsoleColor.Red); //     ,      queue.Dequeue(); log("Dequene track with tag "+tmp.Tag); //     log("Remove the track ended"); tmp.Destroy(); //      log("Prepare next track"); songs[count].Prepare(tmpDir); //    log("Adding it to queue "+songs[count].Tag); queue.Enqueue(songs[count]); //  count++; log("Count now: " + count.ToString()); //    ,         if (count > songs.Count - 1) { count = 0; } } // 30  System.Threading.Thread.Sleep(30000); } } static void log(string str) { Console.WriteLine(str); } static void log(string str, ConsoleColor frcolor) { Console.ForegroundColor = frcolor; Console.WriteLine(str); Console.ForegroundColor=ConsoleColor.White; } } }
      
      









私は牛のコードをおizeびします。これらはすべて同じスクリプト内で記述できますが、問題をより迅速に解決し、異なるサブタスク用に所有していたツールを使用したいと考えました。



通常の操作では、次のものが必要です。





システムはradio_control.csを介して起動します。 それだけです その後、彼はラジオを自分で起動し、プレイリストを生成し、音楽をダウンロードすると同時に、彼がしていることを端末に書き込みます。



残念ながら、私たちはラジオを閉じましたが、私の仕事が無駄にならないようにしたかったのです。



All Articles