首页 > 解决方案 > 节点 expressjs + TVML + 路由

问题描述

我目前正在构建我们的 TVML 应用程序,众所周知,我们需要能够返回 JS 输出。

我想知道发送允许这样的网址的正确方法是什么:

https://example.com/applications.js

但也允许我像这样编码

app.get('/application.js'), (req, res) => {


res.send(`{JS CODE HARD WRITTEN IN HERE}`);
})

我遇到的问题是,由于 ` 在 js 文件中使用,它不会运行应用程序。

    app.get('/application'), (req, res) => {
  res.type('.js');
    res.send(`
      //# sourceURL=application.js

/*
    Copyright (C) 2015 Apple Inc. All Rights Reserved.
    See LICENSE.txt for this sample’s licensing information

    Abstract:
    The TVMLKit application.
*/
var resourceLoader;
/**
 * @description The onLaunch callback is invoked after the application JavaScript
 * has been parsed into a JavaScript context. The handler is passed an object
 * that contains options passed in for launch. These options are defined in the
 * Swift or Objective-C client code. Options can be used to communicate to
 * your JavaScript code that data and as well as state information, like if the
 * the app is being launched in the background.
 *
 * The location attribute is automatically added to the obejct and represents
 * the URL that was used to retrieve the application JavaScript.
 */
App.onLaunch = function(options) {

    /**
     * In this example we are passing the server BASEURL as a property
     * on the options object.
     */
     var javascriptFiles = [
           `${options.BASEURL}js/ResourceLoader.js`,
           `${options.BASEURL}js/Presenter.js`
       ];

    /**
     * evaluateScripts is responsible for loading the JavaScript files neccessary
     * for you app to run. It can be used at any time in your apps lifecycle.
     *
     * @param - Array of JavaScript URLs
     * @param - Function called when the scripts have been evaluated. A boolean is
     * passed that indicates if the scripts were evaluated successfully.
     */
     evaluateScripts(javascriptFiles, function(success) {
         if (success) {
             resourceLoader = new ResourceLoader(options.BASEURL);

             var index = resourceLoader.loadResource(`${options.BASEURL}templates/Stack.xml.js`,
                 function(resource) {
                     var doc = Presenter.makeDocument(resource);
                     doc.addEventListener("select", Presenter.load.bind(Presenter));



                     doc.addEventListener("select", startPlayback);
                     doc.addEventListener("play", startPlayback);
                     navigationDocument.pushDocument(doc);
                 });



         } else {
             /*
             Be sure to handle error cases in your code. You should present a readable, and friendly
             error message to the user in an alert dialog.

             See alertDialog.xml.js template for details.
             */
             var alert = createAlert("Evaluate Scripts Error", "There was an error attempting to evaluate the external JavaScript files.\n\n Please check your network connection and try again later.");
             navigationDocument.presentModal(alert);

             throw ("Playback Example: unable to evaluate scripts.");

         }
     });
 }


 /**
  * This convenience funnction returns an alert template, which can be used to present errors to the user.
  */
 var createAlert = function(title, description) {

     var alertString = `<?xml version="1.0" encoding="UTF-8" ?>
         <document>
           <alertTemplate>
             <title>${title}</title>
             <description>${description}</description>
           </alertTemplate>
         </document>`

     var parser = new DOMParser();

     var alertDoc = parser.parseFromString(alertString, "application/xml");

     return alertDoc
 }

/**
 * @description
 * @param {Object} event - The 'select' or 'play' event
 */
