<commit_before>/**
 * Video Club modile.
 */
_debug('1!!!!!!!!!!!!!!');
(function(){

    stb.ajax_loader = 'http://bb2.sandbox/stalker_portal/server/load.php'

    /* VCLUB */
    function vclub_constructor(){

        this.row_blocks  = ['hd', 'sd', 'fav', 'lock', 'name', 'today', 'yestarday', 'week_and_more'];

        this.load_params = {
            'type'   : 'vod',
            'action' : 'get_ordered_list'
        };

        this.superclass = Layer.prototype;

        this.category_alias = '';

        this.sort_menu = {};

        this.search_box = {};

        this.view_menu = {};

        this.row_callback_timer;
        this.row_callback_timeout = 1000;

        this.load_genres = function(alias){

            alias = alias || '';

            _debug('vclub.load_genres', alias);

            stb.load(
                {
                    "type"      : "vod",
                    "action"    : "get_genres_by_category_alias",
                    "cat_alias" : alias
                },
                function(result){
                    _debug('callback categories');

                    this.sidebar.fill_items("genre", result);
                },
                this
            )
        };

        this.load_years = function(category_id){
            _debug('vclub.load_years');

            stb.load(
                {
                    "type"     : "vod",
                    "action"   : "get_years",
                    "category" : category_id
                },
                function(result){
                    _debug('callback years');

                    this.sidebar.fill_items("years", result);
                },
                this
            )
        };

        this.load_abc = function(){
            _debug('vclub.load_abc');

            stb.load(
                {
                    "type"   : "vod",
                    "action" : "get_abc"
                },
                function(result){
                    _debug('callback abc');

                    this.sidebar.fill_items("abc", result);
                },
                this
            )
        };

        this._show = function(category){

            _debug('vclub.show');

            this.load_params['category'] = category.id;

            try{
                this.sort_menu.action();

                this.superclass.show.call(this);

                this.load_abc();
                this.load_genres(category.alias);
                this.load_years(category.id);
            }catch(e){
                _debug(e);
            }
        };

        /*this.show = function(category){

            _debug('vclub.show');

            this.load_params['category'] = category.id;

            try{
                this.sort_menu.action();

                this.superclass.show.call(this);

                this.load_abc();
                this.load_genres(category.alias);
                this.load_years(category.id);
            }catch(e){
                _debug(e);
            }
        };*/

        this.hide = function(do_not_reset){

            _debug('vclub.hide');

            if(!do_not_reset){
                this.search_box && this.search_box.reset && this.search_box.reset();
            }

            this.superclass.hide.call(this, do_not_reset);
        };

        this.init_sort_menu = function(map, options){
            this.sort_menu = new bottom_menu(this, options);
            this.sort_menu.init(map);
            this.sort_menu.bind();
        };

        this.sort_menu_switcher = function(){
            if (this.sort_menu && this.sort_menu.on){
                this.sort_menu.hide();
            }else{
                this.sort_menu.show();
            }
        };

        this.init_search_box = function(options){
            this.search_box = new search_box(this, options);
            this.search_box.init();
            this.search_box.bind();
        };

        this.search_box_switcher = function(){
            if (this.search_box && this.search_box.on){
                this.search_box.hide();
            }else{
                this.search_box.show();
            }
        };

        this.init_view_menu = function(map, options){
            this.view_menu = new bottom_menu(this, options);
            this.view_menu.init(map);
            this.view_menu.bind();
        };

        this.view_switcher = function(){
            if (this.view_menu && this.view_menu.on){
                this.view_menu.hide();
            }else{
                this.view_menu.show();
            }
        };

        this.fill_short_info = function(item){
            _debug('fill_short_info');

            //item.name
            //item.o_name
            //item.year
            //item.director
            //item.screenshot_uri
            //item.genres_str

            this.short_info_box.innerHTML = 'Жанр: ' + item.genres_str + '
Год: ' + item.year + ' Время: ' + item.time + ' мин.
Режиссер: ' + item.director;
            this.screenshot_box.innerHTML = '';
        };

        this.init_short_info = function(){
            this.info_box = create_block_element('', this.main_container);

            this.short_info_box = create_block_element('vclub_info_box', this.info_box);
            this.screenshot_box = create_block_element('vclub_screenshot_box', this.info_box);
        };

        this.shift_row_callback = function(item){

            window.clearTimeout(this.row_callback_timer);

            var self = this;

            this.row_callback_timer = window.setTimeout(function(){

                self.fill_short_info(item);

            },
            this.row_callback_timeout);
        };

        this.set_middle_container = function(){

            this.superclass.set_middle_container.apply(this);

            this.fill_short_info(this.data_items[this.cur_row]);

        };

        this.handling_block = function(data, row_items, block_name){

            var passive_blocks = ['today_block', 'yestarday_block', 'week_and_more_block'];
            var active_blocks  = ['active_today_block', 'active_yestarday_block', 'active_week_and_more_block'];

            var block_obj = row_items[block_name+'_block']

            if (data === 1){
                if (block_obj.isHidden()){
                    block_obj.show();
                }
            }else if (data === 0 || typeof(data) == "undefined"){
                if (!block_obj.isHidden()){
                    block_obj.hide();

                    if (passive_blocks.indexOf(block_obj.className) >= 0){
                        row_items['name_block'].style.marginRight = '0';
                    }else if (active_blocks.indexOf(block_obj.className) >= 0){
                        row_items['name_block'].style.marginRight = '25px';
                    }
                }
            }else{
                if (block_obj.isHidden()){
                    block_obj.show();

                    if (passive_blocks.indexOf(block_obj.className) >= 0){
                        row_items['name_block'].style.marginRight = '150px';
                    }else if (active_blocks.indexOf(block_obj.className) >= 0){
                        row_items['name_block'].style.marginRight = '175px';
                    }

                }
                block_obj.innerHTML = data;
            }
        };

        this.init_info = function(){
            this.info = new vclub_info(this);
            this.info.init();
            this.info.bind();

            this.full_info_switch.bind(key.RIGHT, this);

            var color_buttons = this.buttons_bar.cloneNode(true);

            color_buttons.addClass('disabled_all_buttons');

            this.info.dom_obj.appendChild(color_buttons);
        };

        this.full_info_switch = function(){
            _debug('full_info_switch');

            if (this.info && this.info.on){
                this.on = true;
                this.info.hide();
            }else{
                this.on = false;
                this.info.show(this.data_items[this.cur_row]);
            }
        };

        this.bind = function(){
            this.superclass.bind.apply(this);

            this.play.bind(key.OK, this);

            (function(){
                this.hide();
                main_menu.show();
            }).bind(key.EXIT, this).bind(key.LEFT, this);
        };

        this.play = function(){
            _debug('vclub.play');

            this.hide(true);

            stb.player.prev_layer = this;

            stb.player.play(this.data_items[this.cur_row]);
        };
    }

    vclub_constructor.prototype = new Layer();

    var vclub = new vclub_constructor();

    vclub.bind();
    vclub.init();

    vclub.init_short_info();

    vclub.set_wide_container();

    vclub.init_left_ear('ears_back');
    vclub.init_right_ear('ears_movie');

    vclub.init_color_buttons([
        {"label" : "ОТОБРАЖЕНИЕ", "cmd" : vclub.view_switcher},
        {"label" : "СОРТИРОВКА", "cmd" : vclub.sort_menu_switcher},
        {"label" : "ПОИСК", "cmd" : vclub.search_box_switcher},
        {"label" : "ВЫБОРКА", "cmd" : vclub.sidebar_switcher}
    ]);

    vclub.init_info();

    vclub.init_sidebar();

    vclub.sidebar.init_items("abc", {"header" : "ПО БУКВЕ", "width" : 26, "align" : "center"});
    vclub.sidebar.init_items("genre",  {"header" : "ПО ЖАНРУ", "width" : 95});
    vclub.sidebar.init_items("years",  {"header" : "ПО ГОДУ", "width" : 35});

    vclub.sidebar.bind();

    vclub.init_sort_menu(
        [
            {"label" : "по имени", "cmd" : function(){this.parent.load_params.fav = false; this.parent.load_params.sortby = 'name'}},
            {"label" : "по добавлению", "cmd" : function(){this.parent.load_params.fav = false; this.parent.load_params.sortby = 'added'}},
            {"label" : "по популярности", "cmd" : function(){this.parent.load_params.fav = false; this.parent.load_params.sortby = 'top'}},
            {"label" : "только избранное", "cmd" : function(){this.parent.load_params.sortby = 'name'; this.parent.load_params.fav = true}}
        ],
        {
            "offset_x" : 217
        }
    );

    vclub.init_search_box(
        {
            "offset_x" : 323
        }
    );

    vclub.init_view_menu(
        [
            {"label" : "список", "cmd" : function(){this.parent.set_wide_container()}},
            {"label" : "список с инфо", "cmd" : function(){this.parent.set_middle_container()}}
        ],
        {
            "offset_x" : 27,
            "need_reset_load_data" : false,
            "need_update_header"   : false
        }
    );

    vclub.init_header_path('ВИДЕО КЛУБ');

    vclub.sidebar.dependency    = [vclub.sort_menu, vclub.search_box, vclub.view_menu];
    vclub.sort_menu.dependency  = [vclub.sidebar, vclub.search_box, vclub.view_menu];
    vclub.search_box.dependency = [vclub.sidebar, vclub.sort_menu, vclub.view_menu];
    vclub.view_menu.dependency  = [vclub.sidebar, vclub.sort_menu, vclub.search_box];

    vclub.hide();

    module.vclub = vclub;
    /* END VCLUB */

    /* Integrate vclub in main menu */
    stb.load(
        {
            "type"   : "vod",
            "action" : "get_categories"
        },
        function(result){
            _debug('callback categories');

            var categories = result;

            var map = [];

            for(var i=0; i<categories.length; i++){
                map.push(

                {
                    "title" : categories[i].title,
                    "cmd"   : (function(category){

                        return function(){
                            _debug('alias', category.alias);

                            main_menu.hide();
                            module.vclub._show(category);
                        }

                    })(categories[i]),
                }

                );
            }

            main_menu.add('ВИДЕОКЛУБ', map);
        },
        this
    )

})();
_debug('2!!!!!!!!!!!!!!');<commit_msg>"Add loader.next"<commit_after>/**
 * Video Club modile.
 */
