如何提供随机元素,以便每个用户以相同的顺序获得相同的随机元素?

How to serve a random element so that each user gets the same random element in the same order?

我正在建立一个在线广播电台。我创建了一个 XML 数据库来存储 播放列表 的歌曲信息,以便用户可以收到由播放列表 (XML) 定义的特定音频文件预定义的顺序;从而产生 show 的错觉。这些节目的长度通常为一个小时。我想做的是在节目结束后随机生成歌曲信息,从我的整个数据库中创建一个无限的随机播放列表。但是需要向所有用户提供一首随机歌曲,以便他们每个人都能获得相同的体验(同一首歌曲)。说明我的节目是如何实时提供的似乎也很重要,因为这决定了我的 随机生成器 应该如何工作。为了节省时间和 space,我将省略这些功能的某些功能,因为您可能会变得相当冗长。如果您希望看到这些省略的功能,我可以根据要求提交。我最初想创建这个 随机生成器 是使用 SSE (服务器发送的事件)但是,也许有更简单的方法。

我有一个 Javascript 文档,它使用 AJAX 查询数据库(播放列表):

load_prs(track_data_complete , "playlist.xml") ;

track_data_complete() 收到响应并使用当前歌曲信息更新 音频播放器 ,然后再次 AJAX 调用 timestamp.php

var current_play = 0 ; // current_play is global to indicate current song element in the playlist XML array
var track_length ; // Store current track length in seconds
var track_obj ; // object data for current song
var showtime ; // the shows beginning unix time
var timestamp ; // current unix time

function track_data_complete( XML )
{
var th = XML.children[current_play] ;
var band = get_val(th , "band") ; // get_val parses the XML data
var album = get_val(th , "album") ;
var title = get_val(th , "title") ;
var genre = get_val(th , "genre") ;
track_length = get_val(th , "length") ;
var tid = th.getAttribute("id") ;
var tsrc = "songs/" + tid + ".mp3" ;
track_obj = new tobj(band , album , title , genre , length , tsrc) ; // tobj creates a new object to store the data

showtime = Number(XML.getAttribute("showtime")) ;
load_prs(load_track , "timestamp.php?time=0") ;
}

timestamp.php

<?php echo ( time() + $_REQUEST['time'] . "" ) ; ?>

load_track() 使用 timestamp.php 返回的 Unix 时间戳实时播放歌曲,然后使用歌曲信息更新播放器:

function load_track( resp )
{
timestamp = Number(resp) ;
track_src.src = track_obj.tsrc ; // track_src is the audio element source
player_title.innerHTML = track_obj.band + " - " + track_obj.title ;
player_album.innerHTML = "Album: " + track_obj.album ;
track_audio.onended = function() { next_track() ; } ; // track_audio is the HTML audio element
track_audio.load() ;
begin_play() ;
}

begin_play() 使用数学计算实时时间来决定何时开始播放音频。这模拟了实时音频播放。如果时间超过第一首歌曲的长度则跳到下一首歌曲,直到当前时间大于 showtime:

function begin_play()
{
swap("stop_track") ;
var time = timestamp - showtime ;
if ( time < track_length ) { track_audio.currentTime = time ; }
else { return next_track() ; }
track_audio.play() ;
}

next_track() 递增 current_play 并将 showtime 和当前 track_length 相加,然后再次调用 track_list_complete() 并重新开始此过程。

playlist.xml

<?xml version="1.0" encoding="UTF-8"?>
<playlist auto="no" showtime="1526448420">
  <track id="funeral_doom_003">
    <genre>Funeral Doom</genre>
    <band>Depressed Mode</band>
    <album>Ghosts of Devotion</album>
    <title>Words of Silence</title>
    <length>3016</length>
  </track>
  <track id="funeral_doom_001">
    <genre>Funeral Doom</genre>
    <band>Evoken</band>
    <album>A Caress of the Void</album>
    <title>Descend the Lifeless Womb</title>
    <length>4270</length>
  </track>
</playlist>

注意:我的整个数据库都在 XML 文件中。每个文件都是一种音乐流派。因为我有三个流派,所以有三个 XML 个文件。播放列表文件是单独的,因为它使我能够创建节目。播放列表文件和流派文件在结构上非常相似,播放列表列出了给定歌曲的大部分相同数据。乍一看,您认为只是从流派数据库中随机获取一首歌曲,但是,这可能会为每个用户生成不同的歌曲。同样地,从播放列表中随机抓取歌曲会遗漏我数据库的其余部分。

使用客户端 PRNG 以随机顺序循环播放列表,并为每个客户端提供相同的种子,因此 they all get the same infinite of random numbers。您可以实现自己的更简单的 PRNG,例如线性同余生成器,它在有任何重复之前生成每个数字一次,或者您可以只使用 PRNG 来提供随机洗牌算法。

您可以将种子值(例如 42 硬编码到 .js 中,或者将其放入 php 生成的 HTML 的 <script> 部分].或者如您所说,如果客户无论如何都需要下载 XML 文件,请将 PRNG 参数放在那里,以便您轻松编辑播放列表文件以获得不同的顺序。

您甚至可以通过 为客户端提供 PRNG 参数以生成 0..N 范围内的随机数,并将这些数字映射到歌曲服务器端。