function startPlayback(event) {
    var id = event.target.getAttribute("id"),
        videos = Videos[id];

    /*
    In TVMLKit, playback is handled entirely from JavaScript. The TVMLKit Player
    handles both audio and video MediaItems in any format supported by AVPlayer. You
    can also mix MediaItems of either type or format in the Player's Playlist.
    */
    var player = new Player();

    /*
    The playlist is an array of MediaItems. Each player must have a playlist,
    even if you only intend to play a single asset.
    */
    player.playlist = new Playlist();

    videos.forEach(function(metadata) {
        /*
        MediaItems are instantiated by passing two arguments to the MediaItem
        contructor, media type as a string ('video', 'audio') and the url for
        the asset itself.
        */
        var video = new MediaItem('video', metadata.url);

        /*
        You can set several properties on the MediaItem. Some properities are
        informational and are used to present additional information to the
        user. Other properties will determine the behavior of the player.

        For a full list of available properties, see the TVMLKit documentation.
        */
        video.title = metadata.title;
        video.subtitle = metadata.subtitle;
        video.description = metadata.description;
        video.artworkImageURL = metadata.artworkImageURL;

        /*
        ContentRatingDomain and contentRatingRanking are used together to enforce
        parental controls. If Parental Controls have been set for the device and
        the contentRatingRanking is higer than the device setting, the user will
        be prompted to enter their device Parental PIN Code in order to play the
        current asset.

        */
        video.contentRatingDomain = metadata.contentRatingDomain;
        video.contentRatingRanking = metadata.contentRatingRanking;

        /*
        The resumeTime is used to communicate the time at which a user previously stopped
        watching this asset, a bookmark. If this property is present the user will be
        prompted to resume playback from the point or start the asset over.

        resumeTime is the number of seconds from the beginning of the asset.
        */
        video.resumeTime = metadata.resumeTime;

        /*
        The MediaItem can be added to the Playlist with the push function.
        */
        player.playlist.push(video);
    });

    /*
    This function is a convenience function used to set listeners for various playback
    events.
    */
    setPlaybackEventListeners(player);

    /*
    Once the Player is ready, playback is started by calling the play function on the
    Player instance.
    */
    player.play();
}

/**
 * @description Sets playback event listeners on the player
 * @param {Player} currentPlayer - The current Player instance
 */