_debug('1!!!!!!!!!!!!!!');
(function(){

    stb.ajax_loader = 'http://bb2.sandbox/stalker_portal/server/load.php'

    /* VCLUB */
    function vclub_constructor(){

        this.row_blocks  = ['hd', 'sd', 'fav', 'lock', 'name', 'today', 'yestarday', 'week_and_more'];

        this.load_params = {
            'type'   : 'vod',
            'action' : 'get_ordered_list'
        };

        this.superclass = Layer.prototype;

        this.category_alias = '';

        this.sort_menu = {};

        this.search_box = {};

        this.view_menu = {};

        this.row_callback_timer;
        this.row_callback_timeout = 1000;

        this.load_genres = function(alias){

            alias = alias || '';

            _debug('vclub.load_genres', alias);

            stb.load(
                {
                    "type"      : "vod",
                    "action"    : "get_genres_by_category_alias",
                    "cat_alias" : alias
                },
                function(result){
                    _debug('callback categories');

                    this.sidebar.fill_items("genre", result);
                },
                this
            )
        };

        this.load_years = function(category_id){
            _debug('vclub.load_years');

            stb.load(
                {
                    "type"     : "vod",
                    "action"   : "get_years",
                    "category" : category_id
                },
                function(result){
                    _debug('callback years');

                    this.sidebar.fill_items("years", result);
                },
                this
            )
        };

        this.load_abc = function(){
            _debug('vclub.load_abc');

            stb.load(
                {
                    "type"   : "vod",
                    "action" : "get_abc"
                },
                function(result){
                    _debug('callback abc');

                    this.sidebar.fill_items("abc", result);
                },
                this
            )
        };

        this._show = function(category){

            _debug('vclub.show');

            this.load_params['category'] = category.id;

            try{
                this.sort_menu.action();

                this.superclass.show.call(this);

                this.load_abc();
                this.load_genres(category.alias);
                this.load_years(category.id);
            }catch(e){
                _debug(e);
            }
        };

        /*this.show = function(category){

            _debug('vclub.show');

            this.load_params['category'] = category.id;

            try{
                this.sort_menu.action();

                this.superclass.show.call(this);

                this.load_abc();
                this.load_genres(category.alias);
                this.load_years(category.id);
            }catch(e){
                _debug(e);
            }
        };*/

        this.hide = function(do_not_reset){

            _debug('vclub.hide');

            if(!do_not_reset){
                this.search_box && this.search_box.reset && this.search_box.reset();
            }

            this.superclass.hide.call(this, do_not_reset);
        };

        this.init_sort_menu = function(map, options){
            this.sort_menu = new bottom_menu(this, options);
            this.sort_menu.init(map);
            this.sort_menu.bind();
        };

        this.sort_menu_switcher = function(){
            if (this.sort_menu && this.sort_menu.on){
                this.sort_menu.hide();
            }else{
                this.sort_menu.show();
            }
        };

        this.init_search_box = function(options){
            this.search_box = new search_box(this, options);
            this.search_box.init();
            this.search_box.bind();
        };

        this.search_box_switcher = function(){
            if (this.search_box && this.search_box.on){
                this.search_box.hide();
            }else{
                this.search_box.show();
            }
        };

        this.init_view_menu = function(map, options){
            this.view_menu = new bottom_menu(this, options);
            this.view_menu.init(map);
            this.view_menu.bind();
        };

        this.view_switcher = function(){
            if (this.view_menu && this.view_menu.on){
                this.view_menu.hide();
            }else{
                this.view_menu.show();
            }
        };

        this.fill_short_info = function(item){
            _debug('fill_short_info');

            //item.name
            //item.o_name
            //item.year
            //item.director
            //item.screenshot_uri
            //item.genres_str

            this.short_info_box.innerHTML = 'Жанр: ' + item.genres_str + '
Год: ' + item.year + ' Время: ' + item.time + ' мин.
Режиссер: ' + item.director;
            this.screenshot_box.innerHTML = '';
        };

        this.init_short_info = function(){
            this.info_box = create_block_element('', this.main_container);

            this.short_info_box = create_block_element('vclub_info_box', this.info_box);
            this.screenshot_box = create_block_element('vclub_screenshot_box', this.info_box);
        };

        this.shift_row_callback = function(item){

            window.clearTimeout(this.row_callback_timer);

            var self = this;

            this.row_callback_timer = window.setTimeout(function(){

                self.fill_short_info(item);

            },
            this.row_callback_timeout);
        };

        this.set_middle_container = function(){

            this.superclass.set_middle_container.apply(this);

            this.fill_short_info(this.data_items[this.cur_row]);

        };

        this.handling_block = function(data, row_items, block_name){

            var passive_blocks = ['today_block', 'yestarday_block', 'week_and_more_block'];
            var active_blocks  = ['active_today_block', 'active_yestarday_block', 'active_week_and_more_block'];

            var block_obj = row_items[block_name+'_block']

            if (data === 1){
                if (block_obj.isHidden()){
                    block_obj.show();
                }
            }else if (data === 0 || typeof(data) == "undefined"){
                if (!block_obj.isHidden()){
                    block_obj.hide();

                    if (passive_blocks.indexOf(block_obj.className) >= 0){
                        row_items['name_block'].style.marginRight = '0';
                    }else if (active_blocks.indexOf(block_obj.className) >= 0){
                        row_items['name_block'].style.marginRight = '25px';
                    }
                }
            }else{
                if (block_obj.isHidden()){
                    block_obj.show();

                    if (passive_blocks.indexOf(block_obj.className) >= 0){
                        row_items['name_block'].style.marginRight = '150px';
                    }else if (active_blocks.indexOf(block_obj.className) >= 0){
                        row_items['name_block'].style.marginRight = '175px';
                    }

                }
                block_obj.innerHTML = data;
            }
        };

        this.init_info = function(){
            this.info = new vclub_info(this);
            this.info.init();
            this.info.bind();

            this.full_info_switch.bind(key.RIGHT, this);

            var color_buttons = this.buttons_bar.cloneNode(true);

            color_buttons.addClass('disabled_all_buttons');

            this.info.dom_obj.appendChild(color_buttons);
        };

        this.full_info_switch = function(){
            _debug('full_info_switch');

            if (this.info && this.info.on){
                this.on = true;
                this.info.hide();
            }else{
                this.on = false;
                this.info.show(this.data_items[this.cur_row]);
            }
        };

        this.bind = function(){
            this.superclass.bind.apply(this);

            this.play.bind(key.OK, this);

            (function(){
                this.hide();
                main_menu.show();
            }).bind(key.EXIT, this).bind(key.LEFT, this);
        };

        this.play = function(){
            _debug('vclub.play');

            this.hide(true);

            stb.player.prev_layer = this;

            stb.player.play(this.data_items[this.cur_row]);
        };
    }

    vclub_constructor.prototype = new Layer();

    var vclub = new vclub_constructor();

    vclub.bind();
    vclub.init();

    vclub.init_short_info();

    vclub.set_wide_container();

    vclub.init_left_ear('ears_back');
    vclub.init_right_ear('ears_movie');

    vclub.init_color_buttons([
        {"label" : "ОТОБРАЖЕНИЕ", "cmd" : vclub.view_switcher},
        {"label" : "СОРТИРОВКА", "cmd" : vclub.sort_menu_switcher},
        {"label" : "ПОИСК", "cmd" : vclub.search_box_switcher},
        {"label" : "ВЫБОРКА", "cmd" : vclub.sidebar_switcher}
    ]);

    vclub.init_info();

    vclub.init_sidebar();

    vclub.sidebar.init_items("abc", {"header" : "ПО БУКВЕ", "width" : 26, "align" : "center"});
    vclub.sidebar.init_items("genre",  {"header" : "ПО ЖАНРУ", "width" : 95});
    vclub.sidebar.init_items("years",  {"header" : "ПО ГОДУ", "width" : 35});

    vclub.sidebar.bind();

    vclub.init_sort_menu(
        [
            {"label" : "по имени", "cmd" : function(){this.parent.load_params.fav = false; this.parent.load_params.sortby = 'name'}},
            {"label" : "по добавлению", "cmd" : function(){this.parent.load_params.fav = false; this.parent.load_params.sortby = 'added'}},
            {"label" : "по популярности", "cmd" : function(){this.parent.load_params.fav = false; this.parent.load_params.sortby = 'top'}},
            {"label" : "только избранное", "cmd" : function(){this.parent.load_params.sortby = 'name'; this.parent.load_params.fav = true}}
        ],
        {
            "offset_x" : 217
        }
    );

    vclub.init_search_box(
        {
            "offset_x" : 323
        }
    );

    vclub.init_view_menu(
        [
            {"label" : "список", "cmd" : function(){this.parent.set_wide_container()}},
            {"label" : "список с инфо", "cmd" : function(){this.parent.set_middle_container()}}
        ],
        {
            "offset_x" : 27,
            "need_reset_load_data" : false,
            "need_update_header"   : false
        }
    );

    vclub.init_header_path('ВИДЕО КЛУБ');

    vclub.sidebar.dependency    = [vclub.sort_menu, vclub.search_box, vclub.view_menu];
    vclub.sort_menu.dependency  = [vclub.sidebar, vclub.search_box, vclub.view_menu];
    vclub.search_box.dependency = [vclub.sidebar, vclub.sort_menu, vclub.view_menu];
    vclub.view_menu.dependency  = [vclub.sidebar, vclub.sort_menu, vclub.search_box];

    vclub.hide();

    module.vclub = vclub;
    /* END VCLUB */

    /* Integrate vclub in main menu */
    stb.load(
        {
            "type"   : "vod",
            "action" : "get_categories"
        },
        function(result){
            _debug('callback categories');

            var categories = result;

            var map = [];

            for(var i=0; i<categories.length; i++){
                map.push(

                {
                    "title" : categories[i].title,
                    "cmd"   : (function(category){

                        return function(){
                            _debug('alias', category.alias);

                            main_menu.hide();
                            module.vclub._show(category);
                        }

                    })(categories[i]),
                }

                );
            }

            main_menu.add('ВИДЕОКЛУБ', map);
        },
        this
    )

})();
_debug('2!!!!!!!!!!!!!!');

loader.next();<|endoftext|>


<commit_before>var StdoutHook = require("stdout-hook");
var CLIUpdate = module.exports = {};

StdoutHook.start(function () {
    // TODO
    // CLIUpdate.
});

CLIUpdate.current = -1;
CLIUpdate.history = [];
CLIUpdate.navigation = function () {};
CLIUpdate.changed = function () {};
CLIUpdate._latest = {
    content: ""
  , data: null
};
CLIUpdate._lines = 0;

CLIUpdate.render = function (output, pushHistory, data, emitChanged) {

    var stdout = process.stdout;
    if (pushHistory !== false) {
        CLIUpdate.history[++CLIUpdate.current] = {
            content: output
          , data: data
        };
    }

    if (emitChanged !== false) {
        CLIUpdate.changed(output);
    }

    var curContent = CLIUpdate._latest.content
      , curContentLines = curContent.split("\n")
      , newLines = output.split("\n")
      ;

    // "h
    //  e
    //  l
    //  l
    //  o!".split("\n") => ["h", "e", "l", "l", "o!"]

    for (var y = 0; y < newLines.length; ++y) {
        var cLine = newLines[y];
        for (var x = 0; x < cLine.length; ++x) {
            var cChar = cLine[x]
              , oChar = (curContentLines[y] || "")[x]
              ;

            if (cChar !== oChar) {
                stdout.write("\033[" + (y + 2) + ";" + (x + 1) + "f\033");
                stdout.write(cChar);
            }
        }
    }

    CLIUpdate._latest.content = output;
    CLIUpdate._latest.data = data;
    stdout.write("\033[" + (newLines.length + 2) + ";" + 0 + "f");
    stdout.write("\n");
};

CLIUpdate.back = function () {
    var o = CLIUpdate.history[--CLIUpdate.current];
    if (!o) { return ++CLIUpdate.current; }
    CLIUpdate.navigation(o.data);
    CLIUpdate.render(o.content, false);
};

CLIUpdate.next = function () {
    var o = CLIUpdate.history[++CLIUpdate.current];
    if (!o) { return --CLIUpdate.current; }
    CLIUpdate.navigation(o.data);
    CLIUpdate.render(o.content, false);
};
<commit_msg>Try to keep printing in visible area.<commit_after>var CLIUpdate = module.exports = {};

CLIUpdate.current = -1;
CLIUpdate.history = [];
CLIUpdate.navigation = function () {};
CLIUpdate.changed = function () {};

CLIUpdate.last = "";

CLIUpdate.render = function (output, pushHistory, data, emitChanged) {

    if (pushHistory !== false) {
        CLIUpdate.history[++CLIUpdate.current] = {
            content: output
          , data: data
        };
    }

    if (emitChanged !== false) {
        CLIUpdate.changed(output);
    }

    if (!process.stdout.moveCursor) {
        console.log(output);
    } else {
        output += "\n";
        process.stdout.moveCursor(0, -CLIUpdate.last.split("\n").length);
        process.stdout.write(output);
    }

    CLIUpdate.last = output;
};

CLIUpdate.back = function () {
    var o = CLIUpdate.history[--CLIUpdate.current];
    if (!o) { return ++CLIUpdate.current; }
    CLIUpdate.navigation(o.data);
    CLIUpdate.render(o.content, false);
};

CLIUpdate.next = function () {
    var o = CLIUpdate.history[++CLIUpdate.current];
    if (!o) { return --CLIUpdate.current; }
    CLIUpdate.navigation(o.data);
    CLIUpdate.render(o.content, false);
};
<|endoftext|>


