• דף הבית
    • אינדקס קישורים
    • פוסטים אחרונים
    • משתמשים
    • חיפוש בהגדרות המתקדמות
    • חיפוש גוגל בפורום
    • ניהול המערכת
    • ניהול המערכת - שרת private
    • הרשמה
    • התחברות

    למה אין נתונים לקווים? 🤔

    מתוזמן נעוץ נעול הועבר בקשות לפיתוח
    146 פוסטים 12 כותבים 1.8k צפיות 5 עוקבים
    טוען פוסטים נוספים
    • מהישן לחדש
    • מהחדש לישן
    • הכי הרבה הצבעות
    תגובה
    • תגובה כנושא
    התחברו כדי לפרסם תגובה
    נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
    • 5 מנותק
      565906 @אA
      נערך לאחרונה על ידי

      @אA החלפתי מהקוד הראשון שנתת כאן לשני וכן עובד, אבל רק חלקית,
      4c18da29-67c9-4c5f-9b6d-164acdfa6f59-image.png

      תגובה 1 תגובה אחרונה תגובה ציטוט 0
      • ב מנותק
        בוס @אA
        נערך לאחרונה על ידי בוס

        @אA אהבתי מאוד את הממשק, תודה רבה.
        יש לי כמה הערות:
        א. הוא לא מביא נתונים אמיתיים, ראה שורה אחרונה שבוודאי זה לא הגיוני.
        0fab30f8-050d-41d0-bb5e-476633fd5d82-image.png

        ב. בלשונית "השמעות" הוא מציג נתונים מכל ההשמעות בעלות שם דומה?
        כלוצר יש לי מספר שלוחות עם השמעה 000, 001. האם הוא מאחד נתונים?
        הייתי אומר להוסיף לו שיסדר לפי השמעות משלוחה מסויימת או שאוטומטי הוא יכתוב את השלוחה ליד הקובץ.

        תודה רבה על כל ההשקעה!

        עריכה: הערה ג. אולי שיהיה אופציה להגדיר לבד את קביעת הסטטוס לפי כמות שיחות/כמות דקות

        5 תגובה 1 תגובה אחרונה תגובה ציטוט 0
        • 1 מנותק
          121244 @אA
          נערך לאחרונה על ידי

          @אA אני בכל מה שקשור לימות וזה דברים מסובכים נעזר בזה
          https://notebooklm.google.com/notebook/6b64a7ea-4f6b-4e07-8542-7be1e3066888

          1 תגובה 1 תגובה אחרונה תגובה ציטוט 0
          • 1 מנותק
            121244 @121244
            נערך לאחרונה על ידי

            @אa תענה בפרטי

            תגובה 1 תגובה אחרונה תגובה ציטוט 0
            • 5 מנותק
              565906 @בוס
              נערך לאחרונה על ידי

              @בוס כתב בלמה אין נתונים לקווים? 🤔:

              א. הוא לא מביא נתונים אמיתיים, ראה שורה אחרונה שבוודאי זה לא הגיוני.

              תראה אצלי מי המובילים.....
              17867a68-0aea-45c2-bb2c-cea15483e658-image.png

              תגובה 1 תגובה אחרונה תגובה ציטוט 0
              • א מנותק
                אA
                נערך לאחרונה על ידי

                וואו!
                איזו כמות תגובות!
                אני לא עומד בקצב...
                אשמח אם יש מי שיוכל לסכם לי את הבאגים והשיפורים.

                ב תגובה 1 תגובה אחרונה תגובה ציטוט 3
                • ב מנותק
                  בוס @אA
                  נערך לאחרונה על ידי בוס

                  @אA כתב בלמה אין נתונים לקווים? 🤔:

                  איזו כמות תגובות!
                  אני לא עומד בקצב.

                  בטח, איך לא. הבאת כאן דבר שנוגע בנקודה הרגישה ביותר!

                  אשמח אם יש מי שיוכל לסכם לי את הבאגים והשיפורים.

                  גדול זה שני הפוסטים הללו:
                  https://f2.freeivr.co.il/post/179893
                  https://f2.freeivr.co.il/post/179891

                  תגובה 1 תגובה אחרונה תגובה ציטוט 0
                  • ב מנותק
                    בוס
                    נערך לאחרונה על ידי בוס

                    @אa כדאי גם להוסיף הצגת ההתקדמות בטעינת הלוגים גם ב מספרים/אחוזים, ולא רק בקו מתמלא.
                    לי יש לוג של מעל מיליון (!) שורות, וכבר למעלה מחצי שעה הוא לא גומר לטעון הקובץ, כך שאני לא יודע אם הוא מתקדם או נתקע סופית.

                    553af961-3c65-483b-b68a-31d1ecb3e228-image.png

                    תגובה 1 תגובה אחרונה תגובה ציטוט 0
                    • 1 מנותק
                      121244
                      נערך לאחרונה על ידי

                      פוסט זה נמחק!
                      ב תגובה 1 תגובה אחרונה תגובה ציטוט 1
                      • ב מנותק
                        בוס @121244
                        נערך לאחרונה על ידי

                        @121244 נשמח שתביא את הקוד כאן, יותר נחמד שהכנסת הטוקן היא על הדפדפן מאשר על שרת.

                        לא שאני חושדך חלילה

                        1 תגובה 1 תגובה אחרונה תגובה ציטוט 0
                        • 1 מנותק
                          121244 @בוס
                          נערך לאחרונה על ידי

                          @בוס מי שלא רוצה לא חייב אני מכניס את זה לכלים בתוך האתר שלי

                          תגובה 1 תגובה אחרונה תגובה ציטוט 0
                          • K מנותק
                            kol
                            נערך לאחרונה על ידי

                            מצורף הקובץ מתוקן ועובד טוב מאוד עם מלא שידורגים

                            בשביל לקבל נתוני השמעות תוסיפו במערכת בהגדרות מתקדמות בשלוחה הראשית בקובץ IVR.ini את ההגדרות הבאות

                            log_playback_play_stop=yes
                            log_playback_play_stop_ymgr_to_html=yes
                            log_playback_play_stop_year_save_folder=yes
                            log_playback_play_stop_year_save_folder_ymgr_to_html=yes
                            log_playback_play_stop_month_save_root_log=yes
                            log_playback_play_stop_month_save_root_log_ymgr_to_html=yes
                            

                            הנה הקוד:

                            <!DOCTYPE html>
                            <html lang="he" dir="rtl">
                            <head>
                                <meta charset="UTF-8">
                                <title>ניתוח נתוני מערכות | v36.0 - גרסה מאובטחת</title>
                                <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
                                <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
                                <style>
                                    :root { --bg: #0f172a; --card: #1e293b; --primary: #38bdf8; --accent: #22c55e; --text: #f1f5f9; --border: #334155; --danger: #ef4444; --warning: #f59e0b; }
                                    body { font-family: 'Segoe UI', sans-serif; background: var(--bg); color: var(--text); margin: 0; display: flex; flex-direction: column; height: 100vh; }
                                    header { background: #1e293b; padding: 1rem 2rem; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border); }
                                    .logo-box { display: flex; align-items: center; gap: 12px; }
                                    .logo-icon { background: linear-gradient(135deg, var(--primary), #0ea5e9); color: #0f172a; width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 1.2rem; }
                                    .logo-text { font-size: 1.4rem; font-weight: 800; color: var(--text); }
                                    .config-box { display: flex; gap: 12px; align-items: center; }
                                    input, select { background: #0f172a; border: 1px solid var(--border); color: white; padding: 10px; border-radius: 8px; outline: none; }
                                    .btn-run { background: var(--primary); color: #0f172a; border: none; padding: 10px 25px; border-radius: 8px; font-weight: bold; cursor: pointer; transition: 0.2s; }
                                    .btn-run:hover { opacity: 0.9; transform: scale(1.02); }
                                    .btn-reset-date { background: transparent; color: #94a3b8; border: 1px solid var(--border); padding: 8px; border-radius: 8px; cursor: pointer; }
                                    .btn-export { background: #475569; color: white; border: none; padding: 6px 12px; border-radius: 6px; cursor: pointer; font-size: 0.8rem; display: flex; align-items: center; gap: 5px; }
                                    .nav-tabs { background: #1e293b; display: flex; padding: 0 20px; border-bottom: 1px solid var(--border); overflow-x: auto; }
                                    .tab { padding: 15px 25px; cursor: pointer; color: #94a3b8; border-bottom: 3px solid transparent; transition: 0.3s; white-space: nowrap; }
                                    .tab.active { color: var(--primary); border-bottom-color: var(--primary); background: rgba(56, 189, 248, 0.07); }
                                    .main-content { flex: 1; padding: 25px; overflow-y: auto; background: #0f172a; }
                                    .card { background: var(--card); padding: 20px; border-radius: 16px; border: 1px solid var(--border); margin-bottom: 25px; }
                                    .stat-num { font-size: 2.2rem; font-weight: 800; color: var(--primary); }
                                    .control-bar { display: flex; gap: 20px; align-items: center; background: #334155; padding: 12px 20px; border-radius: 12px 12px 0 0; justify-content: space-between; flex-wrap: wrap; }
                                    .search-input { background: #0f172a; border: 1px solid var(--border); color: white; padding: 8px 15px; border-radius: 8px; width: 250px; }
                                    table { width: 100%; border-collapse: collapse; background: var(--card); border-radius: 0 0 12px 12px; overflow: hidden; min-width: 600px; }
                                    th { text-align: right; padding: 12px; background: #475569; color: white; font-size: 0.85rem; cursor: pointer; user-select: none; transition: 0.2s; position: relative; }
                                    th:hover { background: #64748b; }
                                    th i { margin-right: 8px; font-size: 0.7rem; opacity: 0.5; }
                                    th.sort-asc i, th.sort-desc i { opacity: 1; color: var(--primary); }
                                    td { padding: 12px; border-bottom: 1px solid var(--border); font-size: 0.9rem; }
                                    .progress-container { width: 100%; background: #1e293b; height: 6px; display: none; position: relative; }
                                    #progress-fill { height: 100%; background: var(--primary); width: 0%; transition: 0.4s; }
                                    .hidden { display: none; }
                                    .btn-play { color: var(--primary); cursor: pointer; background: transparent; border: 1px solid var(--primary); padding: 2px 8px; border-radius: 4px; font-size: 0.8rem; }
                                    .btn-play:hover { background: var(--primary); color: #0f172a; }
                                </style>
                            </head>
                            <body>
                            
                            <header>
                                <div class="logo-box">
                                    <div class="logo-icon"><i class="fas fa-headphones"></i></div>
                                    <div class="logo-text">ניתוח נתוני מערכות</div>
                                </div>
                                <div class="config-box">
                                    <!-- השדה ריק כעת לצורך אבטחה -->
                                    <input type="password" id="apiToken" placeholder="הכנס טוקן API כאן" value="">
                                    <button class="btn-reset-date" title="חזור לתחילת חודש" onclick="setDefaultDates()"><i class="fas fa-calendar-alt"></i></button>
                                    <input type="date" id="startDate">
                                    <input type="date" id="endDate">
                                    <button class="btn-run" onclick="manualStart()">הפעל סריקה</button>
                                </div>
                            </header>
                            
                            <div class="progress-container" id="progBar"><div id="progress-fill"></div></div>
                            
                            <div class="nav-tabs">
                                <div class="tab active" onclick="switchTab(event, 'dash-tab')">דאשבורד</div>
                                <div class="tab" onclick="switchTab(event, 'ext-tab')">כניסות לשלוחות</div>
                                <div class="tab" onclick="switchTab(event, 'play-tab')">לוג השמעות</div>
                                <div class="tab" onclick="switchTab(event, 'users-tab')">מאזינים</div>
                                <div class="tab" style="color: var(--warning)" onclick="switchTab(event, 'debug-tab')">לוג טכני</div>
                            </div>
                            
                            <div class="main-content">
                                <div id="dash-tab" class="tab-content">
                                    <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-bottom: 25px;">
                                        <div class="card"><span style="color: #94a3b8">מאזינים ייחודיים</span><br><span id="stat-users" class="stat-num">0</span></div>
                                        <div class="card"><span style="color: #94a3b8">סה"כ דקות פעילות</span><br><span id="stat-min" class="stat-num">0</span></div>
                                        <div class="card"><span style="color: #94a3b8">השמעות שהושלמו</span><br><span id="stat-comp" class="stat-num">0</span></div>
                                    </div>
                                    <div class="card"><h3>פעילות יומית</h3><canvas id="dailyChart" height="100"></canvas></div>
                                </div>
                            
                                <div id="ext-tab" class="tab-content hidden">
                                    <div class="control-bar">
                                        <input type="text" id="extSearch" class="search-input" placeholder="חפש שלוחה..." onkeyup="renderExts()">
                                        <button class="btn-export" onclick="exportTableToCSV('extTable', 'שלוחות')"><i class="fas fa-file-excel"></i> ייצוא</button>
                                    </div>
                                    <table id="extTable">
                                        <thead>
                                            <tr>
                                                <th onclick="sortTable('extTable', 0, 'string')">שלוחה <i class="fas fa-sort"></i></th>
                                                <th onclick="sortTable('extTable', 1, 'number')">כניסות <i class="fas fa-sort"></i></th>
                                                <th onclick="sortTable('extTable', 2, 'number')">ייחודיים <i class="fas fa-sort"></i></th>
                                                <th onclick="sortTable('extTable', 3, 'number')">סה"כ דקות <i class="fas fa-sort"></i></th>
                                                <th onclick="sortTable('extTable', 4, 'number')">ממוצע <i class="fas fa-sort"></i></th>
                                            </tr>
                                        </thead>
                                        <tbody></tbody>
                                    </table>
                                </div>
                            
                                <div id="play-tab" class="tab-content hidden">
                                    <div class="control-bar">
                                        <input type="text" id="playSearch" class="search-input" placeholder="חפש קובץ, שלוחה או טלפון..." onkeyup="renderPlays()">
                                        <button class="btn-export" onclick="exportTableToCSV('playTable', 'השמעות')"><i class="fas fa-file-excel"></i> ייצוא</button>
                                    </div>
                                    <table id="playTable">
                                        <thead>
                                            <tr>
                                                <th onclick="sortTable('playTable', 0, 'string')">זמן אחרון <i class="fas fa-sort"></i></th>
                                                <th onclick="sortTable('playTable', 1, 'string')">שלוחה <i class="fas fa-sort"></i></th>
                                                <th onclick="sortTable('playTable', 2, 'string')">קובץ <i class="fas fa-sort"></i></th>
                                                <th onclick="sortTable('playTable', 3, 'string')">מאזין אחרון <i class="fas fa-sort"></i></th>
                                                <th onclick="sortTable('playTable', 4, 'number')">השמעות <i class="fas fa-sort"></i></th>
                                                <th onclick="sortTable('playTable', 5, 'number')">סה"כ דק' <i class="fas fa-sort"></i></th>
                                                <th onclick="sortTable('playTable', 6, 'number')">אחוז <i class="fas fa-sort"></i></th>
                                                <th>פעולה</th>
                                            </tr>
                                        </thead>
                                        <tbody></tbody>
                                    </table>
                                </div>
                            
                                <div id="users-tab" class="tab-content hidden">
                                    <div class="control-bar">
                                        <input type="text" id="userSearch" class="search-input" placeholder="חפש טלפון..." onkeyup="renderUsers()">
                                        <button class="btn-export" onclick="exportTableToCSV('usersTable', 'מאזינים')"><i class="fas fa-file-excel"></i> ייצוא</button>
                                    </div>
                                    <table id="usersTable">
                                        <thead>
                                            <tr>
                                                <th onclick="sortTable('usersTable', 0, 'string')">מספר טלפון <i class="fas fa-sort"></i></th>
                                                <th onclick="sortTable('usersTable', 1, 'number')">דקות האזנה <i class="fas fa-sort"></i></th>
                                                <th onclick="sortTable('usersTable', 2, 'number')">פעולות <i class="fas fa-sort"></i></th>
                                                <th onclick="sortTable('usersTable', 3, 'string')">סוג <i class="fas fa-sort"></i></th>
                                            </tr>
                                        </thead>
                                        <tbody></tbody>
                                    </table>
                                </div>
                            
                                <div id="debug-tab" class="tab-content hidden">
                                    <div class="card">
                                        <div id="debug-console" style="background:#000; color:#22c55e; padding:15px; height:450px; overflow-y:auto; font-family:monospace; font-size: 12px; line-height: 1.4;">
                                            <div>מערכת v36.0 מוכנה לאחסון בשרת. הטוקן הוסר מהקוד.</div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            
                            <div id="playerModal" class="hidden" style="position:fixed; bottom:20px; left:20px; background:var(--card); padding:15px; border-radius:12px; border:1px solid var(--primary); z-index:1000; box-shadow: 0 10px 30px rgba(0,0,0,0.5);">
                                <div style="display:flex; justify-content:space-between; margin-bottom:10px;">
                                    <span id="playerTitle" style="font-size:0.8rem; color:var(--primary)">נגן השמעה</span>
                                    <i class="fas fa-times" style="cursor:pointer" onclick="closePlayer()"></i>
                                </div>
                                <audio id="audioPlayer" controls style="width:250px; height:35px;"></audio>
                                <div id="playerError" style="color:var(--danger); font-size:11px; margin-top:5px; display:none;">שגיאה בטעינת הקובץ</div>
                            </div>
                            
                            <script>
                                const API = "https://www.call2all.co.il/ym/api/";
                                let dataStore = { exts: {}, plays: {}, users: {}, daily: {}, totalSec: 0, completed: 0 };
                                let dailyChart = null;
                                let sortState = { tableId: null, colIndex: null, direction: 'asc' };
                            
                                function setDefaultDates() {
                                    const now = new Date();
                                    const firstDay = new Date(now.getFullYear(), now.getMonth(), 1);
                                    const f = (d) => {
                                        let year = d.getFullYear();
                                        let month = String(d.getMonth() + 1).padStart(2, '0');
                                        let day = String(d.getDate()).padStart(2, '0');
                                        return `${year}-${month}-${day}`;
                                    };
                                    document.getElementById('startDate').value = f(firstDay);
                                    document.getElementById('endDate').value = f(now);
                                }
                            
                                function addLog(msg, color = '#22c55e') {
                                    const console = document.getElementById('debug-console');
                                    const div = document.createElement('div');
                                    div.style.color = color;
                                    div.innerHTML = `[${new Date().toLocaleTimeString()}] ${msg}`;
                                    console.appendChild(div);
                                    console.scrollTop = console.scrollHeight;
                                }
                            
                                async function manualStart() {
                                    const token = document.getElementById('apiToken').value;
                                    const start = document.getElementById('startDate').value;
                                    const end = document.getElementById('endDate').value;
                                    if (!token) return alert("נא להזין טוקן API");
                                    
                                    addLog("מתחיל סריקה...");
                                    dataStore = { exts: {}, plays: {}, users: {}, daily: {}, totalSec: 0, completed: 0 };
                                    document.getElementById('progBar').style.display = 'block';
                            
                                    const monthKey = start.substring(0, 7);
                                    try {
                                        const res = await fetch(`${API}RenderYMGRFile?token=${token}&wath=ivr2:/Log/LogFolderEnterExit-${monthKey}.ymgr&convertType=json`);
                                        const json = await res.json();
                                        if (json.data) {
                                            json.data.forEach(row => {
                                                const ext = row["שלוחה"] || "ראשי";
                                                const phone = row["טלפון"] || "חסוי";
                                                const sec = parseInt(row["סה\"כ שניות"] || row["שניות"] || 0);
                                                const date = row["תאריך"] || start;
                            
                                                if (!dataStore.exts[ext]) dataStore.exts[ext] = { count: 0, sec: 0, unique: new Set() };
                                                dataStore.exts[ext].count++;
                                                dataStore.exts[ext].sec += sec;
                                                dataStore.exts[ext].unique.add(phone);
                                                trackUser(phone, sec);
                                                dataStore.daily[date] = (dataStore.daily[date] || 0) + 1;
                                                dataStore.totalSec += sec;
                                            });
                                        }
                                    } catch(e) { addLog("לוג כניסות לא נמצא.", "#f59e0b"); }
                            
                                    let days = [];
                                    let dt = new Date(start);
                                    const endDt = new Date(end);
                                    while(dt <= endDt) {
                                        days.push(new Date(dt).toISOString().split('T')[0]);
                                        dt.setDate(dt.getDate() + 1);
                                    }
                            
                                    for (let day of days) {
                                        updateProgress(days.indexOf(day)+1, days.length);
                                        const paths = [`ivr2:/Log/LogPlaybackPlayStop/LogPlaybackPlayStop.${day}.ymgr`,`ivr2:/Log/LogPlaybackPlayStop.${day}.ymgr`,`ivr2:/Log/LogPlayback.${day}.ymgr`];
                                        for (let path of paths) {
                                            try {
                                                const res = await fetch(`${API}RenderYMGRFile?token=${token}&wath=${path}&convertType=json`);
                                                const json = await res.json();
                                                if (json.data && json.data.length > 0) {
                                                    addLog(`יום ${day}: נמצאו נתוני השמעות.`);
                                                    processPlaybackRows(json.data, day);
                                                    break;
                                                }
                                            } catch(e) {}
                                        }
                                    }
                                    renderUI();
                                }
                            
                                function processPlaybackRows(rows, day) {
                                    rows.forEach(row => {
                                        const keys = Object.keys(row);
                                        const extKey = keys.find(k => k.includes("שלוחה") || k.includes("Folder") || k.includes("תיקייה")) || "שלוחה";
                                        const fileKey = keys.find(k => k.includes("קובץ") || k.includes("השמעה") || k.includes("Play")) || keys[0];
                                        const secKey = keys.find(k => k.includes("שניות") || k.includes("זמן") || k.includes("Sec")) || keys[1];
                                        const exitKey = keys.find(k => k.includes("יציאה") || k.includes("Exit")) || "";
                                        const timeKey = keys.find(k => k.includes("שעה") || k.includes("Time")) || "";
                            
                                        const extName = row[extKey] || "לא ידוע";
                                        const fileName = row[fileKey] || "לא ידוע";
                                        const phone = row["טלפון"] || "חסוי";
                                        const sec = parseInt(row[secKey] || 0);
                                        const time = row[timeKey] || "";
                                        const isEnd = (row[exitKey] || "").toString().includes("סוף") || (row[exitKey] || "").toString().toLowerCase() === "end";
                                        
                                        const playId = `${extName}|${fileName}`;
                            
                                        if (!dataStore.plays[playId]) {
                                            dataStore.plays[playId] = { ext: extName, file: fileName, lastPhone: phone, lastTime: `${day} ${time}`, count: 0, sec: 0, ends: 0 };
                                        }
                                        
                                        dataStore.plays[playId].count++;
                                        dataStore.plays[playId].sec += sec;
                                        dataStore.plays[playId].lastPhone = phone;
                                        dataStore.plays[playId].lastTime = `${day} ${time}`;
                                        if (isEnd) dataStore.plays[playId].ends++;
                            
                                        trackUser(phone, sec);
                                        dataStore.daily[day] = (dataStore.daily[day] || 0) + 1;
                                        dataStore.totalSec += sec;
                                        if (isEnd) dataStore.completed++;
                                    });
                                }
                            
                                async function playFile(ext, file) {
                                    const token = document.getElementById('apiToken').value;
                                    const modal = document.getElementById('playerModal');
                                    const player = document.getElementById('audioPlayer');
                                    const errDiv = document.getElementById('playerError');
                                    
                                    errDiv.style.display = 'none';
                                    modal.classList.remove('hidden');
                                    document.getElementById('playerTitle').innerText = `טוען: שלוחה ${ext} | קובץ ${file}`;
                            
                                    let cleanExt = ext.replace('ivr2:', '').replace(/^\//, '');
                                    if (!cleanExt.startsWith('ivr2:')) cleanExt = 'ivr2:/' + cleanExt;
                                    const fileBase = file.padStart(3, '0');
                                    
                                    const formats = ['.wav', '.mp3', '.amr'];
                                    let success = false;
                            
                                    for (const fmt of formats) {
                                        const fullPath = `${cleanExt}/${fileBase}${fmt}`;
                                        const url = `${API}DownloadFile?token=${token}&path=${fullPath}`;
                                        try {
                                            player.src = url;
                                            await player.play();
                                            success = true;
                                            document.getElementById('playerTitle').innerText = `מנגן: ${ext}/${fileBase}${fmt}`;
                                            break;
                                        } catch (e) {}
                                    }
                                    if (!success) errDiv.style.display = 'block';
                                }
                            
                                function closePlayer() {
                                    const modal = document.getElementById('playerModal');
                                    const player = document.getElementById('audioPlayer');
                                    modal.classList.add('hidden');
                                    player.pause();
                                    player.src = "";
                                }
                            
                                function trackUser(p, s) {
                                    if (!dataStore.users[p]) dataStore.users[p] = { sec: 0, count: 0 };
                                    dataStore.users[p].sec += s;
                                    dataStore.users[p].count++;
                                }
                            
                                function sortTable(tableId, colIndex, type) {
                                    const table = document.getElementById(tableId);
                                    const tbody = table.querySelector('tbody');
                                    const rows = Array.from(tbody.querySelectorAll('tr'));
                                    const headers = table.querySelectorAll('th');
                            
                                    if (sortState.tableId === tableId && sortState.colIndex === colIndex) {
                                        sortState.direction = sortState.direction === 'asc' ? 'desc' : 'asc';
                                    } else {
                                        sortState.tableId = tableId;
                                        sortState.colIndex = colIndex;
                                        sortState.direction = 'asc';
                                    }
                            
                                    headers.forEach(th => th.classList.remove('sort-asc', 'sort-desc'));
                                    headers[colIndex].classList.add(sortState.direction === 'asc' ? 'sort-asc' : 'sort-desc');
                            
                                    const sortedRows = rows.sort((a, b) => {
                                        let aVal = a.children[colIndex].innerText;
                                        let bVal = b.children[colIndex].innerText;
                                        if (type === 'number') {
                                            aVal = parseFloat(aVal.replace(/[^0-9.-]+/g, "")) || 0;
                                            bVal = parseFloat(bVal.replace(/[^0-9.-]+/g, "")) || 0;
                                        } else {
                                            aVal = aVal.toLowerCase();
                                            bVal = bVal.toLowerCase();
                                        }
                                        if (aVal < bVal) return sortState.direction === 'asc' ? -1 : 1;
                                        if (aVal > bVal) return sortState.direction === 'asc' ? 1 : -1;
                                        return 0;
                                    });
                            
                                    tbody.innerHTML = '';
                                    sortedRows.forEach(row => tbody.appendChild(row));
                                }
                            
                                function renderUI() {
                                    document.getElementById('progBar').style.display = 'none';
                                    document.getElementById('stat-users').innerText = Object.keys(dataStore.users).length.toLocaleString();
                                    document.getElementById('stat-min').innerText = Math.floor(dataStore.totalSec / 60).toLocaleString();
                                    document.getElementById('stat-comp').innerText = dataStore.completed.toLocaleString();
                                    renderExts(); renderPlays(); renderUsers(); updateChart();
                                }
                            
                                function renderExts() {
                                    const q = document.getElementById('extSearch').value.toLowerCase();
                                    let h = "";
                                    Object.entries(dataStore.exts).forEach(([n, d]) => {
                                        if (n.toLowerCase().includes(q)) {
                                            h += `<tr><td style="color:var(--primary); font-weight:bold">${n}</td><td>${d.count}</td><td>${d.unique.size}</td><td>${(d.sec/60).toFixed(1)}</td><td>${Math.round(d.sec/d.count || 0)} ש'</td></tr>`;
                                        }
                                    });
                                    document.querySelector('#extTable tbody').innerHTML = h;
                                }
                            
                                function renderPlays() {
                                    const q = document.getElementById('playSearch').value.toLowerCase();
                                    let h = "";
                                    Object.values(dataStore.plays).forEach(d => {
                                        if (d.file.toLowerCase().includes(q) || d.ext.toLowerCase().includes(q) || d.lastPhone.includes(q)) {
                                            const pct = Math.round((d.ends/d.count)*100);
                                            h += `<tr>
                                                <td style="font-size:0.75rem; color:#94a3b8">${d.lastTime}</td>
                                                <td style="color:var(--primary)">${d.ext}</td>
                                                <td style="font-weight:bold">${d.file}</td>
                                                <td>${d.lastPhone}</td>
                                                <td>${d.count}</td>
                                                <td>${(d.sec/60).toFixed(1)}</td>
                                                <td>${pct}%</td>
                                                <td><button class="btn-play" onclick="playFile('${d.ext}', '${d.file}')"><i class="fas fa-play"></i></button></td>
                                            </tr>`;
                                        }
                                    });
                                    document.querySelector('#playTable tbody').innerHTML = h || "<tr><td colspan='8' style='text-align:center'>אין נתונים</td></tr>";
                                }
                            
                                function renderUsers() {
                                    const q = document.getElementById('userSearch').value;
                                    let h = "";
                                    Object.entries(dataStore.users).forEach(([p, d]) => {
                                        if (p.includes(q)) {
                                            h += `<tr><td>${p}</td><td>${(d.sec/60).toFixed(1)}</td><td>${d.count}</td><td>מאזין</td></tr>`;
                                        }
                                    });
                                    document.querySelector('#usersTable tbody').innerHTML = h;
                                }
                            
                                function exportTableToCSV(tableId, filename) {
                                    let csv = [];
                                    const rows = document.querySelectorAll(`#${tableId} tr`);
                                    for (let i = 0; i < rows.length; i++) {
                                        let row = [], cols = rows[i].querySelectorAll("td, th");
                                        for (let j = 0; j < cols.length; j++) row.push('"' + cols[j].innerText + '"');
                                        csv.push(row.join(","));
                                    }
                                    const csvFile = new Blob(["\ufeff" + csv.join("\n")], { type: "text/csv" });
                                    const downloadLink = document.createElement("a");
                                    downloadLink.download = `${filename}.csv`;
                                    downloadLink.href = window.URL.createObjectURL(csvFile);
                                    downloadLink.style.display = "none";
                                    document.body.appendChild(downloadLink);
                                    downloadLink.click();
                                }
                            
                                function updateProgress(c, t) { document.getElementById('progress-fill').style.width = (c/t*100) + '%'; }
                                function switchTab(e, id) {
                                    document.querySelectorAll('.tab-content').forEach(c => c.classList.add('hidden'));
                                    document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
                                    document.getElementById(id).classList.remove('hidden');
                                    e.currentTarget.classList.add('active');
                                }
                            
                                function updateChart() {
                                    if (dailyChart) dailyChart.destroy();
                                    const ctx = document.getElementById('dailyChart').getContext('2d');
                                    const labels = Object.keys(dataStore.daily).sort();
                                    dailyChart = new Chart(ctx, {
                                        type: 'line',
                                        data: { labels, datasets: [{ label: 'פעולות', data: labels.map(l => dataStore.daily[l]), borderColor: '#38bdf8', tension: 0.3, fill: true, backgroundColor: 'rgba(56, 189, 248, 0.1)' }] },
                                        options: { scales: { y: { beginAtZero: true } } }
                                    });
                                }
                            
                                window.onload = setDefaultDates;
                            </script>
                            </body>
                            </html>
                            
                            1 תגובה 1 תגובה אחרונה תגובה ציטוט 2
                            • ק מנותק
                              קו המוסיקה @אA
                              נערך לאחרונה על ידי

                              @אA כתב בלמה אין נתונים לקווים? 🤔:

                              @קו המוסיקה
                              אשמח לעוד רעיונות לשידרוג.

                              נראה מטורף
                              אני יעבור על זה ואני יראה אם יהיה לי מה להוסיף,
                              ברגע שאני יתחיל באמת להשתמש בזה, וכל אחד פה,
                              נוכל באמת להגיד מה צריך וכו׳!!
                              אבל תשמע עשית עבודה מטורפת!!!

                              ק תגובה 1 תגובה אחרונה תגובה ציטוט 0
                              • ק קו המוסיקה סימן נושא זה כנושא רגיל
                              • ק מנותק
                                קו המוסיקה @קו המוסיקה
                                נערך לאחרונה על ידי

                                מה ההבדל המעשי בין הקוד הראשוני ש @אa
                                לקוד של @kol ?
                                אשמח לדעת, כי לא כזה הבנתי כזה ההבדל...

                                תגובה 1 תגובה אחרונה תגובה ציטוט 0
                                • 1 מנותק
                                  121244
                                  נערך לאחרונה על ידי

                                  @kol הקוד הנ"ל לא מחזיר לי כלל תוצאות אבל לא הגדרתי את מה שאמרת בivr כי אנינ צריך את הנתונים על לפני כן
                                  אין כזה דבר?

                                  ק תגובה 1 תגובה אחרונה תגובה ציטוט 0
                                  • 1 מנותק
                                    121244 @kol
                                    נערך לאחרונה על ידי

                                    @kol כתב בלמה אין נתונים לקווים? 🤔:

                                    log_playback_play_stop=yes
                                    log_playback_play_stop_ymgr_to_html=yes
                                    log_playback_play_stop_year_save_folder=yes
                                    log_playback_play_stop_year_save_folder_ymgr_to_html=yes
                                    log_playback_play_stop_month_save_root_log=yes
                                    log_playback_play_stop_month_save_root_log_ymgr_to_html=yes

                                    חלק מההגדרות כאן לא קיימות

                                    תגובה 1 תגובה אחרונה תגובה ציטוט 0
                                    • ק מנותק
                                      קו המוסיקה @121244
                                      נערך לאחרונה על ידי

                                      @121244 ככל שידוע לי אם לא הגדרת את זה לפני לא תקבל את הנתונים שהיו,
                                      אם משהו יודע אחרת שיעדכן כי זה רלוונטי בשבילי,
                                      כי אני הגדרתי את זה לפני שעה ועדיין לא מופיעים לי שום נתונים... (והיו מסתומה מאוד מאזינים בשעה האחרונה)

                                      1 תגובה 1 תגובה אחרונה תגובה ציטוט 0
                                      • 1 מנותק
                                        121244 @קו המוסיקה
                                        נערך לאחרונה על ידי

                                        @קו-המוסיקה כפי שאמרתי ההגדרות הנ"ל חלקן לא נכונות
                                        ולגבי זה שצריך להגדיר לפני כן זה מוזר כי יש לי לוגים במערכת מוגדר אצלי בivr

                                        save_listening_data=yes
                                        log_playback_play_stop_month_save_root_log=yes
                                        listening_mark=yes
                                        

                                        וזה מציג בתוצאות 0 בהכל

                                        תגובה 1 תגובה אחרונה תגובה ציטוט 0
                                        • מ מנותק
                                          מוטי מוטי מוטי @אA
                                          נערך לאחרונה על ידי

                                          @אA c843e490-4cfb-44bf-a92f-823f829c508a-image.png
                                          איך זה עובד ההשמעה והנטישה?
                                          יש 17% האזנה ו 29% נטישה מה זה?
                                          תודה,
                                          זה מטורף!
                                          אשכרה, כבר שנים אין כזה דבר...

                                          ק א 2 תגובות תגובה אחרונה תגובה ציטוט 0
                                          • ק מנותק
                                            קו המוסיקה @מוטי מוטי מוטי
                                            נערך לאחרונה על ידי

                                            אוקיי הבנתי מה היה הבעיה שלי,
                                            אני הייתי צריך לפתוח טוקן חדש בשביל זה!!
                                            והנה זה עובד לי עכשיו זה מטוווורף!!!
                                            @אa אין מילים לא האמנתי שכשהעלתי את הנושא פה באמת נגיע למשהו כזה!!!
                                            תודה רבה לכל מי שסייע לזה זה פשוט מגניב ומטורף ומאוד מאוד יעיל!!!!
                                            (וכמובן אם יהיה לי הערות אני יגיד)

                                            1 תגובה 1 תגובה אחרונה תגובה ציטוט 0
                                            • פוסט ראשון
                                              פוסט אחרון