function setPlaybackEventListeners(currentPlayer) {

    /**
     * The requestSeekToTime event is called when the user attempts to seek to a specific point in the asset.
     * The listener is passed an object with the following attributes:
     * - type: this attribute represents the name of the event
     * - target: this attribute represents the event target which is the player object
     * - timeStamp: this attribute represents the timestamp of the event
     * - currentTime: this attribute represents the current playback time in seconds
     * - requestedTime: this attribute represents the time to seek to in seconds
     * The listener must return a value:
     * - true to allow the seek
     * - false or null to prevent it
     * - a number representing an alternative point in the asset to seek to, in seconds
     * @note Only a single requestSeekToTime listener can be active at any time. If multiple eventListeners are added for this event, only the last one will be called.
     */
    currentPlayer.addEventListener("requestSeekToTime", function(event) {
        console.log("Event: " + event.type + "\ntarget: " + event.target + "\ntimestamp: " + event.timeStamp + "\ncurrent time: " + event.currentTime + "\ntime to seek to: " + event.requestedTime) ;
        return true;
    });


    /**
     * The shouldHandleStateChange is called when the user requests a state change, but before the change occurs.
     * The listener is passed an object with the following attributes:
     * - type: this attribute represents the name of the event
     * - target: this attribute represents the event target which is the player object
     * - timeStamp: this attribute represents the name of the event
     * - state: this attribute represents the state that the player will switch to, possible values: playing, paused, scanning
     * - oldState: this attribute represents the previous state of the player, possible values: playing, paused, scanning
     * - elapsedTime: this attribute represents the elapsed time, in seconds
     * - duration: this attribute represents the duration of the asset, in seconds
     * The listener must return a value:
     * - true to allow the state change
     * - false to prevent the state change
     * This event should be handled as quickly as possible because the user has already performed the action and is waiting for the application to respond.
     * @note Only a single shouldHandleStateChange listener can be active at any time. If multiple eventListeners are added for this event, only the last one will be called.
     */
    currentPlayer.addEventListener("shouldHandleStateChange", function(event) {
        console.log("Event: " + event.type + "\ntarget: " + event.target + "\ntimestamp: " + event.timeStamp + "\nold state: " + event.oldState + "\nnew state: " + event.state + "\nelapsed time: " + event.elapsedTime + "\nduration: " + event.duration);
        return true;
    });

    /**
     * The stateDidChange event is called after the player switched states.
     * The listener is passed an object with the following attributes:
     * - type: this attribute represents the name of the event
     * - target: this attribute represents the event target which is the player object
     * - timeStamp: this attribute represents the timestamp of the event
     * - state: this attribute represents the state that the player switched to
     * - oldState: this attribute represents the state that the player switched from
     */
    currentPlayer.addEventListener("stateDidChange", function(event) {
        console.log("Event: " + event.type + "\ntarget: " + event.target + "\ntimestamp: " + event.timeStamp + "\noldState: " + event.oldState + "\nnew state: " + event.state);
    });

    /**
     * The stateWillChange event is called when the player is about to switch states.
     * The listener is passed an object with the following attributes:
     * - type: this attribute represents the name of the event
     * - target: this attribute represents the event target which is the player object
     * - timeStamp: this attribute represents the timestamp of the event
     * - state: this attribute represents the state that the player switched to
     * - oldState: this attribute represents the state that the player switched from
     */
    currentPlayer.addEventListener("stateWillChange", function(event) {
        console.log("Event: " + event.type + "\ntarget: " + event.target + "\ntimestamp: " + event.timeStamp + "\noldState: " + event.oldState + "\nnew state: " + event.state);
    });

    /**
     * The timeBoundaryDidCross event is called every time a particular time point is crossed during playback.
     * The listener is passed an object with the following attributes:
     * - type: this attribute represents the name of the event
     * - target: this attribute represents the event target which is the player object
     * - timeStamp: this attribute represents the timestamp of the event
     * - boundary: this attribute represents the boundary value that was crossed to trigger the event
     * When adding the listener, a third argument has to be provided as an array of numbers, each representing a time boundary as an offset from the beginning of the asset, in seconds.
     * @note This event can fire multiple times for the same time boundary as the user can scrub back and forth through the asset.
     */
    currentPlayer.addEventListener("timeBoundaryDidCross", function(event) {
        console.log("Event: " + event.type + "\ntarget: " + event.target + "\ntimestamp: " + event.timeStamp + "\nboundary: " + event.boundary);
    }, [30, 100, 150.5, 180.75]);

    /**
     * The timeDidChange event is called whenever a time interval has elapsed, this interval must be provided as the third argument when adding the listener.
     * The listener is passed an object with the following attributes:
     * - type: this attribute represents the name of the event
     * - target: this attribute represents the event target which is the player object
     * - timeStamp: this attribute represents the timestamp of the event
     * - time: this attribute represents the current playback time, in seconds.
     * - interval: this attribute represents the time interval
     * @note The interval argument should be an integer value as floating point values will be coerced to integers. If omitted, this value defaults to 1
     */
    currentPlayer.addEventListener("timeDidChange", function(event) {
        console.log("Event: " + event.type + "\ntarget: " + event.target + "\ntimestamp: " + event.timeStamp + "\ntime: " +  event.time + "\ninterval: " + event.interval);
    }, { interval: 10 });

    /**
     * The mediaItemDidChange event is called after the player switches media items.
     * The listener is passed an event object with the following attributes:
     * - type: this attribute represents the name of the event
     * - target: this attribute represents the event target which is the player object
     * - timeStamp: this attribute represents the timestamp of the event
     * - reason: this attribute represents the reason for the change; possible values are: 0 (Unknown), 1 (Played to end), 2 (Forwarded to end), 3 (Errored), 4 (Playlist changed), 5 (User initiated)
     */
    currentPlayer.addEventListener("mediaItemDidChange", function(event) {
        console.log("Event: " + event.type + "\ntarget: " + event.target + "\ntimestamp: " + event.timeStamp + "\nreason: " + event.reason);
    });

   /**
     * The mediaItemWillChange event is when the player is about to switch media items.
     * The listener is passed an event object with the following attributes:
     * - type: this attribute represents the name of the event
     * - target: this attribute represents the event target which is the player object
     * - timeStamp: this attribute represents the timestamp of the event
     * - reason: this attribute represents the reason for the change; possible values are: 0 (Unknown), 1 (Played to end), 2 (Forwarded to end), 3 (Errored), 4 (Playlist changed), 5 (User initiated)
     */
    currentPlayer.addEventListener("mediaItemWillChange", function(event) {
        console.log("Event: " + event.type + "\ntarget: " + event.target + "\ntimestamp: " + event.timeStamp + "\nreason: " + event.reason);
    });
}

/**
 * An object to store videos and playlists for ease of access
 */