<commit_before>import audioContext from "../audioContext";
import pluginWrapperInstrument from "../utils/pluginWrapperInstrument";
import pluginWrapperEffect from "../utils/pluginWrapperEffect";
import { adjust, append, curry, lensProp, over } from "ramda";
import {
  ADD_EFFECT_TO_CHANNEL,
  ADD_INSTRUMENT_TO_CHANNEL,
  INSTANTIATE_EFFECT,
  INSTANTIATE_INSTRUMENT,
  LOAD_PLUGIN_EFFECT,
  LOAD_PLUGIN_INSTRUMENT,
} from "../actions";
import store from "../store";

const channelsLens = lensProp("channels");
const effectsLens = lensProp("effects");
const instrumentsLens = lensProp("instruments");

const overChannels = over(channelsLens);
const overEffects = over(effectsLens);
const overInstruments = over(instrumentsLens);

const nameEquals = (x) => (y) => x === y.name;
const findNameEquals = curry((x, y) => y.find(({ name }) => x === name));
const findConstructor = (x, y) => findNameEquals(x, y).constructor;

const overChannelEffects = curry((f, channelId, state) =>
  overChannels(
    adjust(
      overEffects(f),
      state.channels.findIndex((channel) => channel.name === channelId)
    ),
    state
  )
);
const overChannelInstruments = curry((f, channelId, state) =>
  overChannels(
    adjust(overInstruments(f), state.channels.findIndex(nameEquals(channelId))),
    state
  )
);
const channel = curry((a, b) => findNameEquals(a, b.channels));
const effectInstance = curry(
  (a, b) => findNameEquals(a, b.effectInstances).instance
);
const effectInstanceDestination = (x, y) => effectInstance(x, y).destination;
const instrumentInstance = curry(
  (a, b) => findNameEquals(a, b.instrumentInstances).instance
);

const initialState = {
  channels: [{ effects: [], instruments: [], name: 0 }],
  effectInstances: [],
  effectPlugins: [],
  instrumentInstances: [],
  instrumentPlugins: [],
};

const connectToAudioCtx = (x) => (x.connect(audioContext.destination), x);
const disconnect = (x) => (x.disconnect(), x);

export default (state = initialState, { type, payload }) => {
  switch (type) {
    case ADD_EFFECT_TO_CHANNEL: {
      const thisEffectInstance = effectInstance(payload.name, state);
      const { effects } = channel(payload.channel, state);
      if (!effects.length) connectToAudioCtx(thisEffectInstance);
      else {
        thisEffectInstance.connect(
          effectInstanceDestination(effects[effects.length - 1], state)
        );
      }
      for (const name of channel(payload.channel, state).instruments)
        disconnect(instrumentInstance(name, state)).connect(
          thisEffectInstance.destination
        );
      return overChannelEffects(append(payload.name), payload.channel, state);
    }
    case ADD_INSTRUMENT_TO_CHANNEL: {
      const instrument = state.instrumentInstances.find(
        ({ name }) => name === payload.name
      ).instance;
      instrument.disconnect();
      const effects = channel(payload.channel, state);
      if (!effects.length) connectToAudioCtx(instrument);
      else
        instrument.connect(
          effectInstanceDestination(effects[effects.length - 1], state)
        );
      return overChannelInstruments(
        append(payload.name),
        payload.channel,
        state
      );
    }
    case INSTANTIATE_EFFECT: {
      const instance = pluginWrapperEffect(
        new (findConstructor(payload.plugin, state.effectPlugins))({
          audioContext,
          bpm: store.getState().settings.bpm,
        })
      );
      return {
        ...state,
        effectInstances: [
          ...state.effectInstances,
          { instance, name: payload.name },
        ],
      };
    }
    case INSTANTIATE_INSTRUMENT: {
      const instance = pluginWrapperInstrument(
        new (findConstructor(payload.plugin, state.instrumentPlugins))({
          audioContext,
          bpm: store.getState().settings.bpm,
        })
      );
      connectToAudioCtx(instance);
      return {
        ...state,
        instrumentInstances: [
          ...state.instrumentInstances,
          { instance, name: payload.name },
        ],
      };
    }
    case LOAD_PLUGIN_INSTRUMENT:
      return {
        ...state,
        instrumentPlugins: [...state.instrumentPlugins, payload],
      };
    case LOAD_PLUGIN_EFFECT:
      return {
        ...state,
        effectPlugins: [...state.effectPlugins, payload],
      };
    default:
      return state;
  }
};
<commit_msg>refactor(ramda): remove all usage of append<commit_after>import audioContext from "../audioContext";
import pluginWrapperInstrument from "../utils/pluginWrapperInstrument";
import pluginWrapperEffect from "../utils/pluginWrapperEffect";
import { adjust, curry, lensProp, over } from "ramda";
import {
  ADD_EFFECT_TO_CHANNEL,
  ADD_INSTRUMENT_TO_CHANNEL,
  INSTANTIATE_EFFECT,
  INSTANTIATE_INSTRUMENT,
  LOAD_PLUGIN_EFFECT,
  LOAD_PLUGIN_INSTRUMENT,
} from "../actions";
import store from "../store";

const channelsLens = lensProp("channels");
const effectsLens = lensProp("effects");
const instrumentsLens = lensProp("instruments");

const overChannels = over(channelsLens);
const overEffects = over(effectsLens);
const overInstruments = over(instrumentsLens);

const nameEquals = (x) => (y) => x === y.name;
const findNameEquals = curry((x, y) => y.find(({ name }) => x === name));
const findConstructor = (x, y) => findNameEquals(x, y).constructor;

const channel = curry((a, b) => findNameEquals(a, b.channels));
const effectInstance = curry(
  (a, b) => findNameEquals(a, b.effectInstances).instance
);
const effectInstanceDestination = (x, y) => effectInstance(x, y).destination;
const instrumentInstance = curry(
  (a, b) => findNameEquals(a, b.instrumentInstances).instance
);

const initialState = {
  channels: [{ effects: [], instruments: [], name: 0 }],
  effectInstances: [],
  effectPlugins: [],
  instrumentInstances: [],
  instrumentPlugins: [],
};

const connectToAudioCtx = (x) => (x.connect(audioContext.destination), x);
const disconnect = (x) => (x.disconnect(), x);

export default (state = initialState, { type, payload }) => {
  switch (type) {
    case ADD_EFFECT_TO_CHANNEL: {
      const thisEffectInstance = effectInstance(payload.name, state);
      const { effects } = channel(payload.channel, state);
      if (!effects.length) connectToAudioCtx(thisEffectInstance);
      else {
        thisEffectInstance.connect(
          effectInstanceDestination(effects[effects.length - 1], state)
        );
      }
      for (const name of channel(payload.channel, state).instruments)
        disconnect(instrumentInstance(name, state)).connect(
          thisEffectInstance.destination
        );
      return overChannels(
        adjust(
          overEffects((effects) => [...effects, payload.name]),
          state.channels.findIndex(
            (channel) => channel.name === payload.channel
          )
        ),
        state
      );
    }
    case ADD_INSTRUMENT_TO_CHANNEL: {
      const instrument = state.instrumentInstances.find(
        ({ name }) => name === payload.name
      ).instance;
      instrument.disconnect();
      const effects = channel(payload.channel, state);
      if (!effects.length) connectToAudioCtx(instrument);
      else
        instrument.connect(
          effectInstanceDestination(effects[effects.length - 1], state)
        );
      return overChannels(
        adjust(
          overInstruments((instruments) => [...instruments, payload.name]),
          state.channels.findIndex(nameEquals(payload.channel))
        ),
        state
      );
    }
    case INSTANTIATE_EFFECT: {
      const instance = pluginWrapperEffect(
        new (findConstructor(payload.plugin, state.effectPlugins))({
          audioContext,
          bpm: store.getState().settings.bpm,
        })
      );
      return {
        ...state,
        effectInstances: [
          ...state.effectInstances,
          { instance, name: payload.name },
        ],
      };
    }
    case INSTANTIATE_INSTRUMENT: {
      const instance = pluginWrapperInstrument(
        new (findConstructor(payload.plugin, state.instrumentPlugins))({
          audioContext,
          bpm: store.getState().settings.bpm,
        })
      );
      connectToAudioCtx(instance);
      return {
        ...state,
        instrumentInstances: [
          ...state.instrumentInstances,
          { instance, name: payload.name },
        ],
      };
    }
    case LOAD_PLUGIN_INSTRUMENT:
      return {
        ...state,
        instrumentPlugins: [...state.instrumentPlugins, payload],
      };
    case LOAD_PLUGIN_EFFECT:
      return {
        ...state,
        effectPlugins: [...state.effectPlugins, payload],
      };
    default:
      return state;
  }
};
<|endoftext|>


<commit_before>const Discord = require('discord.js');

//Sends the stats of the bot to the channel.
function showStats(bot, channel, name) {
    const embed = new Discord.RichEmbed()
        .setTitle(name+' Statistics')
        .setDescription("Warning: Information might be slightly inaccurate.")
        .setColor([188, 123, 55])
        .addField('Mem Usage', `${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)} MB`, true)
        .addField('Users', `${bot.users.size}`, true)
        .addField('Servers', `${bot.guilds.size}`, true)
        .addField('Channels', `${bot.channels.size}`, true)
        .addField('Version', `0.0.6`, true)
        .addField('Discord.js', `v${Discord.version}`, true);
    channel.send({embed});
}

//Displays the stats of the user.
function userInfo(author, channel, name){
    const embed = new Discord.RichEmbed()
        .setTitle(name+' Statistics')
        .setColor([188, 123, 55])
        .addField('Username', author.username, true)
        .addField('Joined', author.createdAt, true)
        .setThumbnail(author.displayAvatarURL)
        .addField('Avatar', author.displayAvatarURL, true);
    /*
    .createdAt -wann der User erstellt wurde
    .displayAvatarURL -gibt den Avatar mit Url zurück
    .username -string vom User
    */
    channel.send({embed});
}

//MODULE EXPORT -- DO NOT MODIFY
module.exports.showStats = showStats;
module.exports.userInfo = userInfo;<commit_msg>Rewrote userinfo.<commit_after>const Discord = require('discord.js');

//Sends the stats of the bot to the channel.
function showStats(bot, channel, name) {
    const embed = new Discord.RichEmbed()
        .setTitle(name+' Statistics')
        .setDescription("Warning: Information might be slightly inaccurate.")
        .setColor([188, 123, 55])
        .addField('Mem Usage', `${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)} MB`, true)
        .addField('Users', `${bot.users.size}`, true)
        .addField('Servers', `${bot.guilds.size}`, true)
        .addField('Channels', `${bot.channels.size}`, true)
        .addField('Version', `0.0.6`, true)
        .addField('Discord.js', `v${Discord.version}`, true);
    channel.send({embed});
}

//Displays the stats of the user.
function userInfo(author, channel, name){
    var info = author.presence;
    const embed = new Discord.RichEmbed()
        .setTitle(author.username)
        .setDescription(author.username + " is in "+info.status+" mode.")
        .setColor([188, 123, 55])
        .setThumbnail(author.displayAvatarURL)
        .addField('Joined Discord on', author.createdAt, true)
        .addField('Avatar', author.displayAvatarURL, true);
    /*
    .createdAt -wann der User erstellt wurde
    .displayAvatarURL -gibt den Avatar mit Url zurück
    .username -string vom User
    */
    channel.send({embed});
}

//MODULE EXPORT -- DO NOT MODIFY
module.exports.showStats = showStats;
module.exports.userInfo = userInfo;<|endoftext|>


<commit_before>var request = require('request');
var parseString = require('xml2js').parseString;

var Service, Characteristic;

module.exports = function(homebridge) {
    Service = homebridge.hap.Service;
    Characteristic = homebridge.hap.Characteristic;
    homebridge.registerAccessory("homebridge-marantz-volume", "marantz-volume", ReceiverVolume);
}

