foobar2000 0.8.3 custom by Draikin

Discussion in 'Nguồn phát từ máy tính' started by tml3nr, 3/8/17.

  1. thienphuc74

    thienphuc74 Advanced Member

    Joined:
    4/9/15
    Messages:
    240
    Likes Received:
    57
    Không hiện được đầy đủ thông tin định dạng file và bit deep như các bản trước. Fix sao Bác?
    upload_2025-8-21_12-51-45.png
     
  2. viking

    viking Advanced Member

    Joined:
    31/7/09
    Messages:
    368
    Likes Received:
    323
    hi bác @thienphuc74,
    Mình không rõ nguyên nhân, có lẽ foo_youtube từ version 3.10 (06/07/2025) đã thay đổi cách diễn dịch (giản lược/bỏ qua) metadata để đổi lấy tốc độ do chuyển hoàn toàn qua yt-dlp (độ trễ rất nhiều) ( . . . removed Third-party Binaries JavaScript and excluded Node.js executable (node.exe) from the component package - they were used only by the internal analyzer which is gone now --https://fy.3dyd.com/changelog/latest/).

    giải pháp:
    về bản chất, metadata (thông tin liên quan đến file nhạc ) đi theo media file nên cách thủ công sau sẽ đáp ứng yêu cầu.
    - lấy youtube clip URL : search yotube clip từ trình duyệt (right click trên video, copy URL), hay play youtube từ foobar2000 như bình thường.
    - download youtube clip: trong màn hình now playing, right click, chọn Download video clip\from Youtube . clip sẽ được lưu xuống thư mục 'mặc nhiên' là D:\music\youtube_source (có thể thay đổi từ chính menu 'Download video clip').
    - play youtube clip (đã download): file youtube clip này được foobar2000 xử lý như file local bình thường nên sẽ hiển thị đầy đủ metadata.

    chúc Bác vui,
    V,
     
    Last edited: 21/8/25
    thienphuc74 likes this.
  3. thienphuc74

    thienphuc74 Advanced Member

    Joined:
    4/9/15
    Messages:
    240
    Likes Received:
    57
    Cảm ơm Bác Nhiều. vì mình thấy các bản trước đó có hiện thông tin file nhạc đầy đủ ( 160kbps 48Hz .opus ) Bác ạ
     
    viking likes this.
  4. caocaolatre199x

    caocaolatre199x Approved Member

    Joined:
    8/1/25
    Messages:
    7
    Likes Received:
    7
    Cám ơn bác, hiện tại em đang tiếp tục dev và test thêm, vẫn chưa hoàn thiện ạ.
     
    viking likes this.
  5. viking

    viking Advanced Member

    Joined:
    31/7/09
    Messages:
    368
    Likes Received:
    323
    Vâng bác,
    Diễn đàn rất cần những thế hệ người dùng mới, cách tiếp cận mới, khai phá những cách 'chơi' audio mới, giải quyết vấn đề cũ theo cách sáng tạo hơn.
    Những thành viên tích cực 1 thời bắt đầu có tuổi, ưu tiên khác trong cuộc sống nên ít tương tác hơn.
    Chúc Bác vui và mong chờ những chia sẻ.
    V,
     
    caocaolatre199x and thienphuc74 like this.
  6. hhiepbi

    hhiepbi Advanced Member

    Joined:
    1/7/13
    Messages:
    2.988
    Likes Received:
    2.698
    E down về chạy FB2000 với quyền Admin, mở file dfs nó không chạy, mò youtube cũng o dc bác à. Win 11 pro, cũng chả hiểu sao nữa.
     
  7. thienphuc74

    thienphuc74 Advanced Member

    Joined:
    4/9/15
    Messages:
    240
    Likes Received:
    57
    chạy DSD thì bác phải cài thêm componel nữa ( goole có hướng dẫn phát file dfs trên foobar đó )
     
    Last edited: 23/8/25
    viking likes this.
  8. thienphuc74

    thienphuc74 Advanced Member

    Joined:
    4/9/15
    Messages:
    240
    Likes Received:
    57
    Phát youtube: Bạn vào biểu tượng búa chéo sau 5 ngôi sao trên cùng > chọn Layout > Shotcut > Youtube theo như bài đã hướng dẫn của Bác VIKING ở trên
     
    viking likes this.
  9. thienphuc74

    thienphuc74 Advanced Member

    Joined:
    4/9/15
    Messages:
    240
    Likes Received:
    57
    Đây nhé........đủ 20 kí tự
     

    Attached Files:

    viking likes this.
  10. thienphuc74

    thienphuc74 Advanced Member

    Joined:
    4/9/15
    Messages:
    240
    Likes Received:
    57
  11. thienphuc74

    thienphuc74 Advanced Member

    Joined:
    4/9/15
    Messages:
    240
    Likes Received:
    57
    SACD(Current version: 1.5.12):

    This plugin is capable to decode Super Audio CD ISO image content as well as DST, DSDIFF and DSD files.
    This plugin contains CODE FROM SACD Ripper http://code.google.com/p/sacd-ripper/ project.
    A change log is included in the zip file.

    Check part 2 of this guide HERE for more information on how to set it up

    **RECOMMENDATION** Do not install nor use the DSDIFF decoder plugin available at the Foobar’s component page. It is obsolete, performs worse and has less functionality than foo_sacd_plugin and can make the player crash when both DSD related plugins are installed at the same time.

    Link: SACD plugin homepage
     
    viking likes this.
  12. viking

    viking Advanced Member

    Joined:
    31/7/09
    Messages:
    368
    Likes Received:
    323
    Chào 4rum,
    Như đã hứa v/v build 1 theme foobar2000 nhẹ, gọn (theo tinh thần NGHE hay - NHÌN được của VNAV), nhưng vẫn đảm bảo các tính năng:
    - hỗ trợ youtube
    - internet radio
    - hỗ trợ tìm lời bài hát (lyrics)
    - tìm tiểu sử ca sỹ (bio artist).
    - tìm hình ca sỹ từ Web last.fm

    Theme sẽ sử dụng foobar2000 x86 để tận dụng rất nhiều các component 32bit, đặc biệt 2 components Shpeck và VU Meter cho phần nhìn. Theme đặt tên DarkOnx86DUI để dễ nhớ (bên cạnh DarkOnx64DUI đã có).
    Mình sẽ cố gắng chi tiết từng bước.
    day 1: design layout, bản vẽ mặt bằng theo dạng đối xứng (vì theme sẽ không có hệ thống tab với nhiều cửa sổ/panel chồng), nên tổng thể cân xứng 1 chút sẽ dễ nhìn (như máy cassette 2 cửa, 2 loa; amply tube).
    (Do vừa nghĩ, làm vừa viết nên câu chữ đôi chỗ sẽ lô xô, mong anh em thông cảm).

    DarkOnx86DUI_layout.jpg
    (còn tiếp)
     
    khangbui and thienphuc74 like this.
  13. thienphuc74

    thienphuc74 Advanced Member

    Joined:
    4/9/15
    Messages:
    240
    Likes Received:
    57
    ỦNG HỘ BÁC VIKING! LÊN LÀ LÊN. HOAN HỶ
     
    Last edited: 26/8/25
    viking likes this.
  14. viking

    viking Advanced Member

    Joined:
    31/7/09
    Messages:
    368
    Likes Received:
    323
    Cảm ơn Bác.
    Mình không biết dùng Photoshop nên phần nhìn hạn chế.
    Theme sẽ sử dụng đa số các tài nguyên (component, script có sẵn của các cao thủ tiền bối - tuy nhiên sẽ dao kéo chút đỉnh cho hợp tông).
    Có lẽ đây cũng là hướng tiếp cận của số đông khi lần đầu đến với món này nên hy vọng tính thực tế, thực dụng.
    thân,
    V,
     
    Last edited: 26/8/25
    thienphuc74 likes this.
  15. viking

    viking Advanced Member

    Joined:
    31/7/09
    Messages:
    368
    Likes Received:
    323
    Chào 4rum,
    chủ đề : build foobar2000 DarkOnx86DUI theme
    day 2: tìm kiếm tài nguyên.

    như có lần chia sẻ, foobar2000 không mạnh ớ khía cạnh hỗ trợ skin, nếu so sánh với AIMP (có tool riêng cho việc này) hay các chương trình khác. điểm mạnh của foobar2000 (nếu có) có lẽ do có lượng người dùng trung thành từ lâu là chính.
    khoảng 2010, thời kỳ hoàng kim của foobar2000, gắn liền với giai đoạn chưa bùng nổ các dịch vụ nhạc trên mạng.
    các component foobar2000 chủ yếu do cá nhân tự làm nên rất khó tránh khỏi bugs, chuyện crash như thường ở huyện.
    vì vậy, chúng ta xem đây như 1 chuyến dạo chơi là chính.

    UI lựa chọn: Default User Interface

    1. theme tham khảo và rã đồ:
    2. component cần thiết:
    - foobar2000 : https://www.foobar2000.org/download
    - đa số component : https://www.foobar2000.org/components
    - các component khác:
    3. script :
    ngoại trừ script cho slideshow, các scripts đều do các cây đa cây đề phát triển trong thời gian dài nên rất ổn định và đẹp (ngay cả tên biến cũng gợi nhớ), tính năng phong phú, giải thuật khỏi chê và quan trọng nhất là tác giả script cũng là tác giả script engine (Marc2003) hay trao đổi trực tiếp (Wil-B với ThetheQwertiest), có sửa cũng dễ.

    hôm nay, chúng ta sẽ ưu tiên tinh chỉnh script dùng cho image slideshow trước:
    - link gốc: https://foobar-users.de/index.php?PHPSESSID=kjnt529aj3mjk1uej2hn12k7ld&msg=16562
    - bản sửa :
    • hỗ trợ vài kiểu frame cho bắt mắt (3D curved, glass, oval, chữ nhật).
    • tìm artwork từ các nguồn : các thư mục trong file nhạc, thư mục hình khác (do người dùng chỉ định: như thư mục hình gia đình, hay hình yêu thích), hình download từ lastfm.
    • thiết lập thông số thời gian slideshow, số lượng hình.
    • cơ chế 'thông minh' khi quản lý cached bộ nhớ.
    script này đã được edit (Mar2024) cho foobar2000 TECH theme nên không mất nhiều thời gian lắm, mình để đoạn script được edit lần này trong box sau, đặng tiện tham khảo từ điện thoại và mong chờ góp ý của các Bác.

    trước mắt như thế, chúng ta sẽ tinh chỉnh tiếp trong quá trình hoàn thiện theme.
    (còn tiếp)

    V,
    Code:
    // image slideshow
    // vnav.vn, 27Aug25 
    . . . 
    getArtworkSubFolders();
    fso && utils_ListFolders_fso(SS_FOLDER);
    sub_folders_all.push(SS_FOLDER);
    window.SetTimeout(function () { //async thread
        check_in();
    },/*enough time for paint calback drawing waiting text*/ 50);
    function on_paint(gr) {
        /* excellent script from @Grimes */
        gr.FillSolidRect(0, 0, ww, wh, g_backcolor );
        gr.SetSmoothingMode(2);
        gr.SetInterpolationMode(1);
       
        if(!g_img) g_img = get_1st_album_art(fb.GetNowPlaying());
        if(busyWorking) {
                busyWorking = false;
                d_img = !d_img ? g_img : d_img;
                try {
                    if (d_img && ww>0 && wh>0) {
                        //full image, scaled to fit panel
                        var _s = Math.min(ww / d_img.Width, wh / d_img.Height);
                        var _w = Math.floor(d_img.Width* _s);
                        var _h = Math.floor(d_img.Height* _s);
                        var _x = Math.round((ww - _w) / 2);
                        var _y = Math.round((wh - _h) / 2);
                   
                        gr.DrawImage(d_img, _x, _y, _w, _h, 0, 0, d_img.Width, d_img.Height);
                    }
                } catch (e) {}
                gr.DrawString("\u2587".repeat(20), gdi.Font("segoe ui", 59, 1), 0x40ffffff, 0, 0, ww, wh, cc_stringformat);
                gr.DrawString((!(fb.IsPaused || fb.IsPlaying) ? "No media playing" : "Working on slideshow . . . "),
                                        gdi.Font("segoe ui", 57, 1), g_syscolor_fr, 0, 0, ww, wh, cc_stringformat);
        };
       
       
        try { // do NOT wait thumbs to be fully cached.
        if (g_img) {
            . . .
            if (show){
                if (right) {
                    gr.DrawImage(g_img, x + move, y, g_img.Width * scale, g_img.Height * scale, 0, 0, g_img.Width, g_img.Height);
                }
               . . .
               }
        } catch(e) {
            //fb.trace("WSH animation cover art :  memory pointer invalid cause by re-generate image list,",e)
            g_img = gdi.Image(noArt);
            g_img = g_imgs[0] ? g_imgs[0] : g_img;
                    var scale = 0;
           
            var x = 0,
                y = 0;
            var scale_w = ww/g_img.Width;
            var scale_h = wh / g_img.Height;
            if (scale_w <= scale_h) {
                scale = scale_w;
                y = (wh - g_img.Height * scale) / 2;
            } else {
                scale = scale_h;
                x = (ww - g_img.Width * scale) / 2;
            }
                gr.DrawImage(g_img, x, y, g_img.Width * scale, g_img.Height * scale, 0, 0, g_img.Width, g_img.Height);           
           
            // in transition track changed
            gr.DrawString("\u2587".repeat(20), gdi.Font("segoe ui", 55, 1), 0x40ffffff, 0, 0, ww, wh, cc_stringformat);
            gr.DrawString((!(fb.IsPaused || fb.IsPlaying) ? "No media playing" : "Working on next slideshow . . . done"), gdi.Font("segoe ui", 50, 1), RGB(0,128,192), 0, 0, ww, wh, cc_stringformat);
        }
    }
    function on_playback_new_track(handle) {
       
        if (!handle) {
            start = false;
            stop = true;
            return ;
        }
         
        show = true;
           
        time = 0;
        check_in(handle);
    }
    function on_playback_dynamic_info_track(){
        // online streaming as radio changes title/arist
        time = 0;
        check_in();
    }
    function on_playback_time(counter_every_second) {
        time++;
       
        if (ca && time > 1 && (time % ct) == 0) on_mouse_lbtn_down(); //animation on
        if (!ca && gennerateSlideDone  && time%5 ==0 ) {
            on_mouse_lbtn_down();
            gennerateSlideDone = false;
        }
       
        if (time <= 2) refresh_timer_cover= 5;
       
        // 1st run: make sure to get metadb
        if (time == 2 && g_imgs.length == 0 ){
           
            busyWorking = true;
            window.Repaint();
            cache_covers(false);
         };
       
         // 2nd run: get downloaded artwork (if any)
        if (time > 2 && time < 60 && (time % 50 /* refresh_timer_cover */) == 0) {
           
            var metadb = (fb.IsPaused || fb.IsPlaying) ? fb.GetNowPlaying() : fb.GetFocusItem();
            if (!metadb || metadb == undefined) return;
       
            var artist  =  fb.TitleFormat("[%artist%]").EvalWithMetadb(metadb);
                artist  =  (artist == "" || !artist) ? fb.TitleFormat("[%artist%]").Eval() : artist ; // if online streaming
            if (artist =="") return;     
            var checkVA = artist.split(",");
           
            if (checkVA.length < 2) checkVA = artist.split(" and ");
            if (checkVA.length < 2) checkVA = artist.split("&");
                checkVA.push(artist);
           
            var g_image_list =[];
            var check_out = false;
            // 1- check JSP3 artist arts downloaded
            for (var i=0; i<imgExt.length ; i++) {
                for (var j= 0 ; j < checkVA.length && checkVA[j] !=""; j++) {
                    g_image_list = utils.Glob(js_data + (checkVA[j]).replace(/^\s+|\s+$/gm,'')+"\\*." + (imgExt[i]).replace(/^\s+|\s+$/gm,'') ).toArray();               
                    if (g_image_list.length) {
                       
                        check_out = true;
                        break;
                    }
                    }                 
            } //i
           
            // 2- check SMP YTTM artist arts downloaded
            if (!check_out) return;
           
            busyWorking = true;
            window.Repaint();
       
            cache_covers(true /*add up more images*/);
           
            refresh_timer_cover=refresh_timer_cover*2; // check in 5,10,20,40 secs
        }
    }
    function slideshow_image_path(){
        var UtB_FOLDER='';
       
        if (objShellApp) UtB_FOLDER = get_folder(SS_FOLDER,'(including sub-folders) for slideshow');
        UtB_FOLDER = UtB_FOLDER.replace(/^\s+|\s+$/gm,'');
       
        if (UtB_FOLDER == "") return false;
        SS_FOLDER = UtB_FOLDER;
       
        if (fso && !fso.FolderExists(SS_FOLDER) ) {
            MsgBox("Failed to set slideshow image path :\n" + SS_FOLDER,4096,themeLongName);
            return false;
           
        } else {
                MsgBox("Path of slideshow images set successfully :\n" + SS_FOLDER,4096,themeLongName);
                window.SetProperty('*SYSTEM.slideshow_image_path (including sub_folders)', SS_FOLDER);
                return true;
        }
       
    }
    //listing of sub-folders recursive function
    function utils_ListFolders_fso(path) {
       
        try {
            var dir = fso.GetFolder(path);
        } catch (e) {
            // online streaming
            // fb.ShowPopupMessage('Error= '+e,window.Name);
            fb.trace('\nError parsing fso.GetFolder(path), ',window.Name, ' : ', e );
            return;
        }
        var e = new Enumerator( dir.SubFolders );
        for(; !e.atEnd(); e.moveNext() ) {
            var p = e.item().Path;
            sub_folders_all.push(p);
            fb.trace('path=' +p);
            utils_ListFolders_fso(p);   
        }
    };
    function getArtworkSubFolders() {   
        var artFile = fb.ProfilePath + "skins\\tech\\misc\\art_sub_folder.ini";
        var text = utils.ReadTextFile(artFile);
        var lines = text.split("\n");
        var lineN = "";
        subFolder[0] ="";
       
        for (var i = 0; i < lines.length; i++) {
            lineN = lines[i].replace(/^\s+|\s+$/gm,'');
            if (lineN.indexOf("//") <0 && lineN != "") {
                    subFolder.push(("\\"+lineN));
            }
        }
       
        subFolder.push("\\{♪_jsvnav_smooth_cache_♪}");
        if (subFolder.length == 2)
            subFolder = ["","\\cover","\\covers","\\scan","\\scans","\\artwork",
                        "\\artworks","\\art","\\image","\\img","\\book","\\folder",
                        "\\{♪_jsvnav_smooth_cache_♪}"];
    };
    function check_in(metadb){
        var handle = metadb;
        if (!metadb || metadb == undefined) {
            handle  = (fb.IsPaused || fb.IsPlaying) ? fb.GetNowPlaying() : fb.GetFocusItem();
            if (!handle || handle == undefined) return false;
        };
       
        var temp_artist = fb.TitleFormat('[%artist%]').EvalWithMetadb(handle);
            temp_artist = temp_artist == '' ? fb.TitleFormat('[%artist%]').Eval() : temp_artist ;
       
       
        var add_up = false;
        if (temp_artist != '' && last_artist === temp_artist) {
           
            var tmp_maxCover = window.GetProperty("*SYSTEM.Automatic cycle arts.MaxNumber",350) -300;
           
            if (ct > 0 && fb.PlaybackLength > 0) {   
                tmp_maxCover = tmp_maxCover > 0 ? Math.min(tmp_maxCover, fb.PlaybackLength/ct)
                            : fb.PlaybackLength/ct;
                           
                tmp_maxCover = parseInt(tmp_maxCover);
            }
           
            if (tmp_maxCover > 0 && maxCover >= tmp_maxCover)  {
               
                return;
            }
           
           
            add_up = true;
        }
       
        busyWorking = true;
        window.Repaint();
       
        last_artist = temp_artist;
        cache_covers(add_up);
       
        return true;
    }
    function cache_covers(not_refresh) {
           
        var metadb = (fb.IsPaused || fb.IsPlaying) ? fb.GetNowPlaying() : fb.GetFocusItem();
           
        if (!not_refresh) {
           
            for (var i=0; i < g_imgs.length; i++) {
                if (g_imgs[i]) g_imgs[i].Dispose(); // assign NULL, leave memory for GC
                CollectGarbage();
            }
            g_imgs=[];
        }
       
        if (!metadb || metadb == undefined) return;
        gennerateSlideDone = false;
       
        maxCover = window.GetProperty("*SYSTEM.Automatic cycle arts.MaxNumber",350) -300;
       
        if (ct > 0 && fb.PlaybackLength > 0) {
            maxCover = maxCover> 0 ? Math.min(maxCover, fb.PlaybackLength/ct)
                        : fb.PlaybackLength/ct;
                       
            maxCover = parseInt(maxCover);
             }
           
        // 1.embedded covers ==>
        if (metadb.RawPath.indexOf("http") < 0)     
        for (var i=0; i < 5; i++) {
            if (!g_imgs[i] )  g_imgs[i] = utils.GetAlbumArtEmbedded(metadb.RawPath, i);
        }       
       
        // 2.some online stream as radio may feed with cover
        if (metadb.RawPath.indexOf("http") >= 0) {
            if (!g_imgs[0] ) g_imgs[0] = utils.GetAlbumArtV2 (metadb, 0);
           
       }
           
           
        /* 3. local arts:  */
        var list_length=5;
        //
        var pathTrack1 = fb.TitleFormat("[$directory_path(%path%)]").EvalWithMetadb(metadb);
        var pathTrack2 = pathTrack1.substr(0,pathTrack1.lastIndexOf('\\')); 
        var pathTrack = [pathTrack1,pathTrack2];
        //online : directory_path => pathTrack1 = 'https://url . . .'; pathTrack2 =""
       
        var maxImg,mMaxImg,ije;
        var g_image_list = new Array;
        for (var p=0; p <pathTrack.length;p++) {
        for (var i=0; i<imgExt.length && pathTrack[p] != "" && metadb.RawPath.indexOf("http") < 0; i++) { //nothing from online store
           
            for (var j=0; j<subFolder.length; j++) {
                                   
                g_image_list = utils.Glob(pathTrack[p]+(subFolder[j]).replace(/^\s+|\s+$/gm,'')+"\\*." + (imgExt[i]).replace(/^\s+|\s+$/gm,'')).toArray();
                list_length =  g_image_list.length > 0 ? list_length + g_image_list.length  : list_length;
                maxImg = maxCover == 0 ? g_image_list.length : Math.min(maxCover,g_image_list.length);
                mMaxImg = maxCover == 0 ? list_length : maxCover;
                ije=0;
               
                for (var ij = 0; ij < mMaxImg ; ij++ ) {
                     if (ije>= maxImg) break;
                     if (!g_imgs[ij]) {
                         for (ije=ije; ije < maxImg ; ){
                            if (g_image_list[ije]) { // always true the 1st time.
                                try {
                                    g_imgs[ij] = gdi.Image(g_image_list[ije]);
                                    ije++;
                                    break;
                                } catch (e) {}
                            }
                            ije++; 
                        }
                     } 
                }
                 if (maxCover >0){   
                     var exit=false;
                     for (k=0; k < maxCover; k++){
                         if ((g_imgs[k]) && k == (maxCover -1)) exit=true;
                     }
                     if (exit) break;
                }                     
            } //j
                 if (maxCover >0){   
                    var exit=false;
                    for (k=0; k < maxCover; k++){
                         if ((g_imgs[k]) && k == (maxCover -1)) exit=true;
                    }
                    if (exit) break;
                }                     
        } //i
        } //p
           
        //4 - artist arts downloaded
            var artist  =  fb.TitleFormat("[%artist%]").EvalWithMetadb(metadb);
                artist  =  (artist == "" || !artist) ? fb.TitleFormat("[%artist%]").Eval() : artist ; // if online streaming
            var checkVA = artist.split(",");
           
            if (checkVA.length < 2) checkVA = artist.split(" and ");
            if (checkVA.length < 2) checkVA = artist.split("&");
                checkVA.push(artist);
           
        // 4.1 check JSP3 arttist arts downlowaded
        list_length=Math.max(5,g_imgs.length);
        g_image_list = [];
        var JSP3art=false;
           
        for (var i=0; i<imgExt.length ; i++) {
            for (var j= 0 ; j < checkVA.length && checkVA[j] !=""; j++) {
             
                g_image_list = utils.Glob(js_data + (checkVA[j]).replace(/^\s+|\s+$/gm,'')+"\\*." + (imgExt[i]).replace(/^\s+|\s+$/gm,'') ).toArray();
               
                list_length =  g_image_list.length > 0 ? list_length + g_image_list.length  : list_length;
                maxImg = maxCover == 0 ? g_image_list.length : Math.min(maxCover,g_image_list.length);
                mMaxImg = maxCover == 0 ? list_length : maxCover;
                ije=0;
               
                for (var ij = 0; ij < mMaxImg ; ij++ ) {
                     if (ije>= maxImg) break;
                     if (!g_imgs[ij]) {
                         for (ije=ije; ije < maxImg ; ){
                            if (g_image_list[ije]) { // always true the 1st time.
                                try {
                                    g_imgs[ij] = gdi.Image(g_image_list[ije]);
                                    ije++;
                                    JSP3art=true;
                                    break;
                                } catch (e) {}
                            }
                            ije++; 
                        }
                     } 
                }
                 if (maxCover >0){   
                     var exit=false;
                     for (k=0; k < maxCover; k++){
                         if ((g_imgs[k]) && k == (maxCover -1)) exit=true;
                     }
                     if (exit) break;
                }                     
            } //j
                 if (maxCover >0){   
                    var exit=false;
                    for (k=0; k < maxCover; k++){
                         if ((g_imgs[k]) && k == (maxCover -1)) exit=true;
                    }
                    if (exit) break;
                }                     
        } //i
           
        // 4.2 // check YTTM arttist arts downlowaded 
        //. . . as in case of 4.1
           
        // 5. lastly, sildeshow image:   
        list_length=Math.max(5,g_imgs.length);
        g_image_list = [];
        for (var i=0; i<imgExt.length; i++) {
            for (var j=0; j<sub_folders_all.length; j++) {
                                   
                g_image_list = utils.Glob((sub_folders_all[j]).replace(/^\s+|\s+$/gm,'')+"\\*." + (imgExt[i]).replace(/^\s+|\s+$/gm,'')).toArray();
               
                list_length =  g_image_list.length > 0 ? list_length + g_image_list.length  : list_length;
                maxImg = maxCover == 0 ? g_image_list.length : Math.min(maxCover,g_image_list.length);
                mMaxImg = maxCover == 0 ? list_length : maxCover;
                ije=0;
               
                for (var ij = 0; ij < mMaxImg ; ij++ ) {
                     if (ije>= maxImg) break;
                     if (!g_imgs[ij]) {
                         for (ije=ije; ije < maxImg ; ){
                            if (g_image_list[ije]) { // always true the 1st time.
                                try {
                                    g_imgs[ij] = gdi.Image(g_image_list[ije]);
                                    ije++;
                                    break;
                                } catch (e) {}
                            }
                            ije++; // just in case file g_image_list[ije] can not be accssed as deleted/locked by its attribute.
                        }
                     } 
                }
                 if (maxCover >0){   
                     var exit=false;
                     for (k=0; k < maxCover; k++){
                         if ((g_imgs[k]) && k == (maxCover -1)) exit=true;
                     }
                     if (exit) break;
                }                     
            } //j
                 if (maxCover >0){   
                    var exit=false;
                    for (k=0; k < maxCover; k++){
                         if ((g_imgs[k]) && k == (maxCover -1)) exit=true;
                    }
                    if (exit) break;
                }                     
        } //i
           
           
        // ======== resize for thumbs cached ================//   
         coverOnShow = maxCover == 0 ? g_imgs.length : Math.min(g_imgs.length, maxCover);
       
         for (var i=0; i < coverOnShow; i++) {
                if (g_imgs[i]) {
                    var g_img_tmp = g_imgs[i];
                    break;
                }
            }
             
         for (var i=0; i < coverOnShow; i++) {
                if (!g_imgs[i]) {
                    if (g_img_tmp) g_imgs[i] = g_img_tmp;
                }                   
            }
           
        try {
             for (var i=0; i < coverOnShow; i++) {
                if (!g_imgs[i]) g_imgs[i]= gdi.Image(noArt);
                if (g_imgs[i])  {
                   
                    if (g_imgs[i].Width> g_imgs[i].Height) {
                        var n_w = maxSizeThumb;
                        var n_h = (g_imgs[i].Height/g_imgs[i].Width)* maxSizeThumb;                         
                    } else {
                        var n_h = maxSizeThumb;
                        var n_w = (g_imgs[i].Width/g_imgs[i].Height)* maxSizeThumb;
                    }
                    g_imgs[i]=g_imgs[i].Resize(n_w, n_h);
                   
                    if (g_img_mask) {
                        if (g_img_mask_id < 3 ) {
                           
                            var mask1 = g_img_mask.Resize(n_w, n_h);
                                g_imgs[i].ApplyMask(mask1);
                                mask1.Dispose();
                        } else if (g_img_mask_id ==3) {
                            //glass
                            var gb = g_imgs[i].GetGraphics();
                            gb.SetSmoothingMode(2);
                            gb.SetInterpolationMode(1);
                                   
                            if(n_h > n_w) {
                                gb.DrawImage(g_img_mask, Math.floor((n_h-n_w)/2)*-1, 0, n_h, n_h, 0, 0, g_img_mask.Width, g_img_mask.Height, 0, 150);
                            } else {
                                gb.DrawImage(g_img_mask, 0, Math.floor((n_w-n_h)/2)*-1, n_w, n_w, 0, 0, g_img_mask.Width, g_img_mask.Height, 0, 150);
                            };
                            g_imgs[i].ReleaseGraphics(gb);
                           
                        }
                    }
                   
                    if ( (!g_img_mask && g_img_mask_id != 0) || g_img_mask_id == 4) { //3D
                            var _s = 6;
                            var _ss = 4
                            var _c = RGB(0,0,0);
                            var _w = g_imgs[i].Width;
                            var _h = g_imgs[i].Height;
                           
                       
                            var _si = gdi.CreateImage(_w, _h);
                                if (_si) {
                                    var _gi = _si.GetGraphics();
                                    var gb = g_imgs[i].GetGraphics();
                                   
                                    gb.SetSmoothingMode(2);
                                    gb.SetInterpolationMode(1);
                                   
                                    //void FillEllipse(x, y, w, h, color);
                                    _gi.FillEllipse(0,-_s/2,_w,_s,_c); //top
                                    _gi.FillEllipse(0,_h-_s/2,_w,_s,_c); //bottom
                                   
                                    _gi.FillEllipse(-_s/2,0,_s,_h,_c); //left
                                    _gi.FillEllipse(_w-_s/2,0,_s,_h,_c); //right
                                   
                                    _si.ReleaseGraphics(_gi);
                                    _si.BoxBlur(_s,1); //BoxBlur(radius, iteration = 1);
                               
                                    gb.DrawImage(_si,0,0,_w,_h,0,0,_w,_h);
                                    //gb.DrawImage(g_imgs[i], _ss, _ss, _w -2*_ss , _h-2*_ss, 0, 0, _w, _h);
                           
                                    _si.Dispose();
                                    g_imgs[i].ReleaseGraphics(gb);
                                   
                            }
                        }
                    }
                } //for (i..
           
        } catch (e) {} 
       
       
        gennerateSlideDone = true;
        window.Repaint();
     }
    
     
  16. thienphuc74

    thienphuc74 Advanced Member

    Joined:
    4/9/15
    Messages:
    240
    Likes Received:
    57
    Hóng Tiếp Bác Ơi! Lên luôn.
     
    viking likes this.
  17. viking

    viking Advanced Member

    Joined:
    31/7/09
    Messages:
    368
    Likes Received:
    323
    Chào 4rum,
    chủ đề : build foobar2000 DarkOnx86DUI theme
    day 3: hoàn tất edit script

    góp ý về image slideshow script bằng WSH script panel:
    - resize image nhỏ trước khi lưu vào cache.
    - quản lý cache (time-based LIFO) : 1 image slideshow sau khi xử lý 'nặng' khoảng 512 px * 512 px ~ 770 KB (do bung ra dạng bitmap và cần 1 ít vùng nhớ để quản lý).
    tốc độ slideshow nhanh nhất 5 giây/hình: 1 track nhạc trung bình tối đa dài 7 phút => max 7*60/5 = 84 hình => chiếm 770 KB * 84 ~ 63 MB là trong giới hạn an toàn.
    với trường hợp image nhiều (nghe cải lương) thì không dùng cache mà draw thẳng ra màn hình bằng 1 tiến trình riêng /*song song với tiến trình lấy và xử lý hình (async) */. do WSH script không thực sự hỗ trợ async (như SMP hay JSP3) nên mình chưa có giải pháp.

    góp ý về Graphic/Artwork Browser:
    - trước đây có ESplaylist component (DUI, CUI) (và trước đó là Graphic Browser component - CUI) hỗ trợ duyệt thư viện dưới dạng artwork, rất trực quan và dễ sử dụng.
    - hiện nay có bác Václav Veselý đang hoàn thiện foobar-grid-view component (https://github.com/veselyvaclavcz/foobar-grid-view) cho foobar2000 x64 DUI, rất tiện dụng và quản lý cache thông minh.
    - script : bác Br33t có 1 script (Smooth Browser) duyệt artwork rất đẹp, nhiều tính năng và dùng cho các DUI, CUI (x86, x64) trên WSH, JSP3 và cả SMP.
    Tuy nhiên, do cần 1 theme gọn nên sẽ dùng bản tích hợp playlist của Ottodix (https://github.com/Ottodix/Eole-foobar-theme).

    cảm ơn các góp ý xây dựng.
    //=================

    bữa nay còn 2 đoạn script, giải quyết xong là chúng ta có thể bắt đầu dựng theme:
    1. lấy hình front cover :
    Do theme dùng các components chủ yếu dựa vào artwork, cụ thể là front cover (vốn được làm đẹp), nên theme sẽ cần foobar2000 hỗ trợ tìm kiếm front cover tích cực nhất có thể. file\preferecens\display\album art\front cover.
    + foobar2000 sẽ tìm và lấy 1 hình đầu tiên thỏa yêu cầu (do chúng ta đưa ra trong search pattern), script sẽ dùng cú pháp ...GetAlbumArt(0), component thường cho set.
    + tìm ở thư mục gốc cùng track nhạc.
    + tìm ở 1 số thư mục con.
    + tìm ở 1 số thư mục cha.
    + vã quá thì quơ quào đại.
    script này quá phổ biến nên chúng ta chỉ cần sửa chút đỉnh từ theme DarkOne mod của bác Kutuzof (https://foobar2000.club/forum/viewtopic.php?t=6549)
    (biến %fb2k_profile_path% do mình xào chẻ, foobar2000 chưa hỗ trợ. khi dùng thì phải thay thế bởi đường dẫn cụ thể như trên Windows (vd: D:\foobar2000\profile\))

    tuy nhiên, quan trọng nhất là album phải có hình front cover lưu kèm (như 1 Bác đã từng khuyên). việc này rất đáng đầu tư thời gian, công sức.
    Code:
    // radio logos
    $if(%length%,,%fb2k_profile_path%skins\radio\logos\%title%.*)
    //1.the same media folder
    *cover*.*
    *front*.*
    *folder*.*
    //2. 1-level down under the same media folder
    art*\*cover*.*
    art*\*front*.*
    art*\*folder*.*
    artwork*\*cover*.*
    artwork*\*front*.*
    artwork*\*folder*.*
    scan*\*cover*.*
    scan*\*front*.*
    scan*\*folder*.*
    image*\*cover*.*
    image*\*front*.*
    image*\*folder*.*
    cover*\*cover*.*
    cover*\*front*.*
    cover*\*folder*.*
    //2. 1-level up vs the  media folder
    $replace($directory_path(%path%),$directory(%path%),*cover*.*)
    $replace($directory_path(%path%),$directory(%path%),*front*.*)
    $replace($directory_path(%path%),$directory(%path%),*folder*.*)
    $replace($directory_path(%path%),$directory(%path%),art*\*cover*.*)
    $replace($directory_path(%path%),$directory(%path%),art*\*front*.*)
    $replace($directory_path(%path%),$directory(%path%),art*\*folder*.*)
    $replace($directory_path(%path%),$directory(%path%),artwork*\*cover*.*)
    $replace($directory_path(%path%),$directory(%path%),artwork*\*front*.*)
    $replace($directory_path(%path%),$directory(%path%),artwork*\*folder*.*)
    $replace($directory_path(%path%),$directory(%path%),scan*\*cover*.*)
    $replace($directory_path(%path%),$directory(%path%),scan*\*front*.*)
    $replace($directory_path(%path%),$directory(%path%),scan*\*folder*.*)
    $replace($directory_path(%path%),$directory(%path%),image*\*cover*.*)
    $replace($directory_path(%path%),$directory(%path%),image*\*front*.*)
    $replace($directory_path(%path%),$directory(%path%),image*\*folder*.*)
    $replace($directory_path(%path%),$directory(%path%),cover*\*cover*.*)
    $replace($directory_path(%path%),$directory(%path%),cover*\*front*.*)
    $replace($directory_path(%path%),$directory(%path%),cover*\*folder*.*)
    //3. whatever
    art*\*.*
    artwork*\*.*
    scan*\*.*
    image*\*.*
    cover*\*.*
    $replace($directory_path(%path%),$directory(%path%),*.*)
    $replace($directory_path(%path%),$directory(%path%),art*\*.*)
    $replace($directory_path(%path%),$directory(%path%),artwork*\*.*)
    $replace($directory_path(%path%),$directory(%path%),scan*\*.*)
    $replace($directory_path(%path%),$directory(%path%),image*\*.*)
    $replace($directory_path(%path%),$directory(%path%),cover*\*.*)
    //SMP YTTM by WilB
    %fb2k_profile_path%yttm\biography-cache\art_img\$cut($meta(artist,0),1)\$meta(artist,0)\*.jpg
    //LASTfm by Marc2k3
    %fb2k_profile_path%js_data\artists\$meta(artist,0)\$meta(artist,0)\*.jpg
    *.*
    //4. default artwork
    %fb2k_profile_path%skins\images\cover.jpg
    %fb2k_profile_path%skins\images\foobar-icon-1.png
    
    2. thumbs script: script còn lại liên quan đến lấy hình từ last.fm đồng thời với hình từ thư mục máy tính:
    - script gốc: script thumbs trong ví dụ kèm theo JScript panel 3 của Marc2003
    Code:
    // ==PREPROCESSOR==
    // @name "Thumbs"
    // @author "marc2003"
    // @import "lodash"
    // @import "%fb2k_component_path%helpers.txt"
    // @import "%fb2k_component_path%samples\js\common.js"
    // @import "%fb2k_component_path%samples\js\panel.js"
    // @import "%fb2k_component_path%samples\js\thumbs.js"
    // ==/PREPROCESSOR==
    // https://jscript-panel.github.io/gallery/thumbs/
    
    - chỉnh sửa (edit 1 chút script của Marc2003):
    + lấy hình front cover (đi theo track nhạc) - mặc định script của Marc2003 chỉ hỗ trợ lấy hình từ các thư mục
    + hỗ trợ hình mặc nhiên (nếu foobar2000 tay trắng trở về).
    + tự động lấy hình ca sỹ từ last.fm nếu trước đó người dùng chỉ chọn lấy hình từ thư mục máy tính. việc này chỉ thực hiện khi chuyển qua youtube hay internet radio (vì trên máy tính đâu có hình ảnh gì liên quan).
    Code:
    function _thumbs_lm() {
        this.download = function () {
            if (!_tagged(this.artist))
                return;
            var url = 'https://www.last.fm/music/' + encodeURIComponent(this.artist) + '/+images';
            var task_id = utils.HTTPRequestAsync(window.ID, 0, url, this.headers);
            this.artists[task_id] = this.artist;
        }
     
        this.http_request_done = function (id, success, response_text) {
            var artist = this.artists[id];
            if (!artist)
                return; // we didn't request this id
            if (!success) {
                console.log(N, response_text);
                return;
            }
            var filename_base = _artistFolder(artist) + utils.ReplaceIllegalChars(artist) + '_'
            _(_getElementsByTagName(response_text, 'li'))
                .filter({ className : 'image-list-item-wrapper' })
                .map(function (item) {
                    var img = _firstElement(item, 'img');
                    var url = img.src.replace('avatar170s/', '');
                    return {
                        url : url,
                        filename : filename_base + url.substring(url.lastIndexOf('/') + 1) + '.jpg',
                    };
                })
                .filter(function (item) {
                    return !utils.IsFile(item.filename);
                })
                .take(thumbs.properties.limit.value)
                .forEach(function (item) {
                    utils.DownloadFileAsync(window.ID, item.url, item.filename, true);
                    updateCounter();
                })
                .value();
        }
        this.metadb_changed = function () {
            if (panel.metadb) {
                // last.fm
                    var temp_artist = panel.tf(DEFAULT_ARTIST);
                    //get the 1st artist name
                    var checkVA = temp_artist.split(",");
                    if (checkVA.length < 2) checkVA=temp_artist.split(" and ");
                    if (checkVA.length < 2) checkVA=temp_artist.split("&");
                    if (checkVA.length < 2) checkVA=temp_artist.split("-");
                    if (checkVA.length < 2) checkVA=temp_artist.split("/");
                        checkVA.push(temp_artist); // add back FULL name  
                        temp_artist = (''+checkVA[0]).replace(/^\s+|\s+$/gm,'');
                    if (temp_artist == "V.A" || temp_artist == "Unknown Artist" || temp_artist == "VA"
                        || temp_artist == "Various Artist" || temp_artist == "Various Artists") temp_artist ="Various Artists_";
                    //
                    if (this.artist == temp_artist)
                        return;
                    this.artist = temp_artist;
                    this.folder = _artistFolder(this.artist);
            } else {
                this.artist = '';
                this.folder = '';
            }
        
            thumbs.update(); //update thumbs
        }
        this.playback_new_track = function () {
            images_length = 0;
            this.counter = 0;
            panel.item_focus_change(); //update metadata
        
        }
        this.playback_time = function () {
            this.counter++;
        
            if (panel.selection.value == /*prefer now playing*/ 0
                && this.counter == 2
                && !this.history[this.artist]
                && _getFiles(this.folder, thumbs.exts).length < thumbs.properties.limit.value) {
            
                this.history[this.artist] = true;
                this.download();
            }
        
            if (this.counter == 10 ) { //1-time  update only , (10-2) seconds later
                //utils.ShowPopupMessage('download done.\nFiles download counter ='+ images_length +'\nFiles downloaded =' + _getFiles(this.folder, thumbs.exts).length );
                //tell parent to update thumbs
                thumbs.update();
            }
        }
        this.history = {}; // track auto-downloads, attempt same artist only once per session
        this.folder = '';
        this.artist = '';
        this.artists = {};
        this.counter = 0;
     
        this.headers = JSON.stringify({
            'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0) Gecko/20100101 Firefox/123.0',
            'Referer' : 'https://www.last.fm',
        });
    }
    
    (còn tiếp)
    V,
     
    Last edited: 28/8/25
    thienphuc74 likes this.
  18. viking

    viking Advanced Member

    Joined:
    31/7/09
    Messages:
    368
    Likes Received:
    323
    Chào 4rum,
    chủ đề : build foobar2000 DarkOnx86DUI theme
    day 4: dựng theme

    các góp ý
    script 1: front cover
    bị sai 1 dòng, sửa lại
    Code:
    //LASTfm by Marc2k3
    %fb2k_profile_path%js_data\artists\$meta(artist,0)\*.jpg
    
    script 2: image slideshow (WSH script panel)
    sau khi cân nhắc 1 vài phương án và gợi ý của bác phương xa, mình đã refactoring toàn bộ phần cache để đảm bảo xử lý được hết các hình trong sildeshow.
    - hình artwork của album: sẽ cache toàn bộ vì số lượng kiểm soát được.
    - hình thêm vào slideshow (khi chọn 1 thư mục hình bất kỳ - gia đình, phong cảnh . . .): sẽ load N play, 1-by-1. gánh nặng xử lý do CPU (vì GPU chưa được WSH tận dụng) đảm nhận. với độ trễ 5 giây và CPU thời nay, việc này chắc không quá khó.
    đúng là sửa nhà còn khó hơn xây mới.
    Code:
    //đoạn script chính
    . . .
    function cache_covers(not_refresh) {
          
        var metadb = (fb.IsPaused || fb.IsPlaying) ? fb.GetNowPlaying() : fb.GetFocusItem();
          
        if (!not_refresh) {
            for (var i=0; i < g_imgs.length; i++) {
                if (g_imgs[i]) g_imgs[i].Dispose(); // assign NULL, leave memory for GC
                CollectGarbage();
            }
            g_imgs=[];
        }
      
        if (!metadb || metadb == undefined) return;
        gennerateSlideDone = false;
      
        maxCover = window.GetProperty("*SYSTEM.Automatic cycle arts.MaxNumber",350) -300;
      
        if (ct > 0 && fb.PlaybackLength > 0) {
            maxCover = maxCover> 0 ? Math.min(maxCover, fb.PlaybackLength/ct)
                        : fb.PlaybackLength/ct;
                      
            maxCover = parseInt(maxCover);
        }
          
        // get what foobar2000 CORE provide: embedded + local (front cover, back, cd, icon, artist)
        // ==============================
      
        var list_length = 0;
        if (metadb.RawPath.indexOf("http") < 0)     {
            // 1.embedded covers ==>
            for (var i=0; i < 5; i++) {
                if (!g_imgs[i] && utils.GetAlbumArtEmbedded(metadb.RawPath, i)) {
                    g_imgs[i] = createThumb(utils.GetAlbumArtEmbedded(metadb.RawPath, i),maxSizeThumb) ; //utils.GetAlbumArtEmbedded(metadb.RawPath, i);
              
                    list_length ++;
                }
            }
      
        } else if (metadb.RawPath.indexOf("http") >= 0) {
            // 2.some online stream as radio may feed with cover
          
            if (!g_imgs[0] && utils.GetAlbumArtV2 (metadb, 0)) {
                g_imgs[0] = createThumb(utils.GetAlbumArtV2 (metadb, 0),maxSizeThumb) ; //utils.GetAlbumArtV2 (metadb, 0);
          
                list_length = list_length ==0 ? 1 : list_length;
            }
       }
            
              
        // get what we ourself havest
        //==================
      
        var _break = false;  
        var g_imgs_p_download =[];
        var g_image_list = [];//new Array;
      
        // 3. local arts:
      
        var pathTrack1 = fb.TitleFormat("[$directory_path(%path%)]").EvalWithMetadb(metadb);
        var pathTrack2 = pathTrack1.substr(0,pathTrack1.lastIndexOf('\\')); //back 1 folder level, may encounter root directory.
        var pathTrack = [pathTrack1,pathTrack2];
        //online : directory_path => pathTrack1 = 'https://url . . .'; pathTrack2 =""
      
        for (var p=0; p <pathTrack.length && !_break;p++) {
            for (var i=0; !_break && i<imgExt.length && pathTrack[p] != "" && metadb.RawPath.indexOf("http") < 0; i++) {
                for (var j=0; !_break && j<subFolder.length; j++) {
                    g_image_list = utils.Glob(pathTrack[p]+(subFolder[j]).replace(/^\s+|\s+$/gm,'')+"\\*." + (imgExt[i]).replace(/^\s+|\s+$/gm,'')).toArray();
                  
                    g_imgs_p_download = g_imgs_p_download.concat(g_image_list);
                    if (maxCover > 0  /* limited images*/
                        && (g_imgs_p_download.length + list_length) >= maxCover )
                            _break = true;
                }
            }
        }
      
      
        //4 - artist arts downloaded
            var artist  =  fb.TitleFormat("[%artist%]").EvalWithMetadb(metadb);
                artist  =  (artist == "" || !artist) ? fb.TitleFormat("[%artist%]").Eval() : artist ; // if online streaming
            var checkVA = artist.split(",");
          
            if (checkVA.length < 2) checkVA = artist.split(" and ");
            if (checkVA.length < 2) checkVA = artist.split("&");  
            if (checkVA.length > 1)  checkVA.push(artist);
          
        // 4.1 check JSP3 arttist arts downlowaded
        var JSP3art=0;
          
        for (var i=0; i<imgExt.length && !_break; i++) {
            for (var j= 0 ; j < checkVA.length && checkVA[j] !="" && !_break; j++) {
              
                g_image_list = utils.Glob(js_data + (checkVA[j]).replace(/^\s+|\s+$/gm,'')+"\\*." + (imgExt[i]).replace(/^\s+|\s+$/gm,'') ).toArray();
                JSP3art += g_image_list.length;
              
                g_imgs_p_download = g_imgs_p_download.concat(g_image_list);
                    if (maxCover > 0  /* limited images*/
                        && (g_imgs_p_download.length + list_length) >= maxCover )
                            _break = true;
                      
                  
            }
        }
      
        // 4.2 // check YTTM arttist arts downlowaded . only no JSP3 artist arts fetched cause they are all from last.fm
        var iArtist="";
     
        for (var i=0; i<imgExt.length && !JSP3art && !_break; i++) {
            for (var j= 0 ; j < checkVA.length && checkVA[j] !="" && !_break; j++) {
              
                iArtist = checkVA[j].replace(/^\s+|\s+$/gm,'');
                iArtist = iArtist.substr(0,1) + "\\"+iArtist;
                g_image_list = utils.Glob(yttm + iArtist +"\\*." + (imgExt[i]).replace(/^\s+|\s+$/gm,'') ).toArray();
                g_imgs_p_download = g_imgs_p_download.concat(g_image_list);
                if (maxCover > 0  /* limited images*/
                    && (g_imgs_p_download.length + list_length) >= maxCover )
                        _break = true;
            }
        } //i
      
      
        //processing
        var n_list_length = g_imgs_p_download.length > 0 ? list_length + g_imgs_p_download.length  : list_length;
        var mMax = maxCover == 0 ? n_list_length : Math.min(n_list_length , maxCover);
        for (var i = 0; i < mMax; i++) {
            if (!g_imgs[i])
                    g_imgs[i] = FormatCover(gdi.Image(g_imgs_p_download[i]),maxSizeThumb);
        };
      
      
        // 5. lastly, sildeshow image:  
        list_length = g_imgs.length;
        g_imgs_p =[];
        for (var i=0; i<imgExt.length && !_break; i++) {
            for (var j=0; j<sub_folders_all.length && !_break; j++) {
                g_image_list = utils.Glob((sub_folders_all[j]).replace(/^\s+|\s+$/gm,'')+"\\*." + (imgExt[i]).replace(/^\s+|\s+$/gm,'')).toArray();
              
                g_imgs_p = g_imgs_p.concat(g_image_list);
                if (maxCover > 0  /* limited images*/
                        && (g_imgs_p.length + list_length) >= maxCover )
                            _break = true;
              
            }
        }
          
        //processing
        if (!loadNplay && g_imgs_p.length > 0) {
            n_list_length = g_imgs_p.length > 0 ? list_length + g_imgs_p.length  : list_length;
            mMax = maxCover == 0 ? n_list_length : Math.min(n_list_length , maxCover);
            for (var i = 0; i < mMax; i++){
                if (!g_imgs[i])
                        g_imgs[i] = FormatCover(gdi.Image(g_imgs_p[i-list_length]),maxSizeThumb);
            }
        }
      
        var img_holder = loadNplay ? g_imgs.length + g_imgs_p.length  :  g_imgs.length;
        coverOnShow = maxCover == 0 ? img_holder : Math.min(img_holder, maxCover);
          
        gennerateSlideDone = true;
        window.Repaint();
     }
    function FormatCover(img,size){
        if(!img) return img;
        try {
        if (img.Width > size || img.Height > size) {
      
            if (img.Width> img.Height) {
                var n_w = size;
                var n_h = (img.Height/img.Width)* size;                        
            } else {
                var n_h = size;
                var n_w = (img.Width/img.Height)* size;
            }
          
            img = img.Resize(n_w, n_h);
        }
              
                  
        if (g_img_mask) {
            if (g_img_mask_id < 3 ) {
                var mask1 = g_img_mask.Resize(n_w, n_h);
                    img.ApplyMask(mask1);
                    mask1.Dispose();
            } else if (g_img_mask_id ==3) {
                //glass
                var gb = img.GetGraphics();
                gb.SetSmoothingMode(2);
                gb.SetInterpolationMode(1);
                      
                if(n_h > n_w) {
                    gb.DrawImage(g_img_mask, Math.floor((n_h-n_w)/2)*-1, 0, n_h, n_h, 0, 0, g_img_mask.Width, g_img_mask.Height, 0, 150);
                } else {
                    gb.DrawImage(g_img_mask, 0, Math.floor((n_w-n_h)/2)*-1, n_w, n_w, 0, 0, g_img_mask.Width, g_img_mask.Height, 0, 150);
                };
                img.ReleaseGraphics(gb);
              
            }
        }
                  
        if ( (!g_img_mask && g_img_mask_id != 0) || g_img_mask_id == 4) { //3D
            var _s = 6;
            var _ss = 4
            var _c = RGB(0,0,0);
            var _w = img.Width;
            var _h = img.Height;
              
          
            var _si = gdi.CreateImage(_w, _h);
                if (_si) {
                    var _gi = _si.GetGraphics();
                    var gb = img.GetGraphics();
                  
                    gb.SetSmoothingMode(2);
                    gb.SetInterpolationMode(1);
                  
                    //void FillEllipse(x, y, w, h, color);
                    _gi.FillEllipse(0,-_s/2,_w,_s,_c); //top
                    _gi.FillEllipse(0,_h-_s/2,_w,_s,_c); //bottom
                  
                    _gi.FillEllipse(-_s/2,0,_s,_h,_c); //left
                    _gi.FillEllipse(_w-_s/2,0,_s,_h,_c); //right
                    
                    _si.ReleaseGraphics(_gi);
                    _si.BoxBlur(_s,1); //BoxBlur(radius, iteration = 1);
              
                    gb.DrawImage(_si,0,0,_w,_h,0,0,_w,_h);
                    //gb.DrawImage(img, _ss, _ss, _w -2*_ss , _h-2*_ss, 0, 0, _w, _h);
          
                    _si.Dispose();
                    img.ReleaseGraphics(gb);
                  
            }
        }
        } catch (e) {}          
        return img;
    }
    function createThumb(img,size){
        if(!img) return img;
        if (img.Width <=size && img.Height <=size) return img
      
        if (img.Width> img.Height) {
            var n_w = size;
            var n_h = (img.Height/img.Width)* size;                        
        } else {
            var n_h = size;
            var n_w = (img.Width/img.Height)* size;
        }
        return img.Resize(n_w, n_h);
    };
    function draw_glass_reflect(w, h) { //credit @Br33t
        // Mask for glass effect
        var Mask_img = gdi.CreateImage(w, h);
        var gb = Mask_img.GetGraphics();
        gb.FillSolidRect(0,0,w,h,0xffffffff);
        gb.FillGradRect(0,0,w-20,h,0,0x99000000,0,1.0);
        gb.SetSmoothingMode(2);
        gb.FillEllipse(-20, 25, w*2+40, h*2, 0xffffffff);
        Mask_img.ReleaseGraphics(gb);
        // drawing the white rect
        var glass_img = gdi.CreateImage(w, h);
        gb = glass_img.GetGraphics();
        gb.FillSolidRect(0, 0, w, h, 0xffffffff);
        glass_img.ReleaseGraphics(gb);
        // resizing and applying the mask
        var Mask = Mask_img.Resize(w, h);
        glass_img.ApplyMask(Mask);
        Mask.Dispose();
        return glass_img;
    };
    function get_1st_album_art(handle) {
        if(!handle /*most of the time*/ ) return gdi.Image(noArt);
        return utils.GetAlbumArtV2(handle, z) ? utils.GetAlbumArtV2(handle, z) : gdi.Image(noArt);
    }
    function get_album_art(handle) {
        if(!handle || !fb.IsPlaying) return gdi.Image(noArt);
      
        if (!loadNplay) {
            return g_imgs[z] ? g_imgs[z] : gdi.Image(noArt);
        }
      
        if (loadNplay){
            //fb.trace('loadNplay image /z= '+z + ' /g_imgs.length=' +g_imgs.length + ' /g_imgs_p.length=' +g_imgs_p.length);
            var img = g_imgs[z];
            if  (!img) {
                fb.trace('image slideshow, loadNplay images /i= '+z
                    + ' /internal images =' +g_imgs.length
                    + ' /external images =' +g_imgs_p.length
                    + ' /path='+ g_imgs_p[z-g_imgs.length]);
                img = legacyCPU ? createThumb(gdi.Image(g_imgs_p[z-g_imgs.length]),maxSizeThumb)
                                : FormatCover(gdi.Image(g_imgs_p[z-g_imgs.length]),maxSizeThumb);
            }
          
            if  (img)    return img;
        }
      
        return gdi.Image(noArt);
    }
    
    cảm ơn các góp ý xây dựng.
    //=================

    hôm nay chúng ta sẽ bắt đầu dựng theme.
    theo thông tin từ day 1, chúng ta sẽ lựa 1 theme từ chợ lạc xoong (thực ra mình đã chọn từ day 1 khi làm bản vẽ sơ bộ).
    - theme 'Foo Tunes' của @Arnie77, 29/07/2012 (https://www.deviantart.com/arnie77/art/Foo-Tunes-317661030) : theme theo kiểu itunes rất đẹp.
    vì Tác giả nhắc đến Br33t, quẹo qua nhà này nghía theme DUiTunes phòng khi bác nào muốn sử dụng (https://www.deviantart.com/br3tt/art/DUiTunes-beta3-412700925) vì Br33t chắc chắn làm theme đẹp (mình có lấy theme này làm ví dụ minh họa cho DarkOnx64DUI theme).
    trên AIMP skin có nhiều theme iTunes cũng rất đẹp, các bác có thể tham khảo khi dựng layout https://www.aimp.ru/?do=catalog&id=0&os=windows&V=0&F1=0&F2=0&F3=0&F4=40&keywords=
    - cài đặt 'Foo Tunes' : cài đặt theo hướng dẫn trên foobar2000 x86 mới nhất, cứ loay hoay cho lên hình đã, những thứ khác tính sau.
    + foo_ui_hacks: sẽ thay open_hacks
    + foo_lyricsdb : ~~ ESlyrics
    + foo_lastfm_radio : không biết làm gì (bỏ).
    + foo_uie_biography: quá đate, thay bằng script của Marc2003 hay Wil-B
    + foo_quicksearch, foo_playcount : cập nhật mới
    + foo_uie_wsh_panel_mod : giữ nguyên cũng được.

    wow, wow . . . đóng điện xem sao, không khói lửa là được rồi, ù xì tính sau.
    thời gian đúng là kẻ thù của cái đẹp.
    trên DA:
    foo_tunes_by_arnie77.jpg
    ngoài đời:
    DarkOnx64DUI_day4_29Aug25.jpg
    vậy là chúng ta sẽ còn nhiều việc phải làm, nhưng rất thú vị.
    cảm giác như quá trình hồi sinh 1 cái máy cassette hay xe máy cũ, cổ.
    mình để link đến file nén 7zip (18MB) https://www.mediafire.com/file/wnrjbthxnyz55ah/fb2k_32_DarkOnx86DUI+[day+4+_+29Aug25].7z/file để các bác tiện tham khảo:
    - theme nguyên bản.
    - theme cập nhật ngày 29/08/2025.

    (còn tiếp)
    V,
     
    thienphuc74 likes this.
  19. thienphuc74

    thienphuc74 Advanced Member

    Joined:
    4/9/15
    Messages:
    240
    Likes Received:
    57
    Đẹp quá Bác Viking ơi. Để mình Test
     
  20. thienphuc74

    thienphuc74 Advanced Member

    Joined:
    4/9/15
    Messages:
    240
    Likes Received:
    57
    upload_2025-8-29_6-13-46.png
    Giao diện đẹp quá Bác ạ
     
    Last edited: 29/8/25
    viking likes this.
  21. thienphuc74

    thienphuc74 Advanced Member

    Joined:
    4/9/15
    Messages:
    240
    Likes Received:
    57
    đã làm youtube hót được nhưng ko có hình Bác ạ
    upload_2025-8-29_7-5-24.png
     
    viking likes this.
  22. viking

    viking Advanced Member

    Joined:
    31/7/09
    Messages:
    368
    Likes Received:
    323
    Chúc mừng bác @thienphuc74 nhé. Bác cài được món khoai nhất là youtube thì mấy chuyện khác không làm khó bác được.
    Nếu mình hiểu đúng ý bác : không hiện video youtube được!? Bác click vô biểu tượng bánh xe răng cưa ở phía dưới, bên trái để truy cập menu của foobar2000.
    chọn view\visualization\video (mang máng là thế vì mình không ở nhà nên không truy cập máy tính).
    Bác vào mục file\preferences\display\main window (hay advanced) để ẩn/hiện menu phía trên, status bar (do ui_hacks đảm nhiệm).
    Bác thử cài foobar2000 1.x từ trang chủ foobar2000 (tìm trong phần lưu trữ) có thể mang theme về như nguyên bản, nhưng e youtube không cài được.
    thân,
    V
     
    thienphuc74 likes this.
  23. thienphuc74

    thienphuc74 Advanced Member

    Joined:
    4/9/15
    Messages:
    240
    Likes Received:
    57
    Vui quá Bác Viking ạ. Cảm ơn Bác nhiều!
     
  24. thienphuc74

    thienphuc74 Advanced Member

    Joined:
    4/9/15
    Messages:
    240
    Likes Received:
    57
    upload_2025-8-29_14-58-33.png

    Youtube Phát Video Ngon lành rồi Bác Viking ơi. Tuyệt vời!
     
    viking likes this.
  25. thienphuc74

    thienphuc74 Advanced Member

    Joined:
    4/9/15
    Messages:
    240
    Likes Received:
    57
    upload_2025-8-29_15-16-49.png

    có cách nào hiện được thanh tìm kiếm Youtube ( search bar ) thì tiện quá Bác ạ!
     
    Last edited: 29/8/25
    viking likes this.
Tags:

Share This Page

Loading...