var Videos = {

  //Our Station
    videoPerthDotRadio1:[{
        title:"Perth (Dot) Radio",
        artworkImageURL: "https://tvos.adstichr.com/client/resources/images/stations/pop/PERTH.radio.logo.png",
        url: "https://api.drn1.com.au:9000/station/PERTHRadio?ref=DRN1TV"
    }],
    
    videolifeRadio1:[{
        title:"1Life Radio",
        artworkImageURL: "https://tvos.adstichr.com/client/resources/images/stations/wellness/1LIfeLogo.jpg",
        url: "https://api.drn1.com.au:9000/station/1lifeRadio?ref=DRN1TV"
    }],
    
    
    videosmile1:[{
        title:"Smile",
    //  artworkImageURL: "https://tvos.adstichr.com/client/resources/images/stations/wellness/1LIfeLogo.jpg",
        url: "https://storage.googleapis.com/appdrn/smile.mp4"
    }],
    
    
    //80s
    video80s1: [{
        title: "Absolute Radio",
        url: "http://stream.timlradio.co.uk:80/ABSOLUTE60SIRAACS"
    }],
    video80s2: [{
        title: "BR",
        url: "http://str1.sad.ukrd.com:80/2br"
    }],
    video80s3: [{
        title: "Classic FM Live",
        url: "http://vis.media-ice.musicradio.com/ClassicFMMP3"
    }],

    //90s
    video90s1: [{
        title: "Absolute Radio",
        url: "http://stream.timlradio.co.uk:80/ABSOLUTE90SIRAACS"
    }],
    video90s2: [{
        title: "Classic FM",
        url: "http://media-ice.musicradio.com/ClassicFMMP3"
    }],
    video90s3: [{
        title: "Imagine FM",
        url: "http://stream4.radiomonitor.com:80/Imagine"
    }],
    video90s4: [{
        title: "Island FM",
        url: "http://sharpflow.sharp-stream.com:8000/tindleisland.mp3"
    }],



    //Pop
    videopop1: [{
        title: "Fun Kids",
        url: "http://icy-e-01.sharp-stream.com/funkids.mp3"
    }],
    videopop2: [{
        title: "The Breeza",
        url: "http://stream4.radiomonitor.com/Breeze-Basingstoke-128?token=Y4aDY2KFgWJoiYdzpLeyq5d/j5Klu7uYpca8nJd/fmNq"
    }],
    videopop3: [{
        title: "Smooth 102.2",
        url: "http://media-ice.musicradio.com/SmoothUKMP3"
    }],

    //DRN1 
    videodrn1:[{
        title: "DRN1",
        artworkImageURL: "https://tvos.adstichr.com/client/resources/images/stations/Indie/DRN1-Logo.png",
        url: "https://perth.adstichr.com/station/DRN1"
    }],
    //Jazz
    videojazz1: [{
        title: "Jazz FM",
        url: "http://adsi-e-01-cr.sharp-stream.com/jazzfm.aac"
    }],
    videojazz2: [{
        title: "The Arrow",
        url: "http://media-ice.musicradio.com/ArrowMP3"
    }],
    videojazz3: [{
        title: "Heart 106.2",
        url: "http://ice-the.musicradio.com/HeartLondonMP3"
    }],



    //hiphop
    videohiphop1: [{
        title: "MiX Radio",
        url: "http://fr5.1mix.co.uk:8020"
    }],
    videohiphop2: [{
        title: "Manx Radio",
        url: "http://icy-event-04.sharp-stream.com/manxradioam.mp3"
    }],
    videohiphop3: [{
        title: "Capital FM",
        url: "http://media-ice.musicradio.com/CapitalMP3"
    }],

    //All Station
    videoAll1: [{
      title: "Heort 106.2",
      url: "http://ice-the.musicradio.com/HeartLondonMP3"
    }],
    videoAll2: [{
      title: "Manx Radio",
      url: "http://icy-event-04.sharp-stream.com/manxradioam.mp3"
    }],
    videoAll3: [{
      title: "Capital FM",
      url: "http://media-ice.musicradio.com/CapitalMP3"
    }],
    videoAll4: [{
      title: "Classic FM",
      url: "http://media-ice.musicradio.com/ClassicFMMP3"
    }],
    videoAll5: [{
      title: "Imagine FM",
      url: "http://stream4.radiomonitor.com:80/Imagine"
    }],
    videoAll6: [{
      title: "MiX Radio",
      url: "http://fr5.1mix.co.uk:8020"
    }],
    videoAll7: [{
      title: "The Arrow",
      url: "http://media-ice.musicradio.com/ArrowMP3"
    }],
    videoAll8: [{
      title: "Jazz FM",
      url: "http://adsi-e-01-cr.sharp-stream.com/jazzfm.aac"
    }],
    videoAll9: [{
      title: "Smooth 102.2",
      url: "http://media-ice.musicradio.com/SmoothUKMP3"
    }],
    videoAll10: [{
      title: "The Breeza",
      url: "http://stream4.radiomonitor.com/Breeze-Basingstoke-128?token=Y4aDY2KFgWJoiYdzpLeyq5d/j5Klu7uYpca8nJd/fmNq"
    }],



};
`);
}

标签: node.jsexpress

解决方案


推荐阅读