function ReceiverVolume(log, config) {
    this.log = log;

    this.name = config['name'] || "Receiver Volume";
    this.maxVolume = config['maxVolume'] || 70;
    this.host = config['host'];
    this.zone = (config['zone'] || 1) | 0; // default to 1, and make sure its an integer
    this.controlPower = !!config['controlPower']; // default to false, and make sure its a bool
    this.controlMute = !!config['controlMute'] && this.controlPower === false;
    this.mapMaxVolumeTo100 = !!config['mapMaxVolumeTo100'];

    //cap maxVolume.  Denon/Marantz percentage maxes at 98 in receiver settings
    if(this.maxVolume > 98)
        this.maxVolume = 98;

    if (!this.host) {
        this.log.warn('Config is missing host/IP of receiver');
        callback(new Error('No host/IP defined.'));
        return;
    }

    if (this.zone < 1 && this.zone > 2) {
        this.log.warn('Zone number is not recognized (must be 1 or 2); assuming zone 1');
        this.zone = 1;
    }

    this.zoneName = this.zone === 1 ? "MainZone" : "Zone2";

    if (!this.controlPower) {
        this.fakePowerState = 1; //default to on so that brightness will update in HomeKit apps
    }
}

ReceiverVolume.prototype.getStatus = function(callback) {
    var statusUrl = `http://${this.host}/goform/form${this.zoneName}_${this.zoneName}XmlStatus.xml`;
    request.get(statusUrl, function (error, response, body) {
        var xml = '';
        if (!error && response.statusCode == 200) {
            parseString(xml + body, function (err, result) {
                callback(result.item);
            }.bind(this));
        }else{
            callback(null);
        }
    }.bind(this));
}

ReceiverVolume.prototype.setControl = function (control, command, callback) {
    var controlUrl = `http://${this.host}/goform/formiPhoneApp${control}.xml?${this.zone}+${command}`;
    request.get(controlUrl, function (error, response, body) {
        if (!error && response.statusCode == 200) {
            callback(null);
        } else {
            callback(error);
        }
    }.bind(this));
}

ReceiverVolume.prototype.getPowerOn = function(callback) {
    if (this.controlPower) {
        this.getStatus(function(status) {
            var powerState = status.Power[0].value[0] === "ON" ? 1 : 0;
            this.log("Receiver %s Volume power state is %s", this.zoneName, powerState);
            callback(null, powerState);
        }.bind(this));
    } else if (this.controlMute) {
        this.getStatus(function(status) {
            var powerState = status.Mute[0].value[0] === "on" ? 0 : 1;
            this.log("Receiver %s Volume state is %s", this.zoneName, powerState);
            callback(null, powerState);
        }.bind(this));
    } else {
        this.log("Receiver %s Volume power state is %s", this.zoneName, this.fakePowerState);
        callback(null, this.fakePowerState);
    }
}

ReceiverVolume.prototype.setPowerOn = function(powerOn, callback) {
    if (this.controlPower) {
        var command = powerOn ? 'PowerOn' : 'PowerStandby';
        this.log("Set receiver %s volume power state to %s", this.zoneName, command);
        this.setControl('Power', command, callback);
    } else if (this.controlMute) {
        var command = powerOn ? 'MuteOff' : 'MuteOn';
        this.log("Set receiver %s volume state to %s", this.zoneName, command);
        this.setControl('Mute', command, callback);
    } else {
        this.fakePowerState = powerOn ? 1 : 0;
        this.log("Set receiver %s volume power state to %s", this.zoneName, this.fakePowerState);
        callback(null);
    }
}

ReceiverVolume.prototype.setBrightness = function(newLevel, callback) {

    if(this.mapMaxVolumeTo100){
        var volumeMultiplier = this.maxVolume/100;
        var newVolume = volumeMultiplier * newLevel;
    }else{
        //cap to max volume set in homebridge config.json
        var newVolume = Math.min(newLevel, this.maxVolume);
    }

    //cap newVolume.  //Denon/Marantz percentage maxes at 98 in receiver settings
    if(newVolume > 98){
        newVolume = 98;
    }

    //convert volume percentage to relative volume
    var relativeVolume = (2 * (newVolume - 80)).toFixed(0) / 2.0;

    //cap between -80 and 0
    relativeVolume = Math.max(-80.0, Math.min(0.0, relativeVolume));

    this.setControl('Volume', relativeVolume, callback);
}

ReceiverVolume.prototype.getBrightness = function(callback) {
    this.getStatus(function(status) {

        if(status){
            var volume = parseInt(status.MasterVolume[0].value[0]) + 80;
            this.log("Get receiver volume %s ", volume);

            if(this.mapMaxVolumeTo100){
                volume = volume * (100/this.maxVolume);
            }

            callback(null, volume);
        }else{
            this.log("Unable to get receiver status");
            callback(null);
        }

    }.bind(this));
}

ReceiverVolume.prototype.getServices = function() {
    var lightbulbService = new Service.Lightbulb(this.name);

    lightbulbService
        .getCharacteristic(Characteristic.On)
        .on('get', this.getPowerOn.bind(this))
        .on('set', this.setPowerOn.bind(this));

    lightbulbService
        .addCharacteristic(new Characteristic.Brightness())
        .on('get', this.getBrightness.bind(this))
        .on('set', this.setBrightness.bind(this));

    return [lightbulbService];
}
<commit_msg>Fixed null error in getPowerOn<commit_after>var request = require('request');
var parseString = require('xml2js').parseString;

var Service, Characteristic;

module.exports = function(homebridge) {
    Service = homebridge.hap.Service;
    Characteristic = homebridge.hap.Characteristic;
    homebridge.registerAccessory("homebridge-marantz-volume", "marantz-volume", ReceiverVolume);
}

function ReceiverVolume(log, config) {
    this.log = log;

    this.name = config['name'] || "Receiver Volume";
    this.maxVolume = config['maxVolume'] || 70;
    this.host = config['host'];
    this.zone = (config['zone'] || 1) | 0; // default to 1, and make sure its an integer
    this.controlPower = !!config['controlPower']; // default to false, and make sure its a bool
    this.controlMute = !!config['controlMute'] && this.controlPower === false;
    this.mapMaxVolumeTo100 = !!config['mapMaxVolumeTo100'];

    //cap maxVolume.  Denon/Marantz percentage maxes at 98 in receiver settings
    if(this.maxVolume > 98)
        this.maxVolume = 98;

    if (!this.host) {
        this.log.warn('Config is missing host/IP of receiver');
        callback(new Error('No host/IP defined.'));
        return;
    }

    if (this.zone < 1 && this.zone > 2) {
        this.log.warn('Zone number is not recognized (must be 1 or 2); assuming zone 1');
        this.zone = 1;
    }

    this.zoneName = this.zone === 1 ? "MainZone" : "Zone2";

    if (!this.controlPower) {
        this.fakePowerState = 1; //default to on so that brightness will update in HomeKit apps
    }
}

ReceiverVolume.prototype.getStatus = function(callback) {
    var statusUrl = `http://${this.host}/goform/form${this.zoneName}_${this.zoneName}XmlStatus.xml`;
    request.get(statusUrl, function (error, response, body) {
        var xml = '';
        if (!error && response.statusCode == 200) {
            parseString(xml + body, function (err, result) {
                callback(result.item);
            }.bind(this));
        }else{
            callback(null);
        }
    }.bind(this));
}

ReceiverVolume.prototype.setControl = function (control, command, callback) {
    var controlUrl = `http://${this.host}/goform/formiPhoneApp${control}.xml?${this.zone}+${command}`;
    request.get(controlUrl, function (error, response, body) {
        if (!error && response.statusCode == 200) {
            callback(null);
        } else {
            callback(error);
        }
    }.bind(this));
}

ReceiverVolume.prototype.getPowerOn = function(callback) {
    if (this.controlPower) {
        this.getStatus(function(status) {
            var powerState = status ? (status.Power[0].value[0] === "ON" ? 1 : 0) : 0;
            this.log("Receiver %s Volume power state is %s", this.zoneName, powerState);
            callback(null, powerState);
        }.bind(this));
    } else if (this.controlMute) {
        this.getStatus(function(status) {
            var powerState = status ? (status.Mute[0].value[0] === "on" ? 0 : 1) : 0;
            this.log("Receiver %s Volume state is %s", this.zoneName, powerState);
            callback(null, powerState);
        }.bind(this));
    } else {
        this.log("Receiver %s Volume power state is %s", this.zoneName, this.fakePowerState);
        callback(null, this.fakePowerState);
    }
}

ReceiverVolume.prototype.setPowerOn = function(powerOn, callback) {
    if (this.controlPower) {
        var command = powerOn ? 'PowerOn' : 'PowerStandby';
        this.log("Set receiver %s volume power state to %s", this.zoneName, command);
        this.setControl('Power', command, callback);
    } else if (this.controlMute) {
        var command = powerOn ? 'MuteOff' : 'MuteOn';
        this.log("Set receiver %s volume state to %s", this.zoneName, command);
        this.setControl('Mute', command, callback);
    } else {
        this.fakePowerState = powerOn ? 1 : 0;
        this.log("Set receiver %s volume power state to %s", this.zoneName, this.fakePowerState);
        callback(null);
    }
}

ReceiverVolume.prototype.setBrightness = function(newLevel, callback) {

    if(this.mapMaxVolumeTo100){
        var volumeMultiplier = this.maxVolume/100;
        var newVolume = volumeMultiplier * newLevel;
    }else{
        //cap to max volume set in homebridge config.json
        var newVolume = Math.min(newLevel, this.maxVolume);
    }

    //cap newVolume.  //Denon/Marantz percentage maxes at 98 in receiver settings
    if(newVolume > 98){
        newVolume = 98;
    }

    //convert volume percentage to relative volume
    var relativeVolume = (2 * (newVolume - 80)).toFixed(0) / 2.0;

    //cap between -80 and 0
    relativeVolume = Math.max(-80.0, Math.min(0.0, relativeVolume));

    this.setControl('Volume', relativeVolume, callback);
}

ReceiverVolume.prototype.getBrightness = function(callback) {
    this.getStatus(function(status) {

        if(status){
            var volume = parseInt(status.MasterVolume[0].value[0]) + 80;
            this.log("Get receiver volume %s ", volume);

            if(this.mapMaxVolumeTo100){
                volume = volume * (100/this.maxVolume);
            }

            callback(null, volume);
        }else{
            this.log("Unable to get receiver status");
            callback(null);
        }

    }.bind(this));
}

ReceiverVolume.prototype.getServices = function() {
    var lightbulbService = new Service.Lightbulb(this.name);

    lightbulbService
        .getCharacteristic(Characteristic.On)
        .on('get', this.getPowerOn.bind(this))
        .on('set', this.setPowerOn.bind(this));

    lightbulbService
        .addCharacteristic(new Characteristic.Brightness())
        .on('get', this.getBrightness.bind(this))
        .on('set', this.setBrightness.bind(this));

    return [lightbulbService];
}
<|endoftext|>


<commit_before>import {Map} from 'immutable';
import {createReducer} from 'redux-immutablejs';

const SET_DRAWER_OPEN = 'garchen-panel/ui/SET_DRAWER_OPEN';
const SET_SNACK_BAR_PARAMS = 'garchen-panel/ui/SET_SNACK_BAR_PARAMS';

const SET_PROCESSING_CSV_STATUS = 'garchen-panel/ui/SET_PROCESSING_CSV_STATUS';

const initialState = Map({
  isDrawerOpen: false,
  snackBarMessage: '',
  isSnackBarOpen: false,
  isProcessingCsv: true
});

export default createReducer(initialState, {

  [SET_DRAWER_OPEN]: (state, action) => {
    return state.set('isDrawerOpen', action.isDrawerOpen);
  },

  [SET_SNACK_BAR_PARAMS]: (state, action) => {
    return state.set('isSnackBarOpen', action.isSnackBarOpen)
      .set('snackBarMessage', action.snackBarMessage);
  },

  [SET_PROCESSING_CSV_STATUS]: (state, action) => {
    return state.set('isProcessingCsv', action.isProcessingCsv);
  }
});

export function setProcessingCsvStatus(isProcessingCsv) {
  return {
    type: SET_PROCESSING_CSV_STATUS,
    isProcessingCsv
  };
}

export function setDrawerOpen(isDrawerOpen) {
  return {
    type: SET_DRAWER_OPEN,
    isDrawerOpen
  };
}

export function setSnackBarParams(isSnackBarOpen, snackBarMessage = '') {
  return {
    type: SET_SNACK_BAR_PARAMS,
    isSnackBarOpen,
    snackBarMessage
  };
}
<commit_msg>set default isProcessingCsv value to false<commit_after>import {Map} from 'immutable';
import {createReducer} from 'redux-immutablejs';

const SET_DRAWER_OPEN = 'garchen-panel/ui/SET_DRAWER_OPEN';
const SET_SNACK_BAR_PARAMS = 'garchen-panel/ui/SET_SNACK_BAR_PARAMS';

const SET_PROCESSING_CSV_STATUS = 'garchen-panel/ui/SET_PROCESSING_CSV_STATUS';

const initialState = Map({
  isDrawerOpen: false,
  snackBarMessage: '',
  isSnackBarOpen: false,
  isProcessingCsv: false
});

export default createReducer(initialState, {

  [SET_DRAWER_OPEN]: (state, action) => {
    return state.set('isDrawerOpen', action.isDrawerOpen);
  },

  [SET_SNACK_BAR_PARAMS]: (state, action) => {
    return state.set('isSnackBarOpen', action.isSnackBarOpen)
      .set('snackBarMessage', action.snackBarMessage);
  },

  [SET_PROCESSING_CSV_STATUS]: (state, action) => {
    return state.set('isProcessingCsv', action.isProcessingCsv);
  }
});

export function setProcessingCsvStatus(isProcessingCsv) {
  return {
    type: SET_PROCESSING_CSV_STATUS,
    isProcessingCsv
  };
}

export function setDrawerOpen(isDrawerOpen) {
  return {
    type: SET_DRAWER_OPEN,
    isDrawerOpen
  };
}

export function setSnackBarParams(isSnackBarOpen, snackBarMessage = '') {
  return {
    type: SET_SNACK_BAR_PARAMS,
    isSnackBarOpen,
    snackBarMessage
  };
}
<|endoftext|>


<commit_before>var _ = require("lodash");
var e = require("estree-builder");
var parser = require("ecmaless-parser");
var compiler = require("ecmaless-compiler");
var escodegen = require("escodegen");

var getMainLoc = function(tree){
  if(!_.isArray(tree)){
    return tree && tree.loc;
  }
  var parts = _.flattenDeep(tree);
  var first_loc;
  var last_loc;
  var i = 0;
  while(i < parts.length){
    if(_.has(parts[i], "loc")){
      first_loc = parts[i].loc;
      break;
    }
    i++;
  }
  i = parts.length - 1;
  while(i >= 0){
    if(_.has(parts[i], "loc")){
      last_loc = parts[i].loc;
      break;
    }
    i--;
  }
  if(!first_loc || !last_loc){
    return;
  }
  return {
    start: first_loc.start,
    end: first_loc.end
  };
};

var toJSFile = function(estree, opts){
  opts = opts || {};

  if(!_.isArray(estree)){
    estree = [estree];
  }
  return escodegen.generate({
    "loc": getMainLoc(estree),
    "type": "Program",
    "body": estree
  }, opts.escodegen);
};

var extractDeps = function(ast){
  var deps = {};
  var new_ast = ast;
  if(ast[0] && ast[0].type === "Dependencies"){
    _.each(ast[0].dependencies, function(d){
      deps[d.id.value] = d;
    });
    new_ast = ast.slice(1);
  }
  return {deps: deps, ast: new_ast};
};

module.exports = function(conf, callback){

  var modules = {};

  var load = function load(path, callback){
    if(_.has(modules, path)){
      return callback();
    }
    conf.loadPath(path, function(err, src){
      if(err)return callback(err);

      var ast = parser(src, {filename: path});
      var mloc = getMainLoc(ast);
      var mast = [
        {
          loc: mloc,
          type: "Function",
          params: [],
          block: {
            loc: mloc,
            type: "Block",
            body: []
          }
        }
      ];
      var deps = {};
      if(ast[0] && ast[0].type === "Dependencies"){
        _.each(ast[0].dependencies, function(d){
          deps[d.id.value] = d.path.value;
          mast[0].params.push(d.id)
        });
        mast[0].block.body = ast.slice(1);
      }else{
        mast[0].block.body = ast;
      }

      var c = compiler(mast);

      modules[path] = {
        src: src,
        ast: ast,
        est: c.estree[0],
        mast: mast,
        deps: deps,
      };

      if(_.isEmpty(deps)){
        return callback();
      }
      var done = (function(){
        var error;
        var after = _.after(_.size(deps), function(){
          callback(error);
        });
        return function(err){
          if(!error && err){
            error = err;
          }
          after();
        };
      }());
      _.each(deps, function(path){
        load(path, done);
      });
    });
  };

  load(conf.start_path, function(err){
    if(err)return callback(err);

    var toReqPath = function(path){
      return e("string", path);
    };

    var mods = {};
    _.each(modules, function(m, path){
      mods[path] = e("array", [m.est].concat(_.map(m.deps, toReqPath)));
    });
    var est = e("call",
        e("fn", ["mdefs", "main"], []),
        [e("object", mods), e("string", conf.start_path)]);
    callback(void 0, toJSFile(est, conf));
  });
};
<commit_msg>paths to indices<commit_after>var _ = require("lodash");
var e = require("estree-builder");
var parser = require("ecmaless-parser");
var compiler = require("ecmaless-compiler");
var escodegen = require("escodegen");

var getMainLoc = function(tree){
  if(!_.isArray(tree)){
    return tree && tree.loc;
  }
  var parts = _.flattenDeep(tree);
  var first_loc;
  var last_loc;
  var i = 0;
  while(i < parts.length){
    if(_.has(parts[i], "loc")){
      first_loc = parts[i].loc;
      break;
    }
    i++;
  }
  i = parts.length - 1;
  while(i >= 0){
    if(_.has(parts[i], "loc")){
      last_loc = parts[i].loc;
      break;
    }
    i--;
  }
  if(!first_loc || !last_loc){
    return;
  }
  return {
    start: first_loc.start,
    end: first_loc.end
  };
};

var toJSFile = function(estree, opts){
  opts = opts || {};

  if(!_.isArray(estree)){
    estree = [estree];
  }
  return escodegen.generate({
    "loc": getMainLoc(estree),
    "type": "Program",
    "body": estree
  }, opts.escodegen);
};

var extractDeps = function(ast){
  var deps = {};
  var new_ast = ast;
  if(ast[0] && ast[0].type === "Dependencies"){
    _.each(ast[0].dependencies, function(d){
      deps[d.id.value] = d;
    });
    new_ast = ast.slice(1);
  }
  return {deps: deps, ast: new_ast};
};

module.exports = function(conf, callback){

  var modules = {};

  var load = function load(path, callback){
    if(_.has(modules, path)){
      return callback();
    }
    conf.loadPath(path, function(err, src){
      if(err)return callback(err);

      var ast = parser(src, {filename: path});
      var mloc = getMainLoc(ast);
      var mast = [
        {
          loc: mloc,
          type: "Function",
          params: [],
          block: {
            loc: mloc,
            type: "Block",
            body: []
          }
        }
      ];
      var deps = {};
      if(ast[0] && ast[0].type === "Dependencies"){
        _.each(ast[0].dependencies, function(d){
          deps[d.id.value] = d.path.value;
          mast[0].params.push(d.id)
        });
        mast[0].block.body = ast.slice(1);
      }else{
        mast[0].block.body = ast;
      }

      var c = compiler(mast);

      modules[path] = {
        src: src,
        ast: ast,
        est: c.estree[0],
        mast: mast,
        deps: deps,
      };

      if(_.isEmpty(deps)){
        return callback();
      }
      var done = (function(){
        var error;
        var after = _.after(_.size(deps), function(){
          callback(error);
        });
        return function(err){
          if(!error && err){
            error = err;
          }
          after();
        };
      }());
      _.each(deps, function(path){
        load(path, done);
      });
    });
  };

  load(conf.start_path, function(err){
    if(err)return callback(err);

    var path_to_i = {};
    var i = 0;
    _.each(modules, function(m, path){
      path_to_i[path] = i;
      i++;
    });

    var toReqPath = function(path){
      return e("number", path_to_i[path]);
    };

    var mods = [];
    _.each(modules, function(m, path){
      mods.push(e("array", [m.est].concat(_.map(m.deps, toReqPath)), m.est.loc));
    });
    var est = e("call",
        e("fn", ["mdefs", "main"], []),
        [e("array", mods), toReqPath(conf.start_path)]);
    callback(void 0, toJSFile(est, conf));
  });
};
<|endoftext|>


<commit_before>
var compressible = require('compressible')
var spdyPush = require('koa-spdy-push')()
var resolve = require('resolve-path')
var hash = require('hash-stream')
var mime = require('mime-types')
var zlib = require('mz/zlib')
var Path = require('path')
var fs = require('mz/fs')

var extname = Path.extname
var basename = Path.basename

var methods = 'HEAD,GET,OPTIONS'
var notfound = {
  ENOENT: true,
  ENAMETOOLONG: true,
  ENOTDIR: true,
}

module.exports = function (root, options) {
  if (typeof root === 'object') {
    options = root
    root = null
  }

  options = options || {}
  root = root || options.root || process.cwd()

  var cache = Object.create(null)
  var maxage = options.maxage
  var cachecontrol = maxage != null
    ? ('public, max-age=' + (maxage / 1000 | 0))
    : ''
  var etagoptions = options.etag || {}
  var algorithm = etagoptions.algorithm || 'sha256'
  var encoding = etagoptions.encoding || 'base64'
  var index = options.index
  var hidden = options.hidden

  // this.fileServer.send(), etc.
  function FileServer(context) {
    this.context = context
  }

  FileServer.prototype.send = function* (path) {
    return yield* send(this.context, path)
  }

  FileServer.prototype.push = function* (path, opts) {
    return yield* push(this.context, path, opts)
  }

  serve.send = send
  serve.push = push
  serve.cache = cache
  return serve

  // middleware
  function* serve(next) {
    this.fileServer = new FileServer(this)

    yield* next

    // response is handled
    if (this.response.body) return
    if (this.response.status !== 404) return

    yield* send(this)
  }

  // utility
  function* send(ctx, path) {
    var req = ctx.request
    var res = ctx.response

    path = path || req.path.slice(1) || ''

    // index file support
    var directory = path === '' || path.slice(-1) === '/'
    if (index && directory) path += 'index.html'

    // regular paths can not be absolute
    path = resolve(root, path)

    // hidden file support
    if (!hidden && leadingDot(path)) return

    var file = yield* get(path)
    if (!file) return // 404

    // proper method handling
    var method = req.method
    switch (method) {
      case 'HEAD':
      case 'GET':
        break // continue
      case 'OPTIONS':
        res.set('Allow', methods)
        res.status = 204
        return file
      default:
        res.set('Allow', methods)
        res.status = 405
        return file
    }

    res.status = 200
    res.etag = file.etag
    res.lastModified = file.stats.mtime
    res.type = file.type
    if (cachecontrol) res.set('Cache-Control', cachecontrol)

    if (req.fresh) {
      res.status = 304
      return file
    }

    if (method === 'HEAD') return file

    if (file.compress && req.acceptsEncodings('gzip', 'identity') === 'gzip') {
      res.set('Content-Encoding', 'gzip')
      res.length = file.compress.stats.size
      res.body = fs.createReadStream(file.compress.path)
    } else {
      res.set('Content-Encoding', 'identity')
      res.length = file.stats.size
      res.body = fs.createReadStream(path)
    }

    return file
  }

  function* push(ctx, path, opts) {
    if (!path) throw new Error('you must define a path!')
    if (!ctx.res.isSpdy) return

    opts = opts || {}

    if (path[0] === '/') throw new Error('you can only push relative paths')
    var uri = path // original path

    // index file support
    var directory = path === '' || path.slice(-1) === '/'
    if (index && directory) path += 'index.html'

    // regular paths can not be absolute
    path = resolve(root, path)

    var file = yield* get(path)
    if (!file) throw new Error('can not push file: ' + uri)

    var options = {
      path: '/' + uri,
      priority: opts.priority,
    }

    var headers = options.headers = {
      'content-type': file.type,
      etag: file.etag,
      'last-modified': file.stats.mtime.toUTCString(),
    }

    if (cachecontrol) headers['cache-control'] = cachecontrol

    if (file.compress) {
      headers['content-encoding'] = 'gzip'
      headers['content-length'] = file.compress.stats.size
      options.filename = file.compress.path
    } else {
      headers['content-encoding'] = 'identity'
      headers['content-length'] = file.stats.size
      options.filename = path
    }

    spdyPush(ctx, options)

    return file
  }

  // get the file from cache if possible
  function* get(path) {
    if (cache[path] && (yield fs.exists(cache[path].compress.path))) return cache[path]

    var stats = yield* stat(path)
    // we don't want to cache 404s because
    // the cache object will get infinitely large
    if (!stats || !stats.isFile()) return
    stats.path = path

    var file = cache[path] = {
      stats: stats,
      etag: '"' + (yield hash(path, algorithm)).toString(encoding) + '"',
      type: mime.contentType(extname(path)) || 'application/octet-stream',
    }

    if (!compressible(file.type)) return file

    // if we can compress this file, we create a .gz
    var compress = file.compress = {
      path: path + '.gz'
    }

    // delete old .gz files in case the file has been updated
    try {
      yield fs.unlink(compress.path)
    } catch (err) {}

    // save to a random file name first
    var tmp = path + '.' + random() + '.gz'
    yield function (done) {
      fs.createReadStream(path)
      .on('error', done)
      .pipe(zlib.createGzip())
      .on('error', done)
      .pipe(fs.createWriteStream(tmp))
      .on('error', done)
      .on('finish', done)
    }

    compress.stats = yield fs.stat(tmp)

    // if the gzip size is larger than the original file,
    // don't bother gzipping
    if (compress.stats.size > stats.size) {
      delete file.compress
      yield fs.unlink(tmp)
    } else {
      // otherwise, rename to the correct path
      yield fs.rename(tmp, compress.path)
    }

    return file
  }
}

function* stat(filename) {
  try {
    return yield fs.stat(filename)
  } catch (err) {
    // bluebird shit
    if (err.cause && err.cause instanceof Error) err = err.cause
    if (notfound[err.code]) return
    err.status = 500
    throw err
  }
}

function leadingDot(path) {
  return '.' === basename(path)[0]
}

function random() {
  return Math.random().toString(36).slice(2)
}
<commit_msg>fix shit<commit_after>
var compressible = require('compressible')
var spdyPush = require('koa-spdy-push')()
var resolve = require('resolve-path')
var hash = require('hash-stream')
var mime = require('mime-types')
var zlib = require('mz/zlib')
var Path = require('path')
var fs = require('mz/fs')

var extname = Path.extname
var basename = Path.basename

var methods = 'HEAD,GET,OPTIONS'
var notfound = {
  ENOENT: true,
  ENAMETOOLONG: true,
  ENOTDIR: true,
}

module.exports = function (root, options) {
  if (typeof root === 'object') {
    options = root
    root = null
  }

  options = options || {}
  root = root || options.root || process.cwd()

  var cache = Object.create(null)
  var maxage = options.maxage
  var cachecontrol = maxage != null
    ? ('public, max-age=' + (maxage / 1000 | 0))
    : ''
  var etagoptions = options.etag || {}
  var algorithm = etagoptions.algorithm || 'sha256'
  var encoding = etagoptions.encoding || 'base64'
  var index = options.index
  var hidden = options.hidden

  // this.fileServer.send(), etc.
  function FileServer(context) {
    this.context = context
  }

  FileServer.prototype.send = function* (path) {
    return yield* send(this.context, path)
  }

  FileServer.prototype.push = function* (path, opts) {
    return yield* push(this.context, path, opts)
  }

  serve.send = send
  serve.push = push
  serve.cache = cache
  return serve

  // middleware
  function* serve(next) {
    this.fileServer = new FileServer(this)

    yield* next

    // response is handled
    if (this.response.body) return
    if (this.response.status !== 404) return

    yield* send(this)
  }

  // utility
  function* send(ctx, path) {
    var req = ctx.request
    var res = ctx.response

    path = path || req.path.slice(1) || ''

    // index file support
    var directory = path === '' || path.slice(-1) === '/'
    if (index && directory) path += 'index.html'

    // regular paths can not be absolute
    path = resolve(root, path)

    // hidden file support
    if (!hidden && leadingDot(path)) return

    var file = yield* get(path)
    if (!file) return // 404

    // proper method handling
    var method = req.method
    switch (method) {
      case 'HEAD':
      case 'GET':
        break // continue
      case 'OPTIONS':
        res.set('Allow', methods)
        res.status = 204
        return file
      default:
        res.set('Allow', methods)
        res.status = 405
        return file
    }

    res.status = 200
    res.etag = file.etag
    res.lastModified = file.stats.mtime
    res.type = file.type
    if (cachecontrol) res.set('Cache-Control', cachecontrol)

    if (req.fresh) {
      res.status = 304
      return file
    }

    if (method === 'HEAD') return file

    if (file.compress && req.acceptsEncodings('gzip', 'identity') === 'gzip') {
      res.set('Content-Encoding', 'gzip')
      res.length = file.compress.stats.size
      res.body = fs.createReadStream(file.compress.path)
    } else {
      res.set('Content-Encoding', 'identity')
      res.length = file.stats.size
      res.body = fs.createReadStream(path)
    }

    return file
  }

  function* push(ctx, path, opts) {
    if (!path) throw new Error('you must define a path!')
    if (!ctx.res.isSpdy) return

    opts = opts || {}

    if (path[0] === '/') throw new Error('you can only push relative paths')
    var uri = path // original path

    // index file support
    var directory = path === '' || path.slice(-1) === '/'
    if (index && directory) path += 'index.html'

    // regular paths can not be absolute
    path = resolve(root, path)

    var file = yield* get(path)
    if (!file) throw new Error('can not push file: ' + uri)

    var options = {
      path: '/' + uri,
      priority: opts.priority,
    }

    var headers = options.headers = {
      'content-type': file.type,
      etag: file.etag,
      'last-modified': file.stats.mtime.toUTCString(),
    }

    if (cachecontrol) headers['cache-control'] = cachecontrol

    if (file.compress) {
      headers['content-encoding'] = 'gzip'
      headers['content-length'] = file.compress.stats.size
      options.filename = file.compress.path
    } else {
      headers['content-encoding'] = 'identity'
      headers['content-length'] = file.stats.size
      options.filename = path
    }

    spdyPush(ctx, options)

    return file
  }

  // get the file from cache if possible
  function* get(path) {
    var val = cache[path]
    if (val && val.compress && (yield fs.exists(val.compress.path))) return val

    var stats = yield* stat(path)
    // we don't want to cache 404s because
    // the cache object will get infinitely large
    if (!stats || !stats.isFile()) return
    stats.path = path

    var file = cache[path] = {
      stats: stats,
      etag: '"' + (yield hash(path, algorithm)).toString(encoding) + '"',
      type: mime.contentType(extname(path)) || 'application/octet-stream',
    }

    if (!compressible(file.type)) return file

    // if we can compress this file, we create a .gz
    var compress = file.compress = {
      path: path + '.gz'
    }

    // delete old .gz files in case the file has been updated
    try {
      yield fs.unlink(compress.path)
    } catch (err) {}

    // save to a random file name first
    var tmp = path + '.' + random() + '.gz'
    yield function (done) {
      fs.createReadStream(path)
      .on('error', done)
      .pipe(zlib.createGzip())
      .on('error', done)
      .pipe(fs.createWriteStream(tmp))
      .on('error', done)
      .on('finish', done)
    }

    compress.stats = yield fs.stat(tmp)

    // if the gzip size is larger than the original file,
    // don't bother gzipping
    if (compress.stats.size > stats.size) {
      delete file.compress
      yield fs.unlink(tmp)
    } else {
      // otherwise, rename to the correct path
      yield fs.rename(tmp, compress.path)
    }

    return file
  }
}

function* stat(filename) {
  try {
    return yield fs.stat(filename)
  } catch (_) {
    // bluebird shit
    var err = _.cause || _
    if (notfound[err.code]) return
    err.status = 500
    throw err
  }
}

function leadingDot(path) {
  return '.' === basename(path)[0]
}

function random() {
  return Math.random().toString(36).slice(2)
}
<|endoftext|>


<commit_before>// https://github.com/cozy/cozy-stack/blob/master/pkg/consts/consts.go

// Doctypes
export const FILES_DOCTYPE = 'io.cozy.files'

// Files document type
export const DIR_TYPE = 'directory'
export const FILE_TYPE = 'file'

// Special document ids
export const ROOT_DIR_ID = 'io.cozy.files.root-dir'
export const TRASH_DIR_ID = 'io.cozy.files.trash-dir'
<commit_msg>remote/constants: Introduce TRASH_DIR_NAME<commit_after>// https://github.com/cozy/cozy-stack/blob/master/pkg/consts/consts.go

// Doctypes
export const FILES_DOCTYPE = 'io.cozy.files'

// Files document type
export const DIR_TYPE = 'directory'
export const FILE_TYPE = 'file'

// Special document ids
export const ROOT_DIR_ID = 'io.cozy.files.root-dir'
export const TRASH_DIR_ID = 'io.cozy.files.trash-dir'

export const TRASH_DIR_NAME = '.cozy_trash'
<|endoftext|>


<commit_before>/*
 * Constants
 * */
var maxSegments = 3;

var movieKeywords = ["1080p", "720p", "480p", "blurayrip", "brrip", "divx", "dvdrip", "hdrip", "hdtv", "tvrip", "xvid", "camrip"];

// Excluded is an object we use to exclude those keywords from consideration for detecting strings like "season X"
var excluded = { };
movieKeywords.forEach(function(x) { excluded[x] = 1 });

var SEGMENTS_SPLIT = /\.| |-|;|_/g;
var MATCH_FILES = /.mp4$|.mkv$|.avi$/;
var minYear = 1900, maxYear = 2060;

/*
 * TWO REFERENCES
 * * http://wiki.xbmc.org/index.php?title=Adding_videos_to_the_library/Naming_files/TV_shows
 * * http://wiki.xbmc.org/index.php?title=Advancedsettings.xml#.3Ctvshowmatching.3E
 */

var path = require("path");

function simplifyName(n) {
    return n.toLowerCase()
        .trim()
        .replace(/\([^\(]+\)$/, "") // remove brackets at end
        .replace(/&/g, "and")
        .replace(/[^0-9a-z ]+/g, " ") // remove special chars
        .split(" ").filter(function(r){return r}).join(" ")
};

function parseVideoName(filePath, options)
{
    //if (! filePath.match(MATCH_FILES)) return { type: "other" };

    var options = options || {};
    var meta = {};

    var segments = filePath
        .replace(/\\/g, "/") // Support Windows slashes, lol
        .split("/")
        .reverse()
        .filter(function(x) { return x })
        .slice(0, maxSegments);
    var firstNameSplit = segments[0].split(/\.| |_/);

    /*
     * Helpers to validate if we have found the proper metadata
     */
    function saneSeason()
    {
        return meta.hasOwnProperty("season") && !isNaN(meta.season)
    };
    function saneEpisode()
    {
        return Array.isArray(meta.episode) && meta.episode.length
    };

    /*
     * Test for a year in the name
     * */
    [segments[0], segments[1]].filter(function(x){return x}).forEach(function(seg)
    {
        var numbers = seg.match(/[^\d](\d\d\d\d)[^\d]/);
        if (numbers && numbers[1])
        {
            var number = parseInt(numbers[1], 10);
            if (number >= minYear && number <= maxYear)
                meta.year = number;
        }
    });

    /*
     * Test for "aired" stamp; if aired stamp is there, we have a series
     */
    var pad = function(x) { return ("00"+x).slice(-2) };
    [segments[0], segments[1]].filter(function(x){return x}).forEach(function(seg)
    {
        var aired = seg.match(/(\d\d\d\d)(\.|-| )(\d\d)(\.|-| )(\d\d)/);
        if (aired && aired[1])
        {
            var year = parseInt(aired[1], 10);
            if (year >= minYear && year <= maxYear)
                meta.aired = [year, pad(aired[3]), pad(aired[5])].join("-");
        }
    });

    /*
     * A typical pattern - "s05e12", "S01E01", etc. ; can be only "E01"
     * Those are matched only in the file name
     *
     * TODO: this stamp may be in another segment (e.g. directory name)
    * */
    [segments[0], segments[1]].forEach(function(seg) {
        if (seg) seg.split(/\.| |_/).forEach(function(x, i)
        {
            /*
             * Card type one
             */
            var seasonMatch = x.match(/S(\d{1,2})/i);   /* TODO: bug: uc-css4cd2.avi is a false positive */
            if (seasonMatch)
                meta.season = parseInt(seasonMatch[1], 10);

            /* TODO: consider the case when a hyphen is used for multiple episodes ; e.g. e1-3 */
            var episodeMatch = x.match(/E(\d{2})/ig);
            if (episodeMatch)
                meta.episode = episodeMatch.map(function(y) { return parseInt(y.slice(1), 10) });

            /*
             * 01x20
             */
            var xStampMatch = x.match(/(\d\d?)x(\d\d?)/i);
            if (xStampMatch)
            {
                meta.season = parseInt(xStampMatch[1], 10);
                meta.episode = [ parseInt(xStampMatch[2], 10) ];
            }
            // if (otherCardMatch)
        });

        /* Extract name from this match */
        var fullMatch = seg && seg.replace(/\.| |;|_/g, " ").match(/^([a-zA-Z0-9,-?!'& ]*) S(\d{1,2})E(\d{2})/i);
        if (!meta.name && meta.season && meta.episode && fullMatch && fullMatch[1]) meta.name = fullMatch[1];
        // TODO: consider not going through simplifyName
    });

    /*
     * This stamp must be tested before splitting (by dot)
     * a pattern of the kind [4.02]
     * This pattern should be arround characters which are not digits and not letters
     * */

    var dotStampMatch = segments[0].match(/[^\da-zA-Z](\d\d?)\.(\d\d?)[^\da-zA-Z]/i);
    if (! (saneSeason() && saneEpisode()) && dotStampMatch && !meta.year) // exclude meta.year to avoid confusing movie matches - especially if they contain 5.1 for suround sound
    {
        meta.season = parseInt(dotStampMatch[1], 10);
        meta.episode = [ parseInt(dotStampMatch[2], 10) ];
    }

    /*
     *  A stamp of the style "804", meaning season 8, episode 4
     * */
    if (!(saneSeason() && saneEpisode()) && !options.strict)
    {
        var stamp = firstNameSplit
        .reverse() /* search from the end */
        .map(function(x)
        {
            if (x.match(new RegExp("\\d\\d\\d\\d?e"))) x = x.slice(0, -1); /* This is a weird case, but I've seen it: dexter.801e.720p.x264-kyr.mkv */
            if (x.match(new RegExp("s\\d\\d\\d\\d?"))) x = x.slice(1); /* I've never seen this, but it might happen */
            return x;
        })
        .filter(function(x)
        {
            return !isNaN(x) && (x.length == 3 || (!meta.year && x.length == 4)) /* 4-digit only allowed if this has not been identified as a year */
        })[0]; /* Notice how always the first match is choosen ; the second might be a part of the episode name (e.g. "Southpark - 102 - weight gain 4000");
                * that presumes episode number/stamp comes before the name, which is where most human beings would put it */

        /* Since this one is risky, do it only if we haven't matched a year (most likely not a movie) or if year is BEFORE stamp, like: show.2014.801.mkv */
        if (stamp && (!meta.year || (meta.year && (firstNameSplit.indexOf(stamp.toString()) < firstNameSplit.indexOf(meta.year.toString())))))
        {
            meta.episode = [ parseInt(stamp.slice(-2), 10) ];
            meta.season = parseInt(stamp.slice(0, -2), 10);
        }
    }

    /*
     * "season 1", "season.1", "season1"
     * */
    if (! saneSeason())
    {
        var seasonMatch = segments.join("/").match(/season(\.| )?(\d{1,2})/ig);
        if (seasonMatch)
            meta.season = parseInt(seasonMatch[0].match(/\d/g).join(""), 10);

        var seasonEpMatch = segments.join("/").match(/Season (\d{1,2}) - (\d{1,2})/i);
        if (seasonEpMatch) {
            meta.season = parseInt(seasonEpMatch[1], 10);
            meta.episode = [ parseInt(seasonEpMatch[2], 10) ];
        }
    }

    /*
     * "episode 13", "episode.13", "episode13", "ep13", etc.
     * */
    if (! saneEpisode())
    {
        /* TODO: consider the case when a hyphen is used for multiple episodes ; e.g. e1-3*/
        var episodeMatch = segments.join("/").match(/ep(isode)?(\.| )?(\d+)/ig);
        if (episodeMatch)
            meta.episode = [ parseInt(episodeMatch[0].match(/\d/g).join(""), 10) ];
    }

    /*
     * Try plain number
     * This will lead to more false positives than true positives; disabling
     * /
     /*
    if (saneSeason() && !saneEpisode())
    {
        var epNumbers = firstNameSplit
            .filter(function(x) { return !isNaN(x) && (x.length == 2 || x.length == 1) })
            .map(function(x) { return parseInt(x, 10) })

        if (epNumbers.length)
            meta.episode = epNumbers;
    }*/

    /*
     * If still nothing, the number from the second dir can be used, if the first dir has the show name??
     *
     * OR, split everything by everything (hyphens, underscores), filter for numbers between 1 and 30 and use the assumption that the episode is on the rightmost and the series is left from it
     * (unless the numbers are a part of a date stamp)
     * */

    /*
     * Which part (for movies which are split into .cd1. and .cd2., etc.. files)
     * TODO: WARNING: this assumes it's in the filename segment
     *
     * */
    var diskNumberMatch = segments[0].match(/[ _.-]*(?:cd|dvd|p(?:ar)?t|dis[ck]|d)[ _.-]*(\d)[^\d]/); /* weird regexp? */
    if (diskNumberMatch)
        meta.diskNumber = parseInt(diskNumberMatch[1], 10);

    /*
     * The name of the series / movie
     * */
    var isSample;

    (options.fromInside ? segments : [].concat(segments).reverse()).forEach(function(seg, i)
    {
        if (seg == segments[0]) {
            seg = seg.split(".").slice(0, -1).join("."); /* Remove extension */

            var sourcePrefix = seg.match(/^\[(.*?)\]/)
            if (sourcePrefix) seg = seg.slice(sourcePrefix[0].length)
        }

        /*
         * WARNING: we must change how this works in order to handle cases like
         * "the office[1.01]" as well as "the office [1.01]"; if we split those at '[' or ']', we will get the name "the office 1 10"
         * For now, here's a hack to fix this
         */
        var squareBracket = seg.indexOf("[");
        if (squareBracket > -1) seg = seg.slice(0, squareBracket);

        //var segSplit = seg.split(/\.| |-|\[|\]|;|_/),
        var segSplit = seg.split(SEGMENTS_SPLIT),
            word,
            nameParts = [];

        isSample = isSample || seg.match(/^sample/i)|| seg.match(/^etrg/i);

        /* No need to go further;  */
        if (meta.name)
            return;

        var lastIndex;
        segSplit.some(function(word, i)
        {
            lastIndex = i;
            /* words with basic punctuation and two-digit numbers; or numbers in the first position */
            if (! (word.match("^[a-zA-Z,?!'&]*$") || (!isNaN(word) && word.length <= 2) || (!isNaN(word) && i==0))
                || excluded[word.toLowerCase()]
                || ((["ep", "episode", "season"].indexOf(word.toLowerCase()) > -1) && !isNaN(segSplit[i+1])) // TODO: more than that, match for stamp too
                )
                return true;

            nameParts.push(word);
        });
        if (nameParts.length == 1 && !isNaN(nameParts[0])) return; /* Only a number: unacceptable */

        meta.name = nameParts
            .filter(function(x) { return x && x.length > 0 })
            .map(function(x) { return x[0].toUpperCase() + x.slice(1).toLowerCase() })
            .join(" ");
    });

    isSample = isSample || ((segments[1] || "").toLowerCase() == "sample"); /* The directory where the file resides */

    /*
     * This is the time to decide the category of this video
     */
    var canBeMovie;
    if (options.strict) canBeMovie = meta.hasOwnProperty("year");
    else canBeMovie = meta.hasOwnProperty("year") || meta.hasOwnProperty("diskNumber") || movieKeywords.some(function(keyword) { return segments.join("/").toLowerCase().search(keyword) > -1 });

    if (meta.name && meta.aired)
        meta.type = "series";
    if (meta.name && saneSeason() && saneEpisode())
        meta.type = "series";
    else if (meta.name && canBeMovie)
        meta.type = "movie";
    // Must be deprioritized compared to movies
    else if (meta.type != "movie" && meta.name && saneSeason()) // assume extras or bloopers?
        meta.type = "extras";
    else
        meta.type = "other";

    if (options.fileLength && options.fileLength < (meta.type.match(/movie/) ? 80 : 50)*1024*1024 && meta.type.match(/movie|series/) && !isSample) {
        meta.type = "other";
    }

    if (meta.type != "series" || meta.aired) {
        delete meta.episode;
        delete meta.season;
    }

    // we have a year. put it to .aired instead
    if (meta.type == "series" && meta.year) {
     meta.aired = meta.aired || meta.year;
     delete meta.year;
    }

    meta.type += isSample ? "-sample" : "";

    meta.name = meta.name && simplifyName(meta.name);

    /* Try to find the IMDB id from the NFO / hints
     */
    //if (meta.nfo)
    //    meta.imdb_id = (fs.readFileSync(meta.nfo).toString().match("tt\\d{7}") || [])[0];

    if (options.hints && options.hints.imdb_id)
        meta.imdb_id = options.hints.imdb_id;

    meta.tag = [];
    if (filePath.match(/1080p/i)) { meta.tag.push("hd"); meta.tag.push("1080p"); }
    if (filePath.match(/720p/i)) { meta.tag.push("720p"); }
    if (filePath.match(/480p/i)) { meta.tag.push("480p"); }
    if (isSample) meta.tag.push("sample");

    return meta;
}

module.exports = parseVideoName;
<commit_msg>remove obsolete usage of path<commit_after>/*
 * Constants
 * */
var maxSegments = 3;

var movieKeywords = ["1080p", "720p", "480p", "blurayrip", "brrip", "divx", "dvdrip", "hdrip", "hdtv", "tvrip", "xvid", "camrip"];

// Excluded is an object we use to exclude those keywords from consideration for detecting strings like "season X"
var excluded = { };
movieKeywords.forEach(function(x) { excluded[x] = 1 });

var SEGMENTS_SPLIT = /\.| |-|;|_/g;
var MATCH_FILES = /.mp4$|.mkv$|.avi$/;
var minYear = 1900, maxYear = 2060;

/*
 * TWO REFERENCES
 * * http://wiki.xbmc.org/index.php?title=Adding_videos_to_the_library/Naming_files/TV_shows
 * * http://wiki.xbmc.org/index.php?title=Advancedsettings.xml#.3Ctvshowmatching.3E
 */

function simplifyName(n) {
    return n.toLowerCase()
        .trim()
        .replace(/\([^\(]+\)$/, "") // remove brackets at end
        .replace(/&/g, "and")
        .replace(/[^0-9a-z ]+/g, " ") // remove special chars
        .split(" ").filter(function(r){return r}).join(" ")
};

function parseVideoName(filePath, options)
{
    //if (! filePath.match(MATCH_FILES)) return { type: "other" };

    var options = options || {};
    var meta = {};

    var segments = filePath
        .replace(/\\/g, "/") // Support Windows slashes, lol
        .split("/")
        .reverse()
        .filter(function(x) { return x })
        .slice(0, maxSegments);
    var firstNameSplit = segments[0].split(/\.| |_/);

    /*
     * Helpers to validate if we have found the proper metadata
     */
    function saneSeason()
    {
        return meta.hasOwnProperty("season") && !isNaN(meta.season)
    };
    function saneEpisode()
    {
        return Array.isArray(meta.episode) && meta.episode.length
    };

    /*
     * Test for a year in the name
     * */
    [segments[0], segments[1]].filter(function(x){return x}).forEach(function(seg)
    {
        var numbers = seg.match(/[^\d](\d\d\d\d)[^\d]/);
        if (numbers && numbers[1])
        {
            var number = parseInt(numbers[1], 10);
            if (number >= minYear && number <= maxYear)
                meta.year = number;
        }
    });

    /*
     * Test for "aired" stamp; if aired stamp is there, we have a series
     */
    var pad = function(x) { return ("00"+x).slice(-2) };
    [segments[0], segments[1]].filter(function(x){return x}).forEach(function(seg)
    {
        var aired = seg.match(/(\d\d\d\d)(\.|-| )(\d\d)(\.|-| )(\d\d)/);
        if (aired && aired[1])
        {
            var year = parseInt(aired[1], 10);
            if (year >= minYear && year <= maxYear)
                meta.aired = [year, pad(aired[3]), pad(aired[5])].join("-");
        }
    });

    /*
     * A typical pattern - "s05e12", "S01E01", etc. ; can be only "E01"
     * Those are matched only in the file name
     *
     * TODO: this stamp may be in another segment (e.g. directory name)
    * */
    [segments[0], segments[1]].forEach(function(seg) {
        if (seg) seg.split(/\.| |_/).forEach(function(x, i)
        {
            /*
             * Card type one
             */
            var seasonMatch = x.match(/S(\d{1,2})/i);   /* TODO: bug: uc-css4cd2.avi is a false positive */
            if (seasonMatch)
                meta.season = parseInt(seasonMatch[1], 10);

            /* TODO: consider the case when a hyphen is used for multiple episodes ; e.g. e1-3 */
            var episodeMatch = x.match(/E(\d{2})/ig);
            if (episodeMatch)
                meta.episode = episodeMatch.map(function(y) { return parseInt(y.slice(1), 10) });

            /*
             * 01x20
             */
            var xStampMatch = x.match(/(\d\d?)x(\d\d?)/i);
            if (xStampMatch)
            {
                meta.season = parseInt(xStampMatch[1], 10);
                meta.episode = [ parseInt(xStampMatch[2], 10) ];
            }
            // if (otherCardMatch)
        });

        /* Extract name from this match */
        var fullMatch = seg && seg.replace(/\.| |;|_/g, " ").match(/^([a-zA-Z0-9,-?!'& ]*) S(\d{1,2})E(\d{2})/i);
        if (!meta.name && meta.season && meta.episode && fullMatch && fullMatch[1]) meta.name = fullMatch[1];
        // TODO: consider not going through simplifyName
    });

    /*
     * This stamp must be tested before splitting (by dot)
     * a pattern of the kind [4.02]
     * This pattern should be arround characters which are not digits and not letters
     * */

    var dotStampMatch = segments[0].match(/[^\da-zA-Z](\d\d?)\.(\d\d?)[^\da-zA-Z]/i);
    if (! (saneSeason() && saneEpisode()) && dotStampMatch && !meta.year) // exclude meta.year to avoid confusing movie matches - especially if they contain 5.1 for suround sound
    {
        meta.season = parseInt(dotStampMatch[1], 10);
        meta.episode = [ parseInt(dotStampMatch[2], 10) ];
    }

    /*
     *  A stamp of the style "804", meaning season 8, episode 4
     * */
    if (!(saneSeason() && saneEpisode()) && !options.strict)
    {
        var stamp = firstNameSplit
        .reverse() /* search from the end */
        .map(function(x)
        {
            if (x.match(new RegExp("\\d\\d\\d\\d?e"))) x = x.slice(0, -1); /* This is a weird case, but I've seen it: dexter.801e.720p.x264-kyr.mkv */
            if (x.match(new RegExp("s\\d\\d\\d\\d?"))) x = x.slice(1); /* I've never seen this, but it might happen */
            return x;
        })
        .filter(function(x)
        {
            return !isNaN(x) && (x.length == 3 || (!meta.year && x.length == 4)) /* 4-digit only allowed if this has not been identified as a year */
        })[0]; /* Notice how always the first match is choosen ; the second might be a part of the episode name (e.g. "Southpark - 102 - weight gain 4000");
                * that presumes episode number/stamp comes before the name, which is where most human beings would put it */

        /* Since this one is risky, do it only if we haven't matched a year (most likely not a movie) or if year is BEFORE stamp, like: show.2014.801.mkv */
        if (stamp && (!meta.year || (meta.year && (firstNameSplit.indexOf(stamp.toString()) < firstNameSplit.indexOf(meta.year.toString())))))
        {
            meta.episode = [ parseInt(stamp.slice(-2), 10) ];
            meta.season = parseInt(stamp.slice(0, -2), 10);
        }
    }

    /*
     * "season 1", "season.1", "season1"
     * */
    if (! saneSeason())
    {
        var seasonMatch = segments.join("/").match(/season(\.| )?(\d{1,2})/ig);
        if (seasonMatch)
            meta.season = parseInt(seasonMatch[0].match(/\d/g).join(""), 10);

        var seasonEpMatch = segments.join("/").match(/Season (\d{1,2}) - (\d{1,2})/i);
        if (seasonEpMatch) {
            meta.season = parseInt(seasonEpMatch[1], 10);
            meta.episode = [ parseInt(seasonEpMatch[2], 10) ];
        }
    }

    /*
     * "episode 13", "episode.13", "episode13", "ep13", etc.
     * */
    if (! saneEpisode())
    {
        /* TODO: consider the case when a hyphen is used for multiple episodes ; e.g. e1-3*/
        var episodeMatch = segments.join("/").match(/ep(isode)?(\.| )?(\d+)/ig);
        if (episodeMatch)
            meta.episode = [ parseInt(episodeMatch[0].match(/\d/g).join(""), 10) ];
    }

    /*
     * Try plain number
     * This will lead to more false positives than true positives; disabling
     * /
     /*
    if (saneSeason() && !saneEpisode())
    {
        var epNumbers = firstNameSplit
            .filter(function(x) { return !isNaN(x) && (x.length == 2 || x.length == 1) })
            .map(function(x) { return parseInt(x, 10) })

        if (epNumbers.length)
            meta.episode = epNumbers;
    }*/

    /*
     * If still nothing, the number from the second dir can be used, if the first dir has the show name??
     *
     * OR, split everything by everything (hyphens, underscores), filter for numbers between 1 and 30 and use the assumption that the episode is on the rightmost and the series is left from it
     * (unless the numbers are a part of a date stamp)
     * */

    /*
     * Which part (for movies which are split into .cd1. and .cd2., etc.. files)
     * TODO: WARNING: this assumes it's in the filename segment
     *
     * */
    var diskNumberMatch = segments[0].match(/[ _.-]*(?:cd|dvd|p(?:ar)?t|dis[ck]|d)[ _.-]*(\d)[^\d]/); /* weird regexp? */
    if (diskNumberMatch)
        meta.diskNumber = parseInt(diskNumberMatch[1], 10);

    /*
     * The name of the series / movie
     * */
    var isSample;

    (options.fromInside ? segments : [].concat(segments).reverse()).forEach(function(seg, i)
    {
        if (seg == segments[0]) {
            seg = seg.split(".").slice(0, -1).join("."); /* Remove extension */

            var sourcePrefix = seg.match(/^\[(.*?)\]/)
            if (sourcePrefix) seg = seg.slice(sourcePrefix[0].length)
        }

        /*
         * WARNING: we must change how this works in order to handle cases like
         * "the office[1.01]" as well as "the office [1.01]"; if we split those at '[' or ']', we will get the name "the office 1 10"
         * For now, here's a hack to fix this
         */
        var squareBracket = seg.indexOf("[");
        if (squareBracket > -1) seg = seg.slice(0, squareBracket);

        //var segSplit = seg.split(/\.| |-|\[|\]|;|_/),
        var segSplit = seg.split(SEGMENTS_SPLIT),
            word,
            nameParts = [];

        isSample = isSample || seg.match(/^sample/i)|| seg.match(/^etrg/i);

        /* No need to go further;  */
        if (meta.name)
            return;

        var lastIndex;
        segSplit.some(function(word, i)
        {
            lastIndex = i;
            /* words with basic punctuation and two-digit numbers; or numbers in the first position */
            if (! (word.match("^[a-zA-Z,?!'&]*$") || (!isNaN(word) && word.length <= 2) || (!isNaN(word) && i==0))
                || excluded[word.toLowerCase()]
                || ((["ep", "episode", "season"].indexOf(word.toLowerCase()) > -1) && !isNaN(segSplit[i+1])) // TODO: more than that, match for stamp too
                )
                return true;

            nameParts.push(word);
        });
        if (nameParts.length == 1 && !isNaN(nameParts[0])) return; /* Only a number: unacceptable */

        meta.name = nameParts
            .filter(function(x) { return x && x.length > 0 })
            .map(function(x) { return x[0].toUpperCase() + x.slice(1).toLowerCase() })
            .join(" ");
    });

    isSample = isSample || ((segments[1] || "").toLowerCase() == "sample"); /* The directory where the file resides */

    /*
     * This is the time to decide the category of this video
     */
    var canBeMovie;
    if (options.strict) canBeMovie = meta.hasOwnProperty("year");
    else canBeMovie = meta.hasOwnProperty("year") || meta.hasOwnProperty("diskNumber") || movieKeywords.some(function(keyword) { return segments.join("/").toLowerCase().search(keyword) > -1 });

    if (meta.name && meta.aired)
        meta.type = "series";
    if (meta.name && saneSeason() && saneEpisode())
        meta.type = "series";
    else if (meta.name && canBeMovie)
        meta.type = "movie";
    // Must be deprioritized compared to movies
    else if (meta.type != "movie" && meta.name && saneSeason()) // assume extras or bloopers?
        meta.type = "extras";
    else
        meta.type = "other";

    if (options.fileLength && options.fileLength < (meta.type.match(/movie/) ? 80 : 50)*1024*1024 && meta.type.match(/movie|series/) && !isSample) {
        meta.type = "other";
    }

    if (meta.type != "series" || meta.aired) {
        delete meta.episode;
        delete meta.season;
    }

    // we have a year. put it to .aired instead
    if (meta.type == "series" && meta.year) {
     meta.aired = meta.aired || meta.year;
     delete meta.year;
    }

    meta.type += isSample ? "-sample" : "";

    meta.name = meta.name && simplifyName(meta.name);

    /* Try to find the IMDB id from the NFO / hints
     */
    //if (meta.nfo)
    //    meta.imdb_id = (fs.readFileSync(meta.nfo).toString().match("tt\\d{7}") || [])[0];

    if (options.hints && options.hints.imdb_id)
        meta.imdb_id = options.hints.imdb_id;

    meta.tag = [];
    if (filePath.match(/1080p/i)) { meta.tag.push("hd"); meta.tag.push("1080p"); }
    if (filePath.match(/720p/i)) { meta.tag.push("720p"); }
    if (filePath.match(/480p/i)) { meta.tag.push("480p"); }
    if (isSample) meta.tag.push("sample");

    return meta;
}

module.exports = parseVideoName;
<|endoftext|>