ap_ds ap_ds v4.0.1
ap_ds / code Public
v4.0.1 / docs / index.html
LFV
v4.0.1
index.html 147.8 KB
<!DOCTYPE html>
<!-- saved from url=(0017)https://apds.top/ -->
<html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="msvalidate.01" content="F11795107043E350A88CF68A1AFEAA64">
    
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ap_ds · lightweight Python audio solution</title>
    <!-- Tailwind + Font Awesome -->
    <script src="./index_files/saved_resource"></script>
    <link rel="stylesheet" href="./index_files/font-awesome.min.css">
    <!-- Marked (MD parser) & Prism (syntax highlighting + copy) -->
    <script src="./index_files/marked.min.js"></script>
    <link rel="stylesheet" href="./index_files/prism-tomorrow.min.css">
    <script src="./index_files/prism.min.js"></script>
    <script src="./index_files/prism-python.min.js"></script>
    <script src="./index_files/prism-bash.min.js"></script>
<style>
    body {
        font-family: 'Segoe UI', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
        line-height: 1.7;
        color: #1e293b;
        background: #f9fafc;
        font-size: 16px;
        text-rendering: optimizeLegibility;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
    }

    h1, h2, h3, h4, h5, h6 {
        color: #0f2b4b;
        font-weight: 600;
        line-height: 1.4;
        letter-spacing: -0.01em;
    }

    h1 {
        font-size: 2.5rem;
        margin-bottom: 1rem;
    }

    h2 {
        font-size: 2rem;
        border-bottom: 2px solid #e2e8f0;
        padding-bottom: 0.75rem;
        margin-top: 2rem;
        margin-bottom: 1.5rem;
    }

    h3 {
        font-size: 1.5rem;
        margin-top: 1.5rem;
        margin-bottom: 1rem;
    }

    h4 {
        font-size: 1.25rem;
        margin-top: 1.2rem;
        margin-bottom: 0.8rem;
    }

    p {
        margin-bottom: 1.2rem;
        line-height: 1.7;
    }

    ul, ol {
        margin-bottom: 1.2rem;
        padding-left: 1.8rem;
    }

    li {
        margin-bottom: 0.3rem;
        line-height: 1.6;
    }

    a {
        color: #2563eb;
        text-decoration: none;
        font-weight: 500;
    }

    a:hover {
        text-decoration: underline;
        text-underline-offset: 3px;
    }

    code {
        font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Consolas', monospace;
        font-size: 0.9em;
        background: #f1f5f9;
        padding: 0.2em 0.4em;
        border-radius: 4px;
        color: #2563eb;
    }

    pre {
        font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Consolas', monospace;
        font-size: 0.9rem;
        line-height: 1.6;
    }

    pre code {
        background: none;
        padding: 0;
        color: inherit;
    }

    th {
        font-weight: 600;
        text-align: left;
        padding: 0.75rem 1rem;
        background: #f1f5f9;
    }

    td {
        padding: 0.75rem 1rem;
        border-bottom: 1px solid #e9edf2;
    }

    blockquote {
        border-left: 4px solid #2563eb;
        padding: 0.5rem 0 0.5rem 1.5rem;
        margin: 1.5rem 0;
        background: #f8fafc;
        font-style: italic;
        color: #475569;
    }

    .note, .warning, .success {
        border-radius: 18px;
        padding: 1.2rem 1.8rem;
        margin: 1.5rem 0;
    }

    .note { background: #eef2ff; border-left: 6px solid #3b82f6; }
    .warning { background: #fffbeb; border-left: 6px solid #f59e0b; }
    .success { background: #ecfdf5; border-left: 6px solid #10b981; }

    .markdown-body {
        font-size: 16px;
        line-height: 1.7;
    }

    .markdown-body h1,
    .markdown-body h2,
    .markdown-body h3,
    .markdown-body h4,
    .markdown-body h5,
    .markdown-body h6 {
        color: #0f2b4b;
        font-weight: 600;
        margin-top: 2rem;
        margin-bottom: 1rem;
    }

    .markdown-body h1 { font-size: 2.2rem; border-bottom: 2px solid #e2e8f0; padding-bottom: 0.5rem; }
    .markdown-body h2 { font-size: 1.8rem; border-bottom: 2px solid #e2e8f0; padding-bottom: 0.5rem; }
    .markdown-body h3 { font-size: 1.5rem; }
    .markdown-body h4 { font-size: 1.25rem; }
    .markdown-body h5 { font-size: 1.1rem; }
    .markdown-body h6 { font-size: 1rem; color: #64748b; }

    .markdown-body p {
        margin-bottom: 1.2rem;
        line-height: 1.7;
    }

    .markdown-body ul,
    .markdown-body ol {
        margin-bottom: 1.2rem;
        padding-left: 2rem;
    }

    .markdown-body li {
        margin-bottom: 0.3rem;
    }

    .markdown-body blockquote {
        border-left: 4px solid #2563eb;
        padding: 0.5rem 0 0.5rem 1.5rem;
        margin: 1.5rem 0;
        background: #f8fafc;
        font-style: italic;
        color: #475569;
    }

    .markdown-body code:not(pre code) {
        background: #f1f5f9;
        padding: 0.2rem 0.4rem;
        border-radius: 4px;
        font-size: 0.9em;
        color: #2563eb;
    }

    .markdown-body pre {
        background: #0f172a;
        border-radius: 16px;
        padding: 1.5rem;
        overflow-x: auto;
    }

    .markdown-body pre code {
        background: none;
        padding: 0;
        color: #f8fafc;
    }

    .markdown-body table {
        width: 100%;
        border-collapse: collapse;
        margin: 1.5rem 0;
    }

    .markdown-body th {
        background: #f1f5f9;
        padding: 0.75rem 1rem;
        border: 1px solid #e2e8f0;
    }

    .markdown-body td {
        padding: 0.75rem 1rem;
        border: 1px solid #e2e8f0;
    }

    .markdown-body hr {
        margin: 2rem 0;
        border: 0;
        border-top: 1px solid #e2e8f0;
    }

    .markdown-body img {
        max-width: 100%;
        height: auto;
    }

    .markdown-body strong {
        font-weight: 600;
        color: #0f2b4b;
    }

    .markdown-body em {
        font-style: italic;
    }

    .markdown-body del {
        text-decoration: line-through;
        color: #64748b;
    }

    .container { max-width: 1280px; margin: 0 auto; padding: 2rem 1.5rem; }
    .content-section {
        background: white;
        border-radius: 24px;
        padding: 2rem;
        margin-bottom: 2.5rem;
        box-shadow: 0 8px 20px rgba(0,0,0,0.02), 0 2px 6px rgba(0,20,50,0.05);
        border: 1px solid #f0f2f5;
    }
    .toc {
        background: #f8fafc;
        border-radius: 20px;
        padding: 1.5rem 2rem;
        border-left: 6px solid #2563eb;
    }
    .code-block {
        position: relative;
        background: #0f172a;
        border-radius: 16px;
        margin: 1.5rem 0;
        overflow: hidden;
    }
    .code-block pre {
        margin: 0;
        padding: 1.5rem;
        overflow-x: auto;
        background: transparent !important;
        font-size: 0.9rem;
        line-height: 1.5;
    }
    .copy-btn {
        position: absolute;
        top: 12px;
        right: 16px;
        background: #334155;
        color: #f1f5f9;
        border: none;
        border-radius: 30px;
        padding: 6px 16px;
        font-size: 0.8rem;
        cursor: pointer;
        display: flex;
        align-items: center;
        gap: 6px;
        transition: 0.2s;
        z-index: 10;
        opacity: 0.7;
    }
    .copy-btn:hover {
        opacity: 1;
        background: #475569;
    }
    .copy-btn.copied {
        background: #059669;
        color: white;
    }
    table {
        width: 100%;
        border-collapse: separate;
        border-spacing: 0;
        background: white;
        border-radius: 18px;
        overflow: hidden;
        box-shadow: 0 2px 8px rgba(0,0,0,0.02);
    }
    th { background: #f1f5f9; font-weight: 600; padding: 1rem; }
    td { padding: 1rem; border-bottom: 1px solid #e9edf2; }
    .license-section { background: #f8fafc; border-radius: 24px; padding: 2rem; }
    hr { opacity: 0.2; }
</style>
<style>*, ::before, ::after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/* ! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com */*,::after,::before{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}::after,::before{--tw-content:''}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;font-family:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.mb-10{margin-bottom:2.5rem}.mb-12{margin-bottom:3rem}.mb-2{margin-bottom:0.5rem}.mb-3{margin-bottom:0.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mr-2{margin-right:0.5rem}.mr-3{margin-right:0.75rem}.mt-12{margin-top:3rem}.mt-2{margin-top:0.5rem}.mt-3{margin-top:0.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.mb-5{margin-bottom:1.25rem}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.max-h-60{max-height:15rem}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.columns-2{columns:2}.grid-cols-1{grid-template-columns:repeat(1, minmax(0, 1fr))}.grid-cols-2{grid-template-columns:repeat(2, minmax(0, 1fr))}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:0.5rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.gap-3{gap:0.75rem}.space-y-1 > :not([hidden]) ~ :not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0.25rem * var(--tw-space-y-reverse))}.space-y-2 > :not([hidden]) ~ :not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0.5rem * var(--tw-space-y-reverse))}.space-y-5 > :not([hidden]) ~ :not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.overflow-y-auto{overflow-y:auto}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded{border-radius:0.25rem}.rounded-lg{border-radius:0.5rem}.border{border-width:1px}.border-t{border-top-width:1px}.border-l-4{border-left-width:4px}.border-blue-100{--tw-border-opacity:1;border-color:rgb(219 234 254 / var(--tw-border-opacity, 1))}.border-green-100{--tw-border-opacity:1;border-color:rgb(220 252 231 / var(--tw-border-opacity, 1))}.border-purple-100{--tw-border-opacity:1;border-color:rgb(243 232 255 / var(--tw-border-opacity, 1))}.border-yellow-100{--tw-border-opacity:1;border-color:rgb(254 249 195 / var(--tw-border-opacity, 1))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1))}.border-green-200{--tw-border-opacity:1;border-color:rgb(187 247 208 / var(--tw-border-opacity, 1))}.border-red-200{--tw-border-opacity:1;border-color:rgb(254 202 202 / var(--tw-border-opacity, 1))}.border-red-500{--tw-border-opacity:1;border-color:rgb(239 68 68 / var(--tw-border-opacity, 1))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255 / var(--tw-bg-opacity, 1))}.bg-blue-50\/60{background-color:rgb(239 246 255 / 0.6)}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(220 252 231 / var(--tw-bg-opacity, 1))}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(240 253 244 / var(--tw-bg-opacity, 1))}.bg-green-50\/60{background-color:rgb(240 253 244 / 0.6)}.bg-indigo-100{--tw-bg-opacity:1;background-color:rgb(224 231 255 / var(--tw-bg-opacity, 1))}.bg-purple-50\/60{background-color:rgb(250 245 255 / 0.6)}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226 / var(--tw-bg-opacity, 1))}.bg-yellow-50\/60{background-color:rgb(254 252 232 / 0.6)}.bg-purple-100{--tw-bg-opacity:1;background-color:rgb(243 232 255 / var(--tw-bg-opacity, 1))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-gradient-to-r{background-image:linear-gradient(to right, var(--tw-gradient-stops))}.from-blue-800{--tw-gradient-from:#1e40af var(--tw-gradient-from-position);--tw-gradient-to:rgb(30 64 175 / 0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.to-indigo-700{--tw-gradient-to:#4338ca var(--tw-gradient-to-position)}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.p-3{padding:0.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-2{padding:0.5rem}.px-2{padding-left:0.5rem;padding-right:0.5rem}.py-0\.5{padding-top:0.125rem;padding-bottom:0.125rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-2{padding-top:0.5rem;padding-bottom:0.5rem}.pl-5{padding-left:1.25rem}.pt-8{padding-top:2rem}.text-center{text-align:center}.font-mono{font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:0.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-xs{font-size:0.75rem;line-height:1rem}.font-bold{font-weight:700}.font-semibold{font-weight:600}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.italic{font-style:italic}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.text-blue-700{--tw-text-opacity:1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-green-600{--tw-text-opacity:1;color:rgb(22 163 74 / var(--tw-text-opacity, 1))}.text-indigo-800{--tw-text-opacity:1;color:rgb(55 48 163 / var(--tw-text-opacity, 1))}.text-purple-600{--tw-text-opacity:1;color:rgb(147 51 234 / var(--tw-text-opacity, 1))}.text-yellow-600{--tw-text-opacity:1;color:rgb(202 138 4 / var(--tw-text-opacity, 1))}.text-blue-800{--tw-text-opacity:1;color:rgb(30 64 175 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-green-800{--tw-text-opacity:1;color:rgb(22 101 52 / var(--tw-text-opacity, 1))}.text-purple-800{--tw-text-opacity:1;color:rgb(107 33 168 / var(--tw-text-opacity, 1))}.text-transparent{color:transparent}.text-green-500{--tw-text-opacity:1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-600{--tw-text-opacity:1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.text-red-800{--tw-text-opacity:1;color:rgb(153 27 27 / var(--tw-text-opacity, 1))}.underline{-webkit-text-decoration-line:underline;text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.hover\:underline:hover{-webkit-text-decoration-line:underline;text-decoration-line:underline}@media (min-width: 768px){.md\:grid-cols-2{grid-template-columns:repeat(2, minmax(0, 1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3, minmax(0, 1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4, minmax(0, 1fr))}.md\:text-5xl{font-size:3rem;line-height:1}}@media (min-width: 1024px){.lg\:grid-cols-4{grid-template-columns:repeat(4, minmax(0, 1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3, minmax(0, 1fr))}}</style></head>
<body class="antialiased">
    <div class="container">
        <header class="text-center mb-12" id="dynamic-header">
                <h1 class="text-4xl md:text-5xl font-extrabold mb-4 bg-gradient-to-r from-blue-800 to-indigo-700 bg-clip-text text-transparent">ap_ds: Redefining Lightweight Python Audio Development</h1>
                <h2 class="text-2xl font-semibold text-gray-600">Starting from 2.5MB, ending the era of bloated audio libraries</h2>
                <div class="mt-6 flex flex-wrap justify-center gap-3">
                    <span class="bg-blue-100 text-blue-800 px-5 py-2 rounded-full text-sm font-mono">v2.4.1</span>
                    <span class="bg-green-100 text-green-800 px-5 py-2 rounded-full text-sm">only 2.5MB</span>
                    <span class="bg-purple-100 text-purple-800 px-5 py-2 rounded-full text-sm">cross‑platform W/M/L</span>
                </div>
            </header>

        <div class="toc mb-10">
            <h3 class="text-xl font-bold mb-4 flex items-center"><i class="fa fa-list-ul mr-3 text-blue-600"></i>Contents</h3>
            <ul class="grid grid-cols-2 md:grid-cols-4 gap-2">
                <li><a href="#introduction" class="text-blue-700 hover:underline">1. Introduction</a></li>
                <li><a href="#features" class="text-blue-700 hover:underline">2. Core features</a></li>
                <li><a href="#comparison" class="text-blue-700 hover:underline">3. Technical comparison</a></li>
                <li><a href="#installation" class="text-blue-700 hover:underline">4. Installation &amp; usage</a></li>
                <li><a href="#technical-manual" class="text-blue-700 hover:underline">5. Technical manual</a></li>
                <li><a href="#license" class="text-blue-700 hover:underline">6. Open source license</a></li>
                <li><a href="#faq" class="text-blue-700 hover:underline">7. FAQ</a></li>
                <li><a href="#contact" class="text-blue-700 hover:underline">8. Contact &amp; support</a></li>
            </ul>
        </div>

        <div class="content-section" id="introduction">
                <h2 class="text-2xl font-bold mb-6">1. Introduction</h2>
                
                <div class="bg-red-50 border-l-4 border-red-500 p-5 mb-6 rounded-lg">
                    <h3 class="text-red-800 font-bold text-lg mb-2">⚠️ Important Version Information</h3>
                    <p class="text-red-700 mb-3">Versions v2.2.0 through v2.3.2 contain a serious cross-platform compatibility issue, causing the library to fail on non-Windows operating systems (macOS and Linux). Subsequent versions have fixed this problem.</p>
                    <p class="bg-red-100 p-3 rounded-lg font-medium text-red-800 mb-3">Please immediately run pip install --upgrade ap_ds to upgrade to the latest stable version v2.4.1.</p>
                    <p class="text-red-600 mb-4">We sincerely apologize for the inconvenience caused by earlier versions. We have now ensured the library's integrity and functionality across all supported platforms.</p>
                    
                    <div class="mt-4">
                        <h4 class="font-semibold text-red-800 mb-2">Version status</h4>
                        <div class="grid grid-cols-1 md:grid-cols-2 gap-2 max-h-60 overflow-y-auto">
                            
                                <div class="flex items-center text-sm p-2 bg-white rounded border border-green-200">
                                    <span class="mr-2">✅</span>
                                    <span class="font-mono mr-2">v2.4.1</span>
                                    <span class="text-gray-500 text-xs">2026-03-01</span>
                                    <span class="ml-auto text-xs text-green-500">Current version - Recommended</span>
                                </div>
                            
                                <div class="flex items-center text-sm p-2 bg-white rounded border border-green-200">
                                    <span class="mr-2">✅</span>
                                    <span class="font-mono mr-2">v2.4.0</span>
                                    <span class="text-gray-500 text-xs">2026-03-01</span>
                                    <span class="ml-auto text-xs text-green-500">Safe to use</span>
                                </div>
                            
                                <div class="flex items-center text-sm p-2 bg-white rounded border border-green-200">
                                    <span class="mr-2">✅</span>
                                    <span class="font-mono mr-2">v2.3.6</span>
                                    <span class="text-gray-500 text-xs">2026-02-27</span>
                                    <span class="ml-auto text-xs text-green-500">Documentation update</span>
                                </div>
                            
                                <div class="flex items-center text-sm p-2 bg-white rounded border border-green-200">
                                    <span class="mr-2">✅</span>
                                    <span class="font-mono mr-2">v2.3.5</span>
                                    <span class="text-gray-500 text-xs">2026-02-26</span>
                                    <span class="ml-auto text-xs text-green-500">Embedded verification and fix</span>
                                </div>
                            
                                <div class="flex items-center text-sm p-2 bg-white rounded border border-green-200">
                                    <span class="mr-2">✅</span>
                                    <span class="font-mono mr-2">v2.3.4</span>
                                    <span class="text-gray-500 text-xs">2026-02-10</span>
                                    <span class="ml-auto text-xs text-green-500">Safe to use</span>
                                </div>
                            
                                <div class="flex items-center text-sm p-2 bg-white rounded border border-green-200">
                                    <span class="mr-2">✅</span>
                                    <span class="font-mono mr-2">v2.3.3</span>
                                    <span class="text-gray-500 text-xs">2026-02-09</span>
                                    <span class="ml-auto text-xs text-green-500">First fixed version</span>
                                </div>
                            
                                <div class="flex items-center text-sm p-2 bg-white rounded border border-red-200">
                                    <span class="mr-2">❌</span>
                                    <span class="font-mono mr-2">v2.3.2</span>
                                    <span class="text-gray-500 text-xs">2026-02-09</span>
                                    <span class="ml-auto text-xs text-red-500">Do not use</span>
                                </div>
                            
                                <div class="flex items-center text-sm p-2 bg-white rounded border border-red-200">
                                    <span class="mr-2">❌</span>
                                    <span class="font-mono mr-2">v2.3.1</span>
                                    <span class="text-gray-500 text-xs">2026-02-09</span>
                                    <span class="ml-auto text-xs text-red-500">Do not use</span>
                                </div>
                            
                                <div class="flex items-center text-sm p-2 bg-white rounded border border-red-200">
                                    <span class="mr-2">❌</span>
                                    <span class="font-mono mr-2">v2.3.0</span>
                                    <span class="text-gray-500 text-xs">2026-01-31</span>
                                    <span class="ml-auto text-xs text-red-500">Do not use</span>
                                </div>
                            
                                <div class="flex items-center text-sm p-2 bg-white rounded border border-red-200">
                                    <span class="mr-2">❌</span>
                                    <span class="font-mono mr-2">v2.2.0</span>
                                    <span class="text-gray-500 text-xs">2026-01-19</span>
                                    <span class="ml-auto text-xs text-red-500">Do not use</span>
                                </div>
                            
                        </div>
                    </div>
                    
                </div>
            
                <div class="note mb-5">
                    <p><strong>Official info</strong></p>
                    <p>Project name: ap_ds (v2.4.1)</p>
                    <p>Website: <a href="https://www.apds.top/" class="text-blue-600 underline">https://www.apds.top</a></p>
                    <p>PyPI: <a href="https://pypi.org/project/ap_ds/" class="text-blue-600 underline">https://pypi.org/project/ap_ds/</a></p>
                    <p>Developer: Dvs (DvsXT)</p>
                    <p>Personal page: <a href="https://dvsyun.top/me/dvs" class="text-blue-600 underline">https://dvsyun.top/me/dvs</a></p>
                </div>
                <p class="mb-4"><strong>ap_ds is an ultra-lightweight Python audio library of only 2.5MB, designed for high-quality playback and precise metadata parsing of four major formats: MP3, FLAC, OGG, and WAV. Zero external Python dependencies, with a non-blocking playback architecture that makes GUI applications run smoothly.</strong></p>
                
                <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 my-6">
                    
                        <div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
                            <div class="text-2xl mb-2">⚡</div>
                            <h4 class="font-bold text-lg">Extremely Lightweight</h4>
                            <p class="text-gray-600 text-sm">Complete solution at only 2.5MB (Windows) / 3.36MB (macOS)</p>
                        </div>
                    
                        <div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
                            <div class="text-2xl mb-2">📦</div>
                            <h4 class="font-bold text-lg">Zero Python Dependencies</h4>
                            <p class="text-gray-600 text-sm">Uses only the standard library</p>
                        </div>
                    
                        <div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
                            <div class="text-2xl mb-2">🎯</div>
                            <h4 class="font-bold text-lg">Precise Metadata</h4>
                            <p class="text-gray-600 text-sm">WAV/FLAC 100%, OGG 99.99%, MP3 &gt;98%</p>
                        </div>
                    
                        <div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
                            <div class="text-2xl mb-2">🔄</div>
                            <h4 class="font-bold text-lg">Non-blocking Playback</h4>
                            <p class="text-gray-600 text-sm">Perfectly suited for GUI applications</p>
                        </div>
                    
                        <div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
                            <div class="text-2xl mb-2">🌐</div>
                            <h4 class="font-bold text-lg">Cross-platform Support</h4>
                            <p class="text-gray-600 text-sm">Windows, macOS, Linux, Embedded ARM64</p>
                        </div>
                    
                        <div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
                            <div class="text-2xl mb-2">📝</div>
                            <h4 class="font-bold text-lg">DAP Recording System</h4>
                            <p class="text-gray-600 text-sm">Automatically records playback history, stores only metadata</p>
                        </div>
                    
                </div>
                
                <p class="mb-4">In the 2026 Python ecosystem, a sharp contradiction has haunted developers for nearly two decades: <strong>the irreconcilable gap between completeness and lightweight projects</strong>. When your project needs audio playback, you face a painful choice:</p>
                <div class="warning">
                    Accept a <strong>hundred‑megabyte monster</strong>, sacrificing storage for basic playback? Or choose a <strong>supposedly lightweight but crippled</strong> library, then struggle with progress bars, format support, and metadata?
                </div>
                <p class="mt-4">This is not a choice — it is a <strong>matter of developer dignity</strong>. Today, this ends. Created by Dvs (DvsXT), <strong>ap_ds (v2.4.1)</strong>, released 2026-03-01, is a <strong>precise revolution in Python audio</strong>.</p>
            </div>

        <div class="content-section" id="features">
            <h2 class="text-2xl font-bold mb-6">2. Core features</h2>
            <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-5 mb-8">
                <div class="bg-blue-50/60 p-5 rounded-2xl border border-blue-100"><i class="fa fa-bolt text-blue-600 mr-2"></i><span class="font-bold">Ultra‑light</span> <span class="text-sm">Win 2.5MB · macOS 3.36MB · Linux ready</span></div>
                <div class="bg-green-50/60 p-5 rounded-2xl border border-green-100"><i class="fa fa-music text-green-600 mr-2"></i><span class="font-bold">4 formats</span> MP3/FLAC/OGG/WAV</div>
                <div class="bg-purple-50/60 p-5 rounded-2xl border border-purple-100"><i class="fa fa-tachometer text-purple-600 mr-2"></i><span class="font-bold">Precise metadata</span> WAV/FLAC 100%</div>
                <div class="bg-yellow-50/60 p-5 rounded-2xl border border-yellow-100"><i class="fa fa-play-circle text-yellow-600 mr-2"></i><span class="font-bold">Non‑blocking</span> perfect for GUIs</div>
            </div>
            <div class="grid md:grid-cols-2 gap-8">
                <div>
                    <h3 class="font-bold text-lg mb-2">📦 Size comparison</h3>
                    <ul class="space-y-2">
                        <li>🟢 <strong>ap_ds</strong> Windows: 2.5MB (SDL2.dll 2.1MB + mixer 400KB + py 42KB)</li>
                        <li>🍎 macOS: 3.36MB (SDL2.framework 1.82MB + mixer 1.54MB + py 42KB)</li>
                        <li>🐧 Linux: dynamically linked system SDL2, package ~50KB (needs libsdl2-mixer)</li>
                        <li>🔴 FFmpeg approach: ≥160MB (ffplay+ffprobe)</li>
                        <li>🟡 Pygame + parsing libs: bloated and incomplete</li>
                    </ul>
                </div>
                <div>
                    <h3 class="font-bold text-lg mb-2">⚙️ Why so tiny?</h3>
                    <ul class="list-disc pl-5 space-y-1 text-gray-700">
                        <li>Focused: playback only, no editing/transcoding</li>
                        <li>Built on industrial‑grade SDL2</li>
                        <li>Optimised to the byte</li>
                        <li><span class="bg-indigo-100 text-indigo-800 px-2 py-0.5 rounded-full text-sm">cross‑platform W/M/L</span></li>
                    </ul>
                </div>
            </div>
        </div>

        <div class="content-section" id="comparison">
            <h2 class="text-2xl font-bold mb-6">3. Technical comparison</h2>
            <h3 class="text-xl font-bold mb-3">Chapter 1: Pygame – the "audio handicap" of a game engine</h3>
            <div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token comment"># Pygame's unreliable audio duration</span>
my_sound <span class="token operator">=</span> pygame<span class="token punctuation">.</span>mixer<span class="token punctuation">.</span>Sound<span class="token punctuation">(</span><span class="token string">'my_song.mp3'</span><span class="token punctuation">)</span>
total_length <span class="token operator">=</span> my_sound<span class="token punctuation">.</span>get_length<span class="token punctuation">(</span><span class="token punctuation">)</span>  <span class="token comment"># reliable only for uncompressed WAV!</span></code></pre><button class="copy-btn" onclick="copyCode(this)"><i class="fa fa-clipboard"></i> Copy</button></div>
            <div class="warning">⚠️ Pygame's <code>Sound.get_length()</code> works correctly only for WAV; MP3/OGG/FLAC return nonsense.</div>

            <h3 class="text-xl font-bold mt-8 mb-3">Chapter 2: The FFmpeg suite – 160MB "at least" pain</h3>
            <table><thead><tr><th>Component</th><th>Function</th><th>Size</th><th>Total</th></tr></thead>
            <tbody><tr><td>ffplay.exe</td><td>playback core</td><td>≈80MB</td><td rowspan="2"><strong>≥160MB</strong></td></tr>
            <tr><td>ffprobe.exe</td><td>metadata probe</td><td>≈80MB</td></tr>
            <tr><td>ffmpeg.exe</td><td>converter</td><td>≈80MB</td><td>≥240MB</td></tr>
            </tbody></table>
            <div class="note mt-4">🔍 Truth: three standalone executables, no Python wrapper included.</div>

            <h3 class="text-xl font-bold mt-8 mb-3">Chapter 3: The ap_ds revolution</h3>
            <div class="success p-5">
                <p><strong>Seven technical breakthroughs</strong></p>
                <ol class="list-decimal pl-5 columns-2">
                    <li>✓ 2.5MB solves 160MB problem</li><li>✓ non‑blocking eliminates GUI lag</li>
                    <li>✓ precise progress queries</li><li>✓ zero‑dependency deployment</li>
                    <li>✓ AID multi‑audio management</li><li>✓ SDL2 performance</li>
                    <li>✓ smart C deps cross‑platform</li>
                </ol>
            </div>
        </div>

        <div class="content-section" id="installation">
            <h2 class="text-2xl font-bold mb-6">4. Installation &amp; usage</h2>
            <div class="code-block"><pre class="language-bash" tabindex="0"><code class="language-bash">pip <span class="token function">install</span> ap_ds</code></pre><button class="copy-btn" onclick="copyCode(this)"><i class="fa fa-clipboard"></i> Copy</button></div>
            <h3 class="text-lg font-bold mt-5">Basic example</h3>
            <div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token keyword">from</span> ap_ds <span class="token keyword">import</span> AudioLibrary
lib <span class="token operator">=</span> AudioLibrary<span class="token punctuation">(</span><span class="token punctuation">)</span>
aid <span class="token operator">=</span> lib<span class="token punctuation">.</span>play_from_file<span class="token punctuation">(</span><span class="token string">"music.mp3"</span><span class="token punctuation">)</span>
lib<span class="token punctuation">.</span>pause_audio<span class="token punctuation">(</span>aid<span class="token punctuation">)</span>
lib<span class="token punctuation">.</span>seek_audio<span class="token punctuation">(</span>aid<span class="token punctuation">,</span> <span class="token number">30.5</span><span class="token punctuation">)</span>
duration <span class="token operator">=</span> lib<span class="token punctuation">.</span>stop_audio<span class="token punctuation">(</span>aid<span class="token punctuation">)</span></code></pre><button class="copy-btn" onclick="copyCode(this)"><i class="fa fa-clipboard"></i> Copy</button></div>
            <h3 class="text-lg font-bold mt-5">DAP playlist (v2.3.0+)</h3>
            <div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python">aid1 <span class="token operator">=</span> lib<span class="token punctuation">.</span>play_from_file<span class="token punctuation">(</span><span class="token string">"song1.mp3"</span><span class="token punctuation">)</span>
recordings <span class="token operator">=</span> lib<span class="token punctuation">.</span>get_dap_recordings<span class="token punctuation">(</span><span class="token punctuation">)</span>
lib<span class="token punctuation">.</span>save_dap_to_json<span class="token punctuation">(</span><span class="token string">"my_playlist.ap-ds-dap"</span><span class="token punctuation">)</span></code></pre><button class="copy-btn" onclick="copyCode(this)"><i class="fa fa-clipboard"></i> Copy</button></div>
        </div>

        <div class="content-section" id="technical-manual">
            <h2 class="text-2xl font-bold mb-4">5. Technical manual</h2>
            <div id="md-container-marked" class="markdown-body"><h1>ap_ds: A Lightweight Python Audio Library</h1>
<p><strong>Current Stable Version: v2.4.1 (Released March 1, 2026)</strong></p>
<hr>
<h2>📢 Latest Updates</h2>
<h3>v2.4.1 (March 1, 2026) - Documentation Update</h3>
<ul>
<li>Updated PyPI documentation with complete 2.4.0 feature descriptions</li>
<li>Added detailed examples and environment variable documentation</li>
<li><strong>No code changes</strong> from v2.4.0</li>
</ul>
<h3>v2.4.0 (March 1, 2026) - Audio Effects &amp; Engineering</h3>
<ul>
<li><strong>New fade functions:</strong> <code>fadein_music()</code>, <code>fadein_music_pos()</code>, <code>fadeout_music()</code></li>
<li><strong>State queries:</strong> <code>is_music_playing()</code>, <code>is_music_paused()</code>, <code>get_music_fading()</code></li>
<li><strong>Smart welcome message:</strong> Controllable via <code>AP_DS_HIDE_SUPPORT_PROMPT</code></li>
<li><strong>Centralized version management:</strong> Auto-generated <code>_version.py</code></li>
<li><strong>Robust import system:</strong> Two-layer fallback for all environments</li>
<li>Unified project URL: <strong><a href="https://www.apds.top/">https://www.apds.top</a></strong></li>
</ul>
<hr>
<h2>Installation</h2>
<div class="code-block"><pre class="language-bash" tabindex="0"><code class="language-bash">pip <span class="token function">install</span> ap_ds
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p>To upgrade from an older version:</p>
<div class="code-block"><pre class="language-bash" tabindex="0"><code class="language-bash">pip <span class="token function">install</span> <span class="token parameter variable">--upgrade</span> ap_ds
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<hr>
<h2>Quick Start</h2>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token keyword">from</span> ap_ds <span class="token keyword">import</span> AudioLibrary

<span class="token comment"># Initialize the library</span>
lib <span class="token operator">=</span> AudioLibrary<span class="token punctuation">(</span><span class="token punctuation">)</span>

<span class="token comment"># Play an audio file</span>
aid <span class="token operator">=</span> lib<span class="token punctuation">.</span>play_from_file<span class="token punctuation">(</span><span class="token string">"music/song.mp3"</span><span class="token punctuation">)</span>

<span class="token comment"># Control playback</span>
lib<span class="token punctuation">.</span>pause_audio<span class="token punctuation">(</span>aid<span class="token punctuation">)</span>      <span class="token comment"># Pause</span>
lib<span class="token punctuation">.</span>play_audio<span class="token punctuation">(</span>aid<span class="token punctuation">)</span>       <span class="token comment"># Resume</span>
lib<span class="token punctuation">.</span>seek_audio<span class="token punctuation">(</span>aid<span class="token punctuation">,</span> <span class="token number">30.5</span><span class="token punctuation">)</span> <span class="token comment"># Seek to 30.5 seconds</span>

<span class="token comment"># Stop and get duration played</span>
duration <span class="token operator">=</span> lib<span class="token punctuation">.</span>stop_audio<span class="token punctuation">(</span>aid<span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Played for </span><span class="token interpolation"><span class="token punctuation">{</span>duration<span class="token punctuation">:</span><span class="token format-spec">.2f</span><span class="token punctuation">}</span></span><span class="token string"> seconds"</span></span><span class="token punctuation">)</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<hr>
<h2>DAP Playlist System</h2>
<p>Audio files are automatically recorded to DAP (Dvs Audio Playlist) upon playback:</p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token comment"># Files are automatically recorded</span>
aid1 <span class="token operator">=</span> lib<span class="token punctuation">.</span>play_from_file<span class="token punctuation">(</span><span class="token string">"song1.mp3"</span><span class="token punctuation">)</span>
aid2 <span class="token operator">=</span> lib<span class="token punctuation">.</span>play_from_file<span class="token punctuation">(</span><span class="token string">"song2.ogg"</span><span class="token punctuation">)</span>

<span class="token comment"># Get all recordings</span>
recordings <span class="token operator">=</span> lib<span class="token punctuation">.</span>get_dap_recordings<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Recorded </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token builtin">len</span><span class="token punctuation">(</span>recordings<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string"> files"</span></span><span class="token punctuation">)</span>

<span class="token comment"># Save to JSON</span>
success <span class="token operator">=</span> lib<span class="token punctuation">.</span>save_dap_to_json<span class="token punctuation">(</span><span class="token string">"my_playlist.ap-ds-dap"</span><span class="token punctuation">)</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p>DAP stores only metadata (path, duration, bitrate, channels), not audio data. Memory usage is approximately 150 bytes per recording.</p>
<hr>
<h2>Platform Support</h2>
<h3>Windows</h3>
<ul>
<li>Automatic download of SDL2.dll and SDL2_mixer.dll</li>
<li>No manual configuration required</li>
<li>Supports Windows 7 and later</li>
</ul>
<h3>macOS</h3>
<ul>
<li>Automatic download of SDL2.framework and SDL2_mixer.framework</li>
<li>No manual configuration required</li>
<li>Supports macOS 10.9 and later</li>
</ul>
<h3>Linux</h3>
<p><strong>Intelligent Multi-Layer Import System:</strong></p>
<ol>
<li><strong>System Library Check:</strong> Uses system-installed SDL2 libraries</li>
<li><strong>User Configuration:</strong> Checks saved paths from previous runs</li>
<li><strong>Automatic Installation:</strong> Detects package manager and installs required packages</li>
<li><strong>Interactive Guidance:</strong> Manual options if all else fails</li>
</ol>
<p><strong>Package Manager Support:</strong></p>
<div class="code-block"><pre class="language-bash" tabindex="0"><code class="language-bash"><span class="token comment"># Ubuntu/Debian</span>
<span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> libsdl2-dev libsdl2-mixer-dev

<span class="token comment"># Fedora</span>
<span class="token function">sudo</span> dnf <span class="token function">install</span> SDL2-devel SDL2_mixer-devel

<span class="token comment"># Arch</span>
<span class="token function">sudo</span> pacman <span class="token parameter variable">-S</span> sdl2 sdl2_mixer
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<h3>Embedded ARM64</h3>
<p>Tested on:</p>
<ul>
<li><strong>Orange Pi 4 Pro</strong> (Allwinner A733, 2xA76 + 6xA55 @ 2.0GHz)</li>
<li><strong>Raspberry Pi 5</strong> (BCM2712, 4xA76 @ 2.4GHz)</li>
</ul>
<p>Both run Ubuntu 22.04 with full audio support via 3.5mm output. Memory growth after extensive testing: ~4MB.</p>
<hr>
<h2>Environment Variables</h2>
<h3>WAV Playback Threshold</h3>
<p>Controls whether WAV files use sound effect mode (no seek) or music mode (full seek):</p>
<div class="code-block"><pre class="language-bash" tabindex="0"><code class="language-bash"><span class="token comment"># Set threshold to 10 seconds (default: 6)</span>
<span class="token builtin class-name">export</span> <span class="token assign-left variable">AP_DS_WAV_THRESHOLD</span><span class="token operator">=</span><span class="token number">10</span>

<span class="token comment"># Files &lt; threshold → sound effect mode (no seek)</span>
<span class="token comment"># Files &gt;= threshold → music mode (full seek)</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>Validation Rules:</strong></p>
<ul>
<li>Values &gt;= 30 are reset to 6 (prevents memory issues)</li>
<li>Negative values are reset to 6</li>
<li>Invalid values fall back to default</li>
</ul>
<h3>Linux SDL2 Library Paths</h3>
<p>For custom-compiled SDL2 libraries:</p>
<div class="code-block"><pre class="language-bash" tabindex="0"><code class="language-bash"><span class="token builtin class-name">export</span> <span class="token assign-left variable">AP_DS_SDL2_PATH</span><span class="token operator">=</span>/usr/local/lib/libSDL2.so
<span class="token builtin class-name">export</span> <span class="token assign-left variable">AP_DS_SDL2_MIXER_PATH</span><span class="token operator">=</span>/usr/local/lib/libSDL2_mixer.so
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p>Paths are automatically saved to <code>~/.config/ap_ds/sdl_paths.conf</code> after first use.</p>
<hr>
<h2>SSL Certificate Verification</h2>
<h3>The Problem</h3>
<p>On some older or enterprise-configured systems, you might encounter SSL certificate verification errors during the initial download of SDL2 libraries:</p>
<div class="code-block"><pre><code>SSL certificate verification failed: unable to get local issuer certificate
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>Common Causes:</strong></p>
<ul>
<li>Old Windows systems (7/8) with outdated root certificates</li>
<li>Enterprise networks with proxy servers and custom certificates</li>
<li>Lightweight installations with minimal certificate stores</li>
<li>Incorrect system time</li>
</ul>
<h3>The Solution</h3>
<p>ap_ds implements a <strong>layered download strategy</strong>:</p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token keyword">def</span> <span class="token function">download_with_ssl</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token keyword">try</span><span class="token punctuation">:</span>
        <span class="token comment"># First attempt: Standard SSL verification</span>
        <span class="token keyword">return</span> urllib<span class="token punctuation">.</span>request<span class="token punctuation">.</span>urlopen<span class="token punctuation">(</span>url<span class="token punctuation">)</span>
    <span class="token keyword">except</span> SSL error<span class="token punctuation">:</span>
        <span class="token comment"># Second attempt: Unverified context (compatibility mode)</span>
        <span class="token comment"># Only triggered when standard verification fails</span>
        <span class="token keyword">return</span> download_with_unverified_context<span class="token punctuation">(</span>url<span class="token punctuation">)</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<h3>Security Analysis</h3>
<p><strong>Is this safe? Yes.</strong></p>
<ol>
<li><p><strong>Limited Scope:</strong> Unverified context is ONLY used for downloading two specific DLLs (SDL2 and SDL2_mixer) from official sources.</p>
</li>
<li><p><strong>Fallback Only:</strong> Standard verification is ALWAYS tried first. Unverified mode is only a fallback for legitimate certificate issues.</p>
</li>
<li><p><strong>Limited Capability:</strong> Even if a DLL were tampered with (extremely unlikely), SDL2 libraries are audio renderers with:</p>
<ul>
<li>No network capabilities</li>
<li>No file system access beyond opening audio files</li>
<li>No ability to create processes</li>
<li>No access to system resources beyond audio output</li>
</ul>
</li>
<li><p><strong>Attack Economics:</strong> Creating a functional malicious replacement for SDL2 requires:</p>
<ul>
<li>Complete replication of complex audio functionality</li>
<li>Mimicking normal behavior to avoid detection</li>
<li>Surviving antivirus scanning</li>
<li>Targeting a niche Python audio library</li>
</ul>
<p>The cost dramatically outweighs any potential benefit.</p>
</li>
<li><p><strong>Multi-Layer Protection:</strong> Any malicious behavior would be immediately detected by:</p>
<ul>
<li>Windows Defender / 360 / other antivirus software</li>
<li>User observation (abnormal CPU, network activity)</li>
<li>System-level protections (UAC, sandboxing)</li>
</ul>
</li>
</ol>
<h3>Manual Alternative</h3>
<p>If you have security concerns, manually download the libraries:</p>
<ol>
<li>Download SDL2 and SDL2_mixer from <a href="https://www.libsdl.org/">official libsdl.org</a></li>
<li>Place DLLs in your system PATH or project directory</li>
<li>ap_ds will automatically use existing local libraries instead of downloading</li>
</ol>
<hr>
<h2>API Reference</h2>
<h3>AudioLibrary Class</h3>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python">__init__<span class="token punctuation">(</span>frequency<span class="token operator">=</span><span class="token number">44100</span><span class="token punctuation">,</span> <span class="token builtin">format</span><span class="token operator">=</span>MIX_DEFAULT_FORMAT<span class="token punctuation">,</span> channels<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">,</span> chunksize<span class="token operator">=</span><span class="token number">2048</span><span class="token punctuation">)</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<h3>Core Methods</h3>
<table>
<thead>
<tr>
<th>Method</th>
<th>Description</th>
<th>Return</th>
</tr>
</thead>
<tbody><tr>
<td><code>play_from_file(path, loops=0, start_pos=0.0)</code></td>
<td>Play audio from file</td>
<td>int (AID)</td>
</tr>
<tr>
<td><code>play_from_memory(path, loops=0, start_pos=0.0)</code></td>
<td>Play from cache</td>
<td>int (AID)</td>
</tr>
<tr>
<td><code>new_aid(path)</code></td>
<td>Pre-load audio into memory</td>
<td>int (AID)</td>
</tr>
<tr>
<td><code>pause_audio(aid)</code></td>
<td>Pause playback</td>
<td>None</td>
</tr>
<tr>
<td><code>play_audio(aid)</code></td>
<td>Resume playback</td>
<td>None</td>
</tr>
<tr>
<td><code>stop_audio(aid)</code></td>
<td>Stop and free resources</td>
<td>float (duration)</td>
</tr>
<tr>
<td><code>seek_audio(aid, position)</code></td>
<td>Seek to position (seconds)</td>
<td>None</td>
</tr>
<tr>
<td><code>set_volume(aid, volume)</code></td>
<td>Set volume (0-128)</td>
<td>bool</td>
</tr>
<tr>
<td><code>get_volume(aid)</code></td>
<td>Get current volume</td>
<td>int</td>
</tr>
<tr>
<td><code>get_audio_duration(source, is_file=False)</code></td>
<td>Get duration</td>
<td>int (seconds)</td>
</tr>
<tr>
<td><code>get_audio_metadata(source, is_file=False)</code></td>
<td>Get metadata</td>
<td>Dict or None</td>
</tr>
</tbody></table>
<h3>DAP Methods</h3>
<table>
<thead>
<tr>
<th>Method</th>
<th>Description</th>
<th>Return</th>
</tr>
</thead>
<tbody><tr>
<td><code>save_dap_to_json(path)</code></td>
<td>Save DAP records to JSON</td>
<td>bool</td>
</tr>
<tr>
<td><code>get_dap_recordings()</code></td>
<td>Get all DAP records</td>
<td>List[Dict]</td>
</tr>
<tr>
<td><code>clear_dap_recordings()</code></td>
<td>Clear DAP records</td>
<td>None</td>
</tr>
</tbody></table>
<h2>v2.4.0 &amp; v2.4.1 Release Notes</h2>
<hr>
<h3>🚀 Overview</h3>
<p>Version 2.4.0 marks a significant milestone in ap_ds evolution, introducing <strong>professional audio transitions</strong> and <strong>major engineering improvements</strong> under the hood. v2.4.1 follows immediately with <strong>complete documentation updates</strong> to ensure users can fully leverage the new features.</p>
<table>
<thead>
<tr>
<th>Version</th>
<th>Release Date</th>
<th>Type</th>
<th>Focus</th>
</tr>
</thead>
<tbody><tr>
<td><strong>v2.4.1</strong></td>
<td>March 1, 2026</td>
<td>Documentation</td>
<td>PyPI docs, examples, environment variables</td>
</tr>
<tr>
<td><strong>v2.4.0</strong></td>
<td>March 1, 2026</td>
<td>Feature + Engineering</td>
<td>Fade functions, version management, import system</td>
</tr>
</tbody></table>
<hr>
<h2>✨ What's New in v2.4.0</h2>
<h3>🎵 Audio Effects: Professional Transitions</h3>
<p>The most visible addition is a complete set of <strong>fade in/out functions</strong>, transforming ap_ds from a simple playback library into a tool capable of professional audio transitions.</p>
<h4>New Functions</h4>
<table>
<thead>
<tr>
<th>Function</th>
<th>Description</th>
<th>Parameters</th>
</tr>
</thead>
<tbody><tr>
<td><code>fadein_music(aid, loops=-1, ms=0)</code></td>
<td>Fade in audio over specified milliseconds</td>
<td><code>aid</code>: Audio instance ID<br><code>loops</code>: -1 = infinite, 0 = once, N = N times<br><code>ms</code>: Fade duration in milliseconds</td>
</tr>
<tr>
<td><code>fadein_music_pos(aid, loops=-1, ms=0, position=0.0)</code></td>
<td>Fade in from specific position</td>
<td>Same as above, plus:<br><code>position</code>: Start position in seconds</td>
</tr>
<tr>
<td><code>fadeout_music(ms=0)</code></td>
<td>Fade out currently playing music</td>
<td><code>ms</code>: Fade duration in milliseconds</td>
</tr>
<tr>
<td><code>is_music_playing()</code></td>
<td>Check if music is currently playing</td>
<td>None</td>
</tr>
<tr>
<td><code>is_music_paused()</code></td>
<td>Check if music is paused</td>
<td>None</td>
</tr>
<tr>
<td><code>get_music_fading()</code></td>
<td>Get current fade state</td>
<td>Returns: <code>0</code> (no fade), <code>1</code> (fading out), <code>2</code> (fading in)</td>
</tr>
</tbody></table>
<h4>Usage Examples</h4>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token keyword">from</span> ap_ds <span class="token keyword">import</span> AudioLibrary
<span class="token keyword">import</span> time

lib <span class="token operator">=</span> AudioLibrary<span class="token punctuation">(</span><span class="token punctuation">)</span>

<span class="token comment"># Basic fade in over 2 seconds</span>
aid <span class="token operator">=</span> lib<span class="token punctuation">.</span>play_from_file<span class="token punctuation">(</span><span class="token string">"song.mp3"</span><span class="token punctuation">)</span>
lib<span class="token punctuation">.</span>fadein_music<span class="token punctuation">(</span>aid<span class="token punctuation">,</span> loops<span class="token operator">=</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> ms<span class="token operator">=</span><span class="token number">2000</span><span class="token punctuation">)</span>

<span class="token comment"># Fade in from the 30-second mark</span>
aid2 <span class="token operator">=</span> lib<span class="token punctuation">.</span>play_from_file<span class="token punctuation">(</span><span class="token string">"podcast.mp3"</span><span class="token punctuation">)</span>
lib<span class="token punctuation">.</span>fadein_music_pos<span class="token punctuation">(</span>aid2<span class="token punctuation">,</span> loops<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">,</span> ms<span class="token operator">=</span><span class="token number">1500</span><span class="token punctuation">,</span> position<span class="token operator">=</span><span class="token number">30.0</span><span class="token punctuation">)</span>

<span class="token comment"># Let it play for a while</span>
time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span>

<span class="token comment"># Smooth fade out over 3 seconds</span>
lib<span class="token punctuation">.</span>fadeout_music<span class="token punctuation">(</span>ms<span class="token operator">=</span><span class="token number">3000</span><span class="token punctuation">)</span>

<span class="token comment"># Query states</span>
<span class="token keyword">if</span> lib<span class="token punctuation">.</span>is_music_playing<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"Music is playing"</span><span class="token punctuation">)</span>
    
fade_state <span class="token operator">=</span> lib<span class="token punctuation">.</span>get_music_fading<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> fade_state <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">:</span>  <span class="token comment"># MIX_FADING_OUT</span>
    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"Fading out..."</span><span class="token punctuation">)</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<h4>Underlying SDL2 Implementation</h4>
<p>These functions directly wrap the following SDL2_mixer APIs:</p>
<ul>
<li><code>Mix_FadeInMusic()</code> → <code>fadein_music()</code></li>
<li><code>Mix_FadeInMusicPos()</code> → <code>fadein_music_pos()</code></li>
<li><code>Mix_FadeOutMusic()</code> → <code>fadeout_music()</code></li>
<li><code>Mix_PlayingMusic()</code> → <code>is_music_playing()</code></li>
<li><code>Mix_PausedMusic()</code> → <code>is_music_paused()</code></li>
<li><code>Mix_FadingMusic()</code> → <code>get_music_fading()</code></li>
</ul>
<hr>
<h3>🧠 Engineering Improvements</h3>
<h4>1. Smart Welcome Message</h4>
<p>The startup banner is now cleaner and <strong>user-controllable</strong>:</p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token comment"># Default behavior (shows once when library loads)</span>
<span class="token keyword">import</span> ap_ds  
<span class="token comment"># Output: AP_DS © - Audio Library By DVS v2.4.0 | https://www.apds.top</span>

<span class="token comment"># Silence it completely with environment variable</span>
<span class="token keyword">import</span> os
os<span class="token punctuation">.</span>environ<span class="token punctuation">[</span><span class="token string">'AP_DS_HIDE_SUPPORT_PROMPT'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">'1'</span>
<span class="token keyword">import</span> ap_ds  <span class="token comment"># No output at all</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>Why this matters:</strong></p>
<ul>
<li>Cleaner integration for GUI applications</li>
<li>No unwanted console output in production</li>
<li>Still visible by default for new users</li>
</ul>
<h4>2. Centralized Version Management</h4>
<p>Version is now defined <strong>once</strong> in <code>setup.py</code> and automatically generates <code>_version.py</code>:</p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token comment"># setup.py</span>
VERSION <span class="token operator">=</span> <span class="token string">"2.4.0"</span>

<span class="token keyword">def</span> <span class="token function">write_version_file</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    version_file_path <span class="token operator">=</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token string">"ap_ds"</span><span class="token punctuation">,</span> <span class="token string">"_version.py"</span><span class="token punctuation">)</span>
    <span class="token keyword">with</span> <span class="token builtin">open</span><span class="token punctuation">(</span>version_file_path<span class="token punctuation">,</span> <span class="token string">"w"</span><span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span> <span class="token keyword">as</span> f<span class="token punctuation">:</span>
        f<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f'__version__ = "</span><span class="token interpolation"><span class="token punctuation">{</span>VERSION<span class="token punctuation">}</span></span><span class="token string">"\n'</span></span><span class="token punctuation">)</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>Benefits:</strong></p>
<ul>
<li>Single source of truth for version</li>
<li>No more manual version updates across files</li>
<li>Prevents version mismatch errors</li>
</ul>
<h4>3. Robust Import System</h4>
<p>Two-layer fallback ensures compatibility across <strong>all Python environments</strong>:</p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token comment"># Version import with fallback</span>
<span class="token keyword">try</span><span class="token punctuation">:</span>
    <span class="token keyword">from</span> <span class="token punctuation">.</span>_version <span class="token keyword">import</span> __version__
<span class="token keyword">except</span> ImportError<span class="token punctuation">:</span>
    <span class="token keyword">try</span><span class="token punctuation">:</span>
        <span class="token keyword">from</span> _version <span class="token keyword">import</span> __version__
    <span class="token keyword">except</span> ImportError<span class="token punctuation">:</span>
        __version__ <span class="token operator">=</span> <span class="token string">"unknown"</span>

<span class="token comment"># Core module import with same pattern</span>
<span class="token keyword">try</span><span class="token punctuation">:</span>
    <span class="token keyword">from</span> <span class="token punctuation">.</span>player <span class="token keyword">import</span> <span class="token operator">*</span>
<span class="token keyword">except</span> ImportError<span class="token punctuation">:</span>
    <span class="token keyword">from</span> player <span class="token keyword">import</span> <span class="token operator">*</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>Why this is important:</strong></p>
<ul>
<li>Works in both package and direct script contexts</li>
<li>Handles different Python path configurations</li>
<li>Graceful degradation if version file is missing</li>
</ul>
<h4>4. Unified Project URL</h4>
<p>All project references now point to the central hub: <strong><a href="https://www.apds.top/">https://www.apds.top</a></strong></p>
<p>This consolidates:</p>
<ul>
<li>Documentation</li>
<li>Version history</li>
<li>Contact information</li>
<li>Future announcements</li>
</ul>
<hr>
<h2>📚 v2.4.1: Documentation Update</h2>
<p>While v2.4.0 delivered the code, <strong>v2.4.1 ensures users can actually use it</strong>.</p>
<h3>What Was Updated</h3>
<h4>PyPI Project Description</h4>
<ul>
<li>Complete rewrite to reflect all v2.4.0 features</li>
<li>Clear function descriptions with parameters and return values</li>
<li>Multiple code examples for each new feature</li>
</ul>
<h4>Environment Variable Documentation</h4>
<ul>
<li><code>AP_DS_WAV_THRESHOLD</code> – WAV playback mode threshold (from v2.3.5)</li>
<li><code>AP_DS_HIDE_SUPPORT_PROMPT</code> – Control startup message (new in v2.4.0)</li>
</ul>
<h4>Quick Start Guide Enhancements</h4>
<ul>
<li>Before/after examples showing migration from v2.3.x</li>
<li>Common usage patterns for fade functions</li>
<li>State query integration examples</li>
</ul>
<h4>Version History</h4>
<ul>
<li>Complete changelog from v1.0.0 to v2.4.1</li>
<li>Clear indication of yanked versions</li>
<li>Upgrade recommendations</li>
</ul>
<hr>
<h2>🔧 Environment Variables Reference</h2>
<table>
<thead>
<tr>
<th>Variable</th>
<th>Default</th>
<th>Description</th>
<th>Since</th>
</tr>
</thead>
<tbody><tr>
<td><code>AP_DS_WAV_THRESHOLD</code></td>
<td><code>6</code></td>
<td>WAV threshold in seconds (≥ threshold = music mode with seek support)</td>
<td>v2.3.5</td>
</tr>
<tr>
<td><code>AP_DS_HIDE_SUPPORT_PROMPT</code></td>
<td>not set</td>
<td>Set to <code>1</code> to hide the startup welcome message</td>
<td>v2.4.0</td>
</tr>
</tbody></table>
<hr>
<h2>📦 Migration Guide</h2>
<h3>From v2.3.x to v2.4.x</h3>
<p><strong>No code changes required</strong> – all existing applications continue to work unchanged.</p>
<p>To start using new features:</p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token comment"># Before (v2.3.x)</span>
aid <span class="token operator">=</span> lib<span class="token punctuation">.</span>play_from_file<span class="token punctuation">(</span><span class="token string">"song.mp3"</span><span class="token punctuation">)</span>
time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span>
lib<span class="token punctuation">.</span>stop_audio<span class="token punctuation">(</span>aid<span class="token punctuation">)</span>  <span class="token comment"># Abrupt stop</span>

<span class="token comment"># After (v2.4.0) - Professional!</span>
aid <span class="token operator">=</span> lib<span class="token punctuation">.</span>play_from_file<span class="token punctuation">(</span><span class="token string">"song.mp3"</span><span class="token punctuation">)</span>
time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span>
lib<span class="token punctuation">.</span>fadeout_music<span class="token punctuation">(</span>ms<span class="token operator">=</span><span class="token number">3000</span><span class="token punctuation">)</span>  <span class="token comment"># Smooth exit over 3 seconds</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<h3>Installation</h3>
<div class="code-block"><pre class="language-bash" tabindex="0"><code class="language-bash"><span class="token comment"># Install or upgrade to latest version</span>
pip <span class="token function">install</span> <span class="token parameter variable">--upgrade</span> ap_ds

<span class="token comment"># Verify installation</span>
python <span class="token parameter variable">-c</span> <span class="token string">"import ap_ds; print(ap_ds.__version__)"</span>  <span class="token comment"># Should show 2.4.1</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<hr>
<h2>⚡ Performance &amp; Compatibility</h2>
<table>
<thead>
<tr>
<th>Metric</th>
<th>Value</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Package Size</strong></td>
<td>Windows: 2.5MB / macOS: 3.36MB / Linux: depends on system SDL2</td>
</tr>
<tr>
<td><strong>Memory Growth</strong></td>
<td>~4MB after extensive testing</td>
</tr>
<tr>
<td><strong>Python Support</strong></td>
<td>3.7+ (all versions)</td>
</tr>
<tr>
<td><strong>Platform Support</strong></td>
<td>Windows, macOS, Linux (x86_64, ARM64)</td>
</tr>
<tr>
<td><strong>API Compatibility</strong></td>
<td>100% backward compatible with v2.3.x</td>
</tr>
</tbody></table>
<hr>
<h2>🎯 Summary</h2>
<p><strong>v2.4.0 transforms ap_ds from a "playback library" into a professional audio tool:</strong></p>
<ul>
<li>✅ Smooth audio transitions (fade in/out)</li>
<li>✅ Complete state querying</li>
<li>✅ Cleaner, more professional startup</li>
<li>✅ Industrial-strength version management</li>
<li>✅ Bulletproof import system</li>
</ul>
<p><strong>v2.4.1 ensures every user can fully leverage these features:</strong></p>
<ul>
<li>✅ Comprehensive PyPI documentation</li>
<li>✅ Detailed code examples</li>
<li>✅ Clear environment variable documentation</li>
</ul>
<p><strong>All while maintaining the core promise:</strong> lightweight, zero external Python dependencies, and true cross-platform compatibility.</p>
<hr>
<h3>Metadata Format</h3>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token punctuation">{</span>
    <span class="token string">'format'</span><span class="token punctuation">:</span> <span class="token string">'MP3'</span><span class="token punctuation">,</span>           <span class="token comment"># File format</span>
    <span class="token string">'duration'</span><span class="token punctuation">:</span> <span class="token number">240</span><span class="token punctuation">,</span>            <span class="token comment"># Duration in seconds</span>
    <span class="token string">'sample_rate'</span><span class="token punctuation">:</span> <span class="token number">44100</span><span class="token punctuation">,</span>       <span class="token comment"># Sample rate in Hz</span>
    <span class="token string">'channels'</span><span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span>              <span class="token comment"># Number of channels</span>
    <span class="token string">'bitrate'</span><span class="token punctuation">:</span> <span class="token number">320000</span>           <span class="token comment"># Bitrate in bps</span>
<span class="token punctuation">}</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<h3>DAP Record Format</h3>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token punctuation">{</span>
    <span class="token string">'path'</span><span class="token punctuation">:</span> <span class="token string">'/Music/song.mp3'</span><span class="token punctuation">,</span>  <span class="token comment"># File path</span>
    <span class="token string">'duration'</span><span class="token punctuation">:</span> <span class="token number">240</span><span class="token punctuation">,</span>             <span class="token comment"># Duration in seconds</span>
    <span class="token string">'bitrate'</span><span class="token punctuation">:</span> <span class="token number">320000</span><span class="token punctuation">,</span>           <span class="token comment"># Bitrate in bps</span>
    <span class="token string">'channels'</span><span class="token punctuation">:</span> <span class="token number">2</span>                <span class="token comment"># Number of channels</span>
<span class="token punctuation">}</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<hr>
<h2>Complete Examples</h2>
<h3>Get Audio Metadata</h3>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token keyword">from</span> ap_ds <span class="token keyword">import</span> get_audio_parser

parser <span class="token operator">=</span> get_audio_parser<span class="token punctuation">(</span><span class="token punctuation">)</span>
metadata <span class="token operator">=</span> parser<span class="token punctuation">.</span>get_audio_metadata<span class="token punctuation">(</span><span class="token string">"song.mp3"</span><span class="token punctuation">)</span>

<span class="token keyword">if</span> metadata<span class="token punctuation">:</span>
    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Format: </span><span class="token interpolation"><span class="token punctuation">{</span>metadata<span class="token punctuation">[</span><span class="token string">'format'</span><span class="token punctuation">]</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Duration: </span><span class="token interpolation"><span class="token punctuation">{</span>metadata<span class="token punctuation">[</span><span class="token string">'duration'</span><span class="token punctuation">]</span><span class="token punctuation">}</span></span><span class="token string"> seconds"</span></span><span class="token punctuation">)</span>
    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Sample Rate: </span><span class="token interpolation"><span class="token punctuation">{</span>metadata<span class="token punctuation">[</span><span class="token string">'sample_rate'</span><span class="token punctuation">]</span><span class="token punctuation">}</span></span><span class="token string">Hz"</span></span><span class="token punctuation">)</span>
    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Channels: </span><span class="token interpolation"><span class="token punctuation">{</span>metadata<span class="token punctuation">[</span><span class="token string">'channels'</span><span class="token punctuation">]</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Bitrate: </span><span class="token interpolation"><span class="token punctuation">{</span>metadata<span class="token punctuation">[</span><span class="token string">'bitrate'</span><span class="token punctuation">]</span><span class="token punctuation">}</span></span><span class="token string">bps"</span></span><span class="token punctuation">)</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<h3>Advanced Playback Control</h3>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token comment"># Pre-load audio files</span>
effect <span class="token operator">=</span> lib<span class="token punctuation">.</span>new_aid<span class="token punctuation">(</span><span class="token string">"sound.wav"</span><span class="token punctuation">)</span>
music <span class="token operator">=</span> lib<span class="token punctuation">.</span>new_aid<span class="token punctuation">(</span><span class="token string">"track.flac"</span><span class="token punctuation">)</span>

<span class="token comment"># Play from memory (instant start)</span>
lib<span class="token punctuation">.</span>play_audio<span class="token punctuation">(</span>effect<span class="token punctuation">)</span>

<span class="token comment"># Volume control</span>
lib<span class="token punctuation">.</span>set_volume<span class="token punctuation">(</span>effect<span class="token punctuation">,</span> <span class="token number">80</span><span class="token punctuation">)</span>
current <span class="token operator">=</span> lib<span class="token punctuation">.</span>get_volume<span class="token punctuation">(</span>effect<span class="token punctuation">)</span>

<span class="token comment"># Get duration for progress bar</span>
duration <span class="token operator">=</span> lib<span class="token punctuation">.</span>get_audio_duration<span class="token punctuation">(</span>effect<span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Duration: </span><span class="token interpolation"><span class="token punctuation">{</span>duration<span class="token punctuation">}</span></span><span class="token string">s"</span></span><span class="token punctuation">)</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<h3>Listening Habit Analyzer</h3>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token keyword">import</span> json

<span class="token keyword">class</span> <span class="token class-name">ListeningAnalyzer</span><span class="token punctuation">:</span>
    <span class="token keyword">def</span> <span class="token function">analyze</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> dap_path<span class="token punctuation">)</span><span class="token punctuation">:</span>
        <span class="token keyword">with</span> <span class="token builtin">open</span><span class="token punctuation">(</span>dap_path<span class="token punctuation">,</span> <span class="token string">'r'</span><span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">'utf-8'</span><span class="token punctuation">)</span> <span class="token keyword">as</span> f<span class="token punctuation">:</span>
            records <span class="token operator">=</span> json<span class="token punctuation">.</span>load<span class="token punctuation">(</span>f<span class="token punctuation">)</span>
        
        total_seconds <span class="token operator">=</span> <span class="token builtin">sum</span><span class="token punctuation">(</span>r<span class="token punctuation">[</span><span class="token string">'duration'</span><span class="token punctuation">]</span> <span class="token keyword">for</span> r <span class="token keyword">in</span> records<span class="token punctuation">)</span>
        hours <span class="token operator">=</span> total_seconds <span class="token operator">//</span> <span class="token number">3600</span>
        
        bitrate_stats <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
        <span class="token keyword">for</span> r <span class="token keyword">in</span> records<span class="token punctuation">:</span>
            bitrate_stats<span class="token punctuation">[</span>r<span class="token punctuation">[</span><span class="token string">'bitrate'</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">=</span> bitrate_stats<span class="token punctuation">.</span>get<span class="token punctuation">(</span>r<span class="token punctuation">[</span><span class="token string">'bitrate'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span>
        
        <span class="token keyword">return</span> <span class="token punctuation">{</span>
            <span class="token string">"total_songs"</span><span class="token punctuation">:</span> <span class="token builtin">len</span><span class="token punctuation">(</span>records<span class="token punctuation">)</span><span class="token punctuation">,</span>
            <span class="token string">"total_hours"</span><span class="token punctuation">:</span> hours<span class="token punctuation">,</span>
            <span class="token string">"bitrate_distribution"</span><span class="token punctuation">:</span> bitrate_stats
        <span class="token punctuation">}</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<h3>Cross-Platform Player</h3>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token keyword">import</span> platform
<span class="token keyword">from</span> ap_ds <span class="token keyword">import</span> AudioLibrary

<span class="token keyword">class</span> <span class="token class-name">Player</span><span class="token punctuation">:</span>
    <span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span>
        self<span class="token punctuation">.</span>lib <span class="token operator">=</span> AudioLibrary<span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Running on </span><span class="token interpolation"><span class="token punctuation">{</span>platform<span class="token punctuation">.</span>system<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
    
    <span class="token keyword">def</span> <span class="token function">play</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> path<span class="token punctuation">)</span><span class="token punctuation">:</span>
        <span class="token keyword">try</span><span class="token punctuation">:</span>
            aid <span class="token operator">=</span> self<span class="token punctuation">.</span>lib<span class="token punctuation">.</span>play_from_file<span class="token punctuation">(</span>path<span class="token punctuation">)</span>
            <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Playing: </span><span class="token interpolation"><span class="token punctuation">{</span>path<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
            <span class="token keyword">return</span> aid
        <span class="token keyword">except</span> Exception <span class="token keyword">as</span> e<span class="token punctuation">:</span>
            <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Error: </span><span class="token interpolation"><span class="token punctuation">{</span>e<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
            <span class="token keyword">return</span> <span class="token boolean">None</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<hr>
<h2>Format Support and Precision</h2>
<table>
<thead>
<tr>
<th align="left">Format</th>
<th align="center">Playback</th>
<th align="center">Duration Precision</th>
<th align="left">Metadata</th>
</tr>
</thead>
<tbody><tr>
<td align="left"><strong>MP3</strong></td>
<td align="center">✅ Full</td>
<td align="center">&gt;98%</td>
<td align="left">Sample Rate, Bitrate</td>
</tr>
<tr>
<td align="left"><strong>FLAC</strong></td>
<td align="center">✅ Full</td>
<td align="center">100%</td>
<td align="left">All Metadata</td>
</tr>
<tr>
<td align="left"><strong>OGG</strong></td>
<td align="center">✅ Full</td>
<td align="center">99.99%</td>
<td align="left">All Metadata</td>
</tr>
<tr>
<td align="left"><strong>WAV</strong></td>
<td align="center">✅ Full</td>
<td align="center">100%</td>
<td align="left">All Metadata</td>
</tr>
</tbody></table>
<hr>
<h2>Size Comparison</h2>
<table>
<thead>
<tr>
<th>Solution</th>
<th>Size</th>
<th>Ratio</th>
</tr>
</thead>
<tbody><tr>
<td><strong>ap_ds (Windows)</strong></td>
<td>2.5 MB</td>
<td>1x</td>
</tr>
<tr>
<td><strong>ap_ds (macOS)</strong></td>
<td>3.36 MB</td>
<td>1.34x</td>
</tr>
<tr>
<td><strong>FFmpeg-based</strong></td>
<td>160+ MB</td>
<td>64x</td>
</tr>
<tr>
<td><strong>Pygame + parsers</strong></td>
<td>50+ MB</td>
<td>20x</td>
</tr>
</tbody></table>
<p><strong>Breakdown:</strong></p>
<ul>
<li>SDL2.dll: 2.1 MB</li>
<li>SDL2_mixer.dll: 400 KB</li>
<li>Python code: 42 KB</li>
<li><strong>Total: 2.5 MB</strong></li>
</ul>
<hr>
<h2>Frequently Asked Questions</h2>
<h3>Can I use this in commercial products?</h3>
<p>Yes, absolutely. The license explicitly permits any commercial use, including integration into commercial products, cloud services, and SaaS platforms, completely free of charge. You must comply with the attribution requirements.</p>
<h3>Why is it so small?</h3>
<p>ap_ds focuses precisely on playback and parsing for the four most common formats, avoiding the bloat of editing/transcoding features. It's built on the efficient SDL2 C library and is meticulously optimized.</p>
<h3>How accurate is MP3 parsing?</h3>
<p>MP3 duration parsing is &gt;98% accurate. This is due to the format's variable header complexities. For WAV and FLAC we guarantee 100% accuracy, and for OGG 99.99%.</p>
<h3>Does it work on embedded devices?</h3>
<p>Yes! ap_ds includes testing on Orange Pi 4 Pro and Raspberry Pi 5 (ARM64) running Ubuntu 22.04. Memory growth is minimal (~4MB after extensive testing).</p>
<h3>What are the system requirements?</h3>
<ul>
<li><strong>Windows:</strong> Windows 7+, Python 3.7+</li>
<li><strong>macOS:</strong> macOS 10.9+, Python 3.7+</li>
<li><strong>Linux:</strong> Modern distributions, Python 3.7+, SDL2 libraries</li>
<li><strong>Embedded:</strong> ARM64 devices with Ubuntu 22.04 or similar</li>
</ul>
<h3>How do I configure the WAV threshold?</h3>
<p>Set the environment variable:</p>
<div class="code-block"><pre class="language-bash" tabindex="0"><code class="language-bash"><span class="token comment"># Linux/macOS</span>
<span class="token builtin class-name">export</span> <span class="token assign-left variable">AP_DS_WAV_THRESHOLD</span><span class="token operator">=</span><span class="token number">10</span>

<span class="token comment"># Windows Command Prompt</span>
<span class="token builtin class-name">set</span> <span class="token assign-left variable">AP_DS_WAV_THRESHOLD</span><span class="token operator">=</span><span class="token number">10</span>

<span class="token comment"># Windows PowerShell</span>
<span class="token variable">$env</span>:AP_DS_WAV_THRESHOLD<span class="token operator">=</span><span class="token number">10</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<h3>Is the SSL fallback safe?</h3>
<p>Yes. It only activates when standard verification fails, only downloads two specific audio libraries, and those libraries have extremely limited capabilities. See the SSL Certificate Verification section for detailed analysis.</p>
<hr>
<h2>Technical Architecture</h2>
<h3>Core Components</h3>
<div class="code-block"><pre><code>ap_ds/
├── player.py          # Main player logic, platform abstraction
├── audio_parser.py    # Metadata parsing
├── audio_info.py      # Format-specific parsers
└── __init__.py        # Package initialization
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<h3>AID Management System</h3>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python">self<span class="token punctuation">.</span>_audio_cache <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>      <span class="token comment"># path -&gt; Mix_Chunk</span>
self<span class="token punctuation">.</span>_music_cache <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>      <span class="token comment"># path -&gt; Mix_Music</span>
self<span class="token punctuation">.</span>_channel_info <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>     <span class="token comment"># channel ID -&gt; playback info</span>
self<span class="token punctuation">.</span>_aid_to_filepath <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>  <span class="token comment"># AID -&gt; path</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<h3>DAP Memory Layout</h3>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python">self<span class="token punctuation">.</span>_dap_recordings <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>  <span class="token comment"># List of record dicts</span>
<span class="token comment"># Memory: ~150 bytes per record</span>
<span class="token comment"># 10,000 records → ~1.5 MB RAM</span>
<span class="token comment"># 10,000 records → ~2-3 MB JSON file</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<hr>
<h2>Version History</h2>
<h3>v1.0.0 (July 8, 2025) - Initial Release</h3>
<p><strong>Milestone:</strong> Project birth, foundational functionality</p>
<p><strong>Core Features:</strong></p>
<ul>
<li>Basic audio playback: MP3, WAV, FLAC, OGG formats</li>
<li>Playback control: Play, Pause, Stop, Seek basic APIs</li>
<li>Volume control support</li>
<li>Lightweight design: Initial version ~2MB</li>
</ul>
<p><strong>Technical Characteristics:</strong></p>
<ul>
<li>SDL2-based audio processing</li>
<li>Pure Python encapsulation, no complex dependencies</li>
<li>Clean API design</li>
</ul>
<hr>
<h3>v2.0.0 (November 5, 2025) - Architecture Refactoring</h3>
<p><strong>Milestone:</strong> Introduction of modern audio management system</p>
<p><strong>Major Improvements:</strong></p>
<ul>
<li><strong>AID System:</strong> Audio ID for unified audio instance management</li>
<li><strong>Architecture Refactoring:</strong> Modular design for improved maintainability</li>
<li><strong>Smart Memory Management:</strong> Automatic cleanup of unused audio resources</li>
<li><strong>Metadata Parser:</strong> First introduction of comprehensive metadata extraction</li>
<li><strong>State Management:</strong> Unified playback state tracking</li>
</ul>
<p><strong>Technical Upgrades:</strong></p>
<ul>
<li>Introduction of AudioLibrary class as core manager</li>
<li>Audio instance lifecycle management</li>
<li>Error handling and recovery mechanisms</li>
</ul>
<hr>
<h3>v2.1.0 (December 26, 2025) - Feature Enhancement</h3>
<p><strong>Milestone:</strong> Professional functionality expansion</p>
<p><strong>New Features:</strong></p>
<ul>
<li><strong>Metadata Enhancement:</strong> More precise audio information parsing (improved from v2.0.0)</li>
<li><strong>Playback Accuracy Improvement:</strong> Better time control and seeking</li>
<li>Extended format compatibility</li>
</ul>
<p><strong>Optimization Improvements:</strong></p>
<ul>
<li>Enhanced audio format compatibility</li>
<li>Optimized memory usage efficiency</li>
<li>More user-friendly API interface</li>
</ul>
<hr>
<h3>v2.1.4 (January 18, 2026) - Stable Version</h3>
<p><strong>Milestone:</strong> Production environment stable release</p>
<p><strong>Version Highlights:</strong></p>
<ul>
<li>Core Stability: Thoroughly tested with no known critical bugs</li>
<li>Extreme Lightweight: Complete solution at only 2.5MB</li>
<li>Pain Point Resolution: Fills Python audio development gap</li>
<li>Complete Documentation: Detailed technical manual and examples</li>
</ul>
<p><strong>Market Positioning:</strong> "2.5MB Windows Python Audio Solution"</p>
<p><strong>Technical Specifications Size Analysis:</strong></p>
<div class="code-block"><pre><code>├── SDL2.dll: 2.1MB
├── SDL2_mixer.dll: 400KB
└── Python Code: 42KB
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>Comparison Advantages:</strong></p>
<div class="code-block"><pre><code>├── FFmpeg Solution: At least 160MB (64x larger!)
├── Pygame Solution: Bloated with incomplete features
└── ap_ds: 2.5MB perfect solution ✓
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<hr>
<h3>v2.2.0 (January 19, 2026) - Cross-Platform Revolution</h3>
<p><strong>Milestone:</strong> From single-platform to cross-platform</p>
<p><strong>Major New Features:</strong></p>
<ol>
<li><p><strong>Complete macOS Support</strong></p>
<ul>
<li>Automatic download and installation of SDL2.framework, SDL2_mixer.framework</li>
<li>Smart .dmg file extraction and framework loading</li>
<li>Maintains extreme lightweight: Only 3.36MB (vs 2.5MB Windows version)</li>
<li>Cross-platform unified API, code requires no modification</li>
</ul>
</li>
<li><p><strong>Enhanced Automatic Dependency Management</strong></p>
<ul>
<li>Cross-platform intelligent download strategy:<ul>
<li>Windows: Automatic .dll download</li>
<li>macOS: Automatic .framework download and extraction</li>
</ul>
</li>
<li>Complete error handling and retry mechanisms</li>
<li>Dependency file local caching to avoid repeated downloads</li>
</ul>
</li>
<li><p><strong>Strengthened Platform Position Statement</strong></p>
<ul>
<li>Explicit Linux non-support with detailed technical reasoning</li>
<li>Professional rejection strategy and alternative solution suggestions</li>
<li>Focus on serving real user needs (Windows/macOS developers)</li>
</ul>
</li>
</ol>
<p><strong>Performance &amp; Optimization Size Control Breakthrough:</strong></p>
<p><strong>Windows Version: 2.5MB</strong></p>
<div class="code-block"><pre><code>├── SDL2.dll: 2.1MB
├── SDL2_mixer.dll: 400KB
└── Python Code: 42KB
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>macOS Version: 3.36MB</strong></p>
<div class="code-block"><pre><code>├── SDL2.framework: 1.82MB
├── SDL2_mixer.framework: 1.54MB
└── Python Code: 42KB
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>Comparison with Traditional Solutions:</strong></p>
<div class="code-block"><pre><code>├── FFmpeg Solution: At least 160MB (47x larger than ap_ds!)
├── Pygame + Parser Libraries: Bloated with incomplete features
└── ap_ds: 3.36MB complete solution ✓
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>Loading Performance Optimization:</strong></p>
<ul>
<li>First load: Automatic dependency download</li>
<li>Subsequent loads: Use local cache</li>
<li>Cross-platform loading logic unified and efficient</li>
</ul>
<p><strong>Technical Architecture Improvements - Cross-Platform Loading System:</strong></p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token keyword">def</span> <span class="token function">import_sdl2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token triple-quoted-string string">"""Intelligent SDL2 library loading (Windows/macOS)"""</span>
    <span class="token keyword">if</span> platform <span class="token operator">==</span> <span class="token string">"win32"</span><span class="token punctuation">:</span>
        <span class="token comment"># Load .dll</span>
    <span class="token keyword">elif</span> platform <span class="token operator">==</span> <span class="token string">"darwin"</span><span class="token punctuation">:</span>
        <span class="token comment"># Load .framework</span>
    <span class="token keyword">else</span><span class="token punctuation">:</span>
        <span class="token comment"># Explicitly reject unsupported platforms</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>Enhanced Error Handling:</strong></p>
<ul>
<li>More user-friendly error messages</li>
<li>Detailed troubleshooting suggestions</li>
<li>Intelligent environment detection and problem diagnosis</li>
</ul>
<p><strong>Documentation &amp; Examples Update:</strong></p>
<ul>
<li>Windows Installation: <code>pip install ap_ds</code> (fully automatic)</li>
<li>macOS Installation: <code>pip install ap_ds</code> (fully automatic, requires network download)</li>
<li>Linux: Clear explanation of non-support reasons and alternatives</li>
</ul>
<p><strong>Design Philosophy Reiteration:</strong></p>
<ul>
<li>Audio playback only, no editing/transcoding</li>
<li>Serves real needs: Python desktop application developers</li>
<li>Willingness to say no: No Linux support, no AAC support</li>
</ul>
<p><strong>Market Positioning Upgrade:</strong></p>
<ul>
<li>From: "2.5MB Windows Python Audio Solution"</li>
<li>To: "3.36MB Cross-Platform Python Audio Solution"</li>
</ul>
<hr>
<h3>v2.3.0 (January 31, 2026) - DAP Recording System</h3>
<p><strong>Milestone:</strong> From playback to memory, introducing audio playback history recording system</p>
<p>DAP (Dvs Audio Playlist) is a major functional extension of the ap_ds library, providing developers with a complete solution for audio playback history recording. This is not a traditional playlist manager, but a lightweight system focused on recording and memory.</p>
<p><strong>Core Characteristics:</strong></p>
<ol>
<li><p><strong>Intelligent Automatic Recording</strong></p>
<ul>
<li>Seamless integration: Automatically triggered in <code>play_from_file()</code>, <code>play_from_memory()</code></li>
<li>Precise timing: Records only during actual playback, avoiding misoperations</li>
<li>Complete metadata: Records path, duration, bitrate, channel count, and other key information</li>
</ul>
</li>
<li><p><strong>Lightweight Design Philosophy</strong></p>
<ul>
<li>Metadata only: No audio data storage, maintaining extremely low memory usage</li>
<li>Intelligent deduplication: Automatically avoids duplicate records of the same file</li>
<li>On-demand persistence: Runtime memory storage, explicit call required for file saving</li>
</ul>
</li>
<li><p><strong>Standardized File Format</strong></p>
<ul>
<li>Dedicated extension: <code>.ap-ds-dap</code> ensures format recognition</li>
<li>Standard JSON: Easy parsing, editing, and exchange</li>
<li>Format validation: Enforced extension, ensuring data integrity</li>
</ul>
</li>
</ol>
<p><strong>New API Details</strong></p>
<p><strong>DAP Recording Function List</strong></p>
<ol>
<li><p><strong><code>_add_to_dap_recordings(file_path: str) -&gt; None</code></strong></p>
<ul>
<li>Function: Add audio file metadata to memory record list</li>
<li>Characteristics:<ul>
<li>Internal use only (automatically triggered via playback methods)</li>
<li>Automatic audio metadata extraction (duration, bitrate, channel count)</li>
<li>Intelligent deduplication mechanism</li>
<li>Standardized recording format</li>
</ul>
</li>
<li>Usage Example:<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token comment"># Automatically triggered via playback</span>
lib<span class="token punctuation">.</span>play_from_file<span class="token punctuation">(</span><span class="token string">"song.mp3"</span><span class="token punctuation">)</span>  <span class="token comment"># Automatically recorded to DAP</span>
<span class="token comment"># Log output: Recorded DAP file: song.mp3</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
</li>
</ul>
</li>
<li><p><strong><code>save_dap_to_json(save_path: str) -&gt; bool</code></strong></p>
<ul>
<li>Function: Save DAP records from memory to JSON file</li>
<li>Mandatory Requirements:<ul>
<li>File extension must be <code>.ap-ds-dap</code></li>
<li>UTF-8 encoding for multilingual compatibility</li>
<li>Pretty JSON format (2-space indentation)</li>
</ul>
</li>
<li>Return Value:<ul>
<li><code>True</code>: Save successful</li>
<li><code>False</code>: Save failed (error logged)</li>
</ul>
</li>
<li>Error Handling:<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token keyword">try</span><span class="token punctuation">:</span>
    success <span class="token operator">=</span> lib<span class="token punctuation">.</span>save_dap_to_json<span class="token punctuation">(</span><span class="token string">"history.ap-ds-dap"</span><span class="token punctuation">)</span>
<span class="token keyword">except</span> ValueError <span class="token keyword">as</span> e<span class="token punctuation">:</span>
    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Format error: </span><span class="token interpolation"><span class="token punctuation">{</span>e<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>  <span class="token comment"># Extension doesn't meet requirements</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
</li>
</ul>
</li>
<li><p><strong><code>get_dap_recordings() -&gt; List[Dict]</code></strong></p>
<ul>
<li>Function: Get deep copy of all current DAP records</li>
<li>Data Format:<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token punctuation">[</span>
  <span class="token punctuation">{</span>
    <span class="token string">"path"</span><span class="token punctuation">:</span> <span class="token string">"/music/song1.mp3"</span><span class="token punctuation">,</span>
    <span class="token string">"duration"</span><span class="token punctuation">:</span> <span class="token number">240</span><span class="token punctuation">,</span>
    <span class="token string">"bitrate"</span><span class="token punctuation">:</span> <span class="token number">320000</span><span class="token punctuation">,</span>
    <span class="token string">"channels"</span><span class="token punctuation">:</span> <span class="token number">2</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">]</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
</li>
<li>Usage Scenarios:<ul>
<li>Display playback history statistics</li>
<li>Export to other formats</li>
<li>Custom interface display</li>
</ul>
</li>
</ul>
</li>
<li><p><strong><code>clear_dap_recordings() -&gt; None</code></strong></p>
<ul>
<li>Function: Clear all DAP records from memory</li>
<li>Characteristics:<ul>
<li>Irreversible operation (unless already saved)</li>
<li>Clear operation logging</li>
<li>Immediate memory release</li>
</ul>
</li>
</ul>
</li>
</ol>
<p><strong>Technical Architecture Design</strong></p>
<p><strong>Workflow:</strong></p>
<div class="code-block"><pre><code>User plays audio
    ↓
Calls play_from_file()
    ↓
Automatically calls _add_to_dap_recordings()
    ↓
Extracts metadata via get_audio_metadata_by_path()
    ↓
Creates standardized record
    ↓
Adds to _dap_recordings list
    ↓
Intelligent deduplication check
    ↓
Stores in memory
    ↓
User optionally calls save_dap_to_json()
    ↓
Extension validation → JSON serialization → File saving
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>Memory Management Design:</strong></p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token keyword">class</span> <span class="token class-name">AudioLibrary</span><span class="token punctuation">:</span>
    <span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span>
        <span class="token comment"># DAP memory storage</span>
        self<span class="token punctuation">.</span>_dap_recordings <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>  <span class="token comment"># List[Dict]</span>
        
        <span class="token comment"># Approximate memory usage per record:</span>
        <span class="token comment"># path: ~100 bytes</span>
        <span class="token comment"># metadata: ~50 bytes</span>
        <span class="token comment"># total: ~150 bytes/record</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>Performance Characteristics:</strong></p>
<ul>
<li>Record operation: O(1) complexity (adding new records)</li>
<li>Deduplication check: O(n) complexity (linear check)</li>
<li>Memory usage: ~1.5MB per 10,000 records</li>
<li>File size: ~2-3MB per 10,000 records (JSON format)</li>
</ul>
<hr>
<h3>v2.3.1 (February 9, 2026) - Documentation Update</h3>
<p><strong>Milestone:</strong> Improved documentation and minor fixes</p>
<p><strong>Changes:</strong></p>
<ul>
<li>Updated README.md with better examples and explanations</li>
<li>Minor bug fixes in documentation examples</li>
<li>Improved error messages for common usage scenarios</li>
<li>Enhanced installation instructions for different platforms</li>
</ul>
<hr>
<h3>v2.3.2 (February 9, 2026) - Linux Support Enhancement</h3>
<p><strong>Milestone:</strong> Extended Linux support with interactive setup</p>
<p><strong>Major New Features:</strong></p>
<ol>
<li><p><strong>Interactive Linux Support</strong></p>
<ul>
<li>Three options for Linux users:<ol>
<li>Use system-installed libraries (via package manager)</li>
<li>Specify paths to compiled .so files</li>
<li>Get detailed compilation instructions</li>
</ol>
</li>
<li>Smart platform detection and guidance</li>
<li>Unified API across all platforms</li>
</ul>
</li>
<li><p><strong>Enhanced Cross-Platform Compatibility</strong></p>
<ul>
<li>Windows: Full auto-download support for SDL2 libraries</li>
<li>macOS: Full auto-download support for SDL2 frameworks</li>
<li>Linux: Interactive setup with user guidance</li>
</ul>
</li>
<li><p><strong>Improved User Experience</strong></p>
<ul>
<li>Clear platform-specific installation guidance</li>
<li>Better error handling for library loading failures</li>
<li>Enhanced troubleshooting documentation</li>
</ul>
</li>
</ol>
<p><strong>Technical Implementation:</strong></p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token keyword">def</span> <span class="token function">import_sdl2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token triple-quoted-string string">"""Main function: Import SDL2 libraries with cross-platform support"""</span>
    platform <span class="token operator">=</span> sys<span class="token punctuation">.</span>platform
    
    <span class="token keyword">if</span> platform <span class="token operator">==</span> <span class="token string">"win32"</span><span class="token punctuation">:</span>
        <span class="token comment"># Windows - auto-download and load .dll</span>
    <span class="token keyword">elif</span> platform <span class="token operator">==</span> <span class="token string">"darwin"</span><span class="token punctuation">:</span>
        <span class="token comment"># macOS - auto-download and load .framework</span>
    <span class="token keyword">elif</span> platform<span class="token punctuation">.</span>startswith<span class="token punctuation">(</span><span class="token string">"linux"</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
        <span class="token comment"># Linux - interactive setup with options:</span>
        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"Linux SDL2 Library Loading"</span><span class="token punctuation">)</span>
        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"Options:"</span><span class="token punctuation">)</span>
        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"1. Use system-installed libraries (if available)"</span><span class="token punctuation">)</span>
        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"2. Specify path to your compiled .so files"</span><span class="token punctuation">)</span>
        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"3. Get compilation instructions"</span><span class="token punctuation">)</span>
        <span class="token comment"># User interaction and library loading</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>Market Positioning Upgrade:</strong></p>
<ul>
<li>From: "3.36MB Cross-Platform Python Audio Solution"</li>
<li>To: "Complete Cross-Platform Python Audio Solution (Windows, macOS, Linux)"</li>
</ul>
<p><strong>Performance &amp; Optimization:</strong></p>
<ul>
<li>Maintains lightweight design across all platforms</li>
<li>Intelligent dependency management for each platform</li>
<li>Consistent API experience regardless of platform</li>
</ul>
<p><strong>Backward Compatibility:</strong></p>
<ul>
<li>All existing code continues to work unchanged</li>
<li>New Linux support doesn't affect Windows/macOS users</li>
<li>DAP system fully functional on all platforms</li>
</ul>
<hr>
<h3>v2.3.3 (February 9, 2026) - Critical Bug Fix &amp; Platform Stabilization</h3>
<p>🚨 <strong>This is a critical update that fixes a major bug. Previous versions (2.2.0, 2.3.0, 2.3.1, 2.3.2) have been yanked from PyPI due to this issue. Please upgrade immediately.</strong></p>
<p><strong>Critical Fix:</strong></p>
<ul>
<li><strong>Resolved Cross-Platform Crash:</strong> Fixed a critical segmentation fault bug that prevented the library from functioning on macOS and Linux. The issue was caused by missing C function prototypes (ctypes argtypes/restype) on non-Windows platforms.</li>
<li><strong>Root Cause:</strong> In earlier versions, the platform-specific code only defined essential C function bindings (prototypes) for Windows (win32), causing memory access violations on other operating systems.</li>
<li><strong>Solution:</strong> The library now unconditionally defines all necessary C function bindings immediately after loading the SDL2 libraries, regardless of the operating system. This ensures stable and safe calls across Windows, macOS, and Linux.</li>
</ul>
<p><strong>Enhanced Stability &amp; Integrity:</strong></p>
<ul>
<li>Guaranteed Functionality: The core promise—<code>pip install ap_ds</code> followed by functional playback and parsing—is now reliably fulfilled on all three major platforms.</li>
<li>Validated Workflow: The existing, user-friendly platform-handling logic (auto-download for Windows/macOS, interactive guidance for Linux) has been fully stabilized and verified end-to-end.</li>
</ul>
<p><strong>What This Means for You:</strong></p>
<ul>
<li>For All Users: If you are using any version prior to 2.3.3, you are affected. Please run <code>pip install --upgrade ap_ds</code> now.</li>
<li>For Linux/macOS Users: The library will now work correctly. The interactive Linux setup (choosing system libraries, specifying paths, or getting compilation help) functions as intended.</li>
<li>For Windows Users: While you may not have experienced crashes, upgrading is essential to stay on the supported, stable release.</li>
</ul>
<p><strong>Technical Summary:</strong><br>This patch (2.3.2 → 2.3.3) is a PATCH-level version change under Semantic Versioning, signifying a backward-compatible bug fix that resolves incorrect behavior. The core API, features, and user experience remain unchanged and now operate reliably everywhere.</p>
<p><strong>Maintainer's Note:</strong> We sincerely apologize for the disruption. Upholding stability and a professional standard for all users is our top priority. Version 2.3.3 represents that commitment.</p>
<hr>
<h3>v2.3.4 (February 10, 2026) - Linux Intelligent Import System</h3>
<p>🚀 <strong>This update revolutionizes Linux support with an intelligent, multi-layer import system that dramatically improves user experience.</strong></p>
<p><strong>Intelligent Linux Import System</strong></p>
<p><strong>Four-Layer Fallback Strategy:</strong> Implements a sophisticated, progressive library discovery system:</p>
<ol>
<li><strong>System Library Check:</strong> First attempts to use system-installed SDL2 libraries via standard library paths</li>
<li><strong>User Configuration:</strong> Checks for user-saved library paths from previous successful configurations</li>
<li><strong>Automatic Installation:</strong> Intelligently detects package manager and attempts non-interactive installation</li>
<li><strong>Interactive Guidance:</strong> Only presents manual options when all automatic methods fail</li>
</ol>
<p><strong>Package Manager Detection &amp; Auto-Install:</strong></p>
<ul>
<li><strong>Ubuntu/Debian:</strong> Auto-detects <code>apt-get</code> and installs <code>libsdl2-dev libsdl2_mixer-dev</code></li>
<li><strong>Fedora:</strong> Auto-detects <code>dnf</code> and installs <code>SDL2-devel SDL2_mixer-devel</code></li>
<li><strong>Arch:</strong> Auto-detects <code>pacman</code> and installs <code>sdl2 sdl2_mixer</code></li>
<li>All installations use non-interactive mode (<code>-y</code>/<code>--noconfirm</code>) for seamless setup</li>
</ul>
<p><strong>Configuration Persistence &amp; Smart Memory:</strong></p>
<ul>
<li><strong>Automatic Path Saving:</strong> User-specified library paths are automatically saved to both:<ul>
<li>Environment variables (<code>AP_DS_SDL2_PATH</code>, <code>AP_DS_SDL2_MIXER_PATH</code>)</li>
<li>Persistent config file (<code>~/.config/ap_ds/sdl_paths.conf</code>)</li>
</ul>
</li>
<li><strong>One-Time Setup:</strong> Linux users only need to configure paths once; subsequent runs use saved configurations automatically</li>
<li><strong>Configuration Validation:</strong> Saved paths are validated before use to ensure libraries are still accessible</li>
</ul>
<p><strong>Enhanced User Experience:</strong></p>
<ul>
<li><strong>Reduced User Interaction:</strong> Most users will experience automatic setup without any manual input</li>
<li><strong>Clear Progress Feedback:</strong> Real-time status updates during each layer of the discovery process</li>
<li><strong>Intelligent Fallback:</strong> System gracefully degrades through each layer, always providing the next-best option</li>
</ul>
<p><strong>Technical Implementation Highlights:</strong></p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token keyword">def</span> <span class="token function">import_sdl2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token triple-quoted-string string">"""Intelligent multi-layer SDL2 import system"""</span>
    <span class="token keyword">if</span> platform<span class="token punctuation">.</span>startswith<span class="token punctuation">(</span><span class="token string">"linux"</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
        <span class="token comment"># Layer 1: System library check</span>
        <span class="token keyword">if</span> find_system_libraries<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
            <span class="token keyword">return</span> load_from_system<span class="token punctuation">(</span><span class="token punctuation">)</span>
        
        <span class="token comment"># Layer 2: User-configured paths</span>
        <span class="token keyword">if</span> check_user_config<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
            <span class="token keyword">return</span> load_from_user_config<span class="token punctuation">(</span><span class="token punctuation">)</span>
        
        <span class="token comment"># Layer 3: Automatic package manager installation</span>
        <span class="token keyword">if</span> try_auto_install<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
            <span class="token keyword">return</span> load_from_newly_installed<span class="token punctuation">(</span><span class="token punctuation">)</span>
        
        <span class="token comment"># Layer 4: Interactive guidance (only if all else fails)</span>
        <span class="token keyword">return</span> interactive_setup_and_save<span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>Platform-Specific Improvements:</strong></p>
<ul>
<li><strong>Windows/macOS:</strong> Unchanged - continue with seamless auto-download functionality</li>
<li><strong>Linux:</strong> Transformed from manual setup to intelligent automatic configuration</li>
<li><strong>All Platforms:</strong> Consistent API experience with zero changes to user code</li>
</ul>
<p><strong>Performance &amp; Stability:</strong></p>
<ul>
<li><strong>Faster First-Time Setup:</strong> Linux users experience dramatically reduced setup time</li>
<li><strong>Reduced Error Rates:</strong> Intelligent validation prevents common configuration mistakes</li>
<li><strong>Enhanced Reliability:</strong> Multi-layer approach ensures maximum compatibility across diverse Linux distributions</li>
</ul>
<p><strong>What This Means for You:</strong></p>
<ul>
<li><strong>For New Linux Users:</strong> Installation is now as simple as Windows/macOS - <code>pip install ap_ds</code> followed by automatic setup in most cases</li>
<li><strong>For Existing Linux Users:</strong> Your saved configurations continue to work; new users benefit from the intelligent system</li>
<li><strong>For All Users:</strong> The library maintains its lightweight design (still under 4MB) while gaining sophisticated platform intelligence</li>
</ul>
<hr>
<h3>v2.3.5 (February 26, 2026) - Stability Optimization &amp; Embedded Validation</h3>
<p><strong>Stability &amp; Testing</strong></p>
<p><strong>Six-Dimension Test Coverage:</strong></p>
<ol>
<li><p><strong>Library Loading &amp; Initialization</strong></p>
<ul>
<li>Cross-platform SDL2 loading validation</li>
<li>Network failure, file corruption, permission error recovery</li>
<li>AudioLibrary parameter verification</li>
<li>Default settings validation across devices</li>
</ul>
</li>
<li><p><strong>Playback Testing</strong></p>
<ul>
<li>MP3, FLAC, OGG, WAV format validation</li>
<li>Variable bitrate and non-standard file handling</li>
<li>Non-blocking playback verification</li>
<li>Concurrent audio playback testing</li>
</ul>
</li>
<li><p><strong>Seek Testing</strong></p>
<ul>
<li>Precision validation across formats</li>
<li>Boundary condition testing (start, end, beyond duration)</li>
<li>Seek during paused/stopped states</li>
</ul>
</li>
<li><p><strong>Memory Pressure &amp; Leak Detection</strong></p>
<ul>
<li>Long-duration playback monitoring</li>
<li>Repeated load/unload cycles</li>
<li>Cache behavior validation</li>
<li><strong>Result:</strong> ~4MB growth after extensive testing</li>
</ul>
</li>
<li><p><strong>Metadata Parsing Accuracy</strong></p>
<ul>
<li>Sample collection from diverse sources</li>
<li>Edge case analysis</li>
<li>Format-specific parser validation</li>
</ul>
</li>
<li><p><strong>DAP System Validation</strong></p>
<ul>
<li>Automatic recording verification</li>
<li>Save/load reliability</li>
<li>Memory cleanup on clear</li>
</ul>
</li>
</ol>
<p><strong>Embedded Platform Support</strong></p>
<p><strong>Tested Environments:</strong></p>
<table>
<thead>
<tr>
<th>Platform</th>
<th>SoC</th>
<th>Cores</th>
<th>RAM</th>
<th>OS</th>
<th>Audio Output</th>
</tr>
</thead>
<tbody><tr>
<td>Orange Pi 4 Pro</td>
<td>Allwinner A733</td>
<td>2xA76 + 6xA55 @ 2.0GHz</td>
<td>8GB LPDDR5</td>
<td>Ubuntu 22.04 ARM64</td>
<td>3.5mm → TPA3116D2 @ 2×8Ω 5W</td>
</tr>
<tr>
<td>Raspberry Pi 5</td>
<td>BCM2712</td>
<td>4xA76 @ 2.4GHz</td>
<td>8GB LPDDR4X</td>
<td>Ubuntu 22.04 ARM64</td>
<td>3.5mm → TPA3116D2 @ 2×8Ω 5W</td>
</tr>
</tbody></table>
<p><strong>Results:</strong></p>
<ul>
<li>Intelligent package management: Working normally</li>
<li>Audio output: Normal via 3.5mm</li>
<li>AID management system: Working normally</li>
<li>Memory growth: ~4MB after comprehensive testing</li>
</ul>
<p><strong>Important Note:</strong> ap_ds is a wrapper library. Low-level concerns (power optimization, I2S/HDMI/ALSA output, fine-grained memory management) are handled by SDL2 and the operating system. Python's language nature limits fine resource control. We have tested and confirmed functionality; no embedded-specific optimizations are planned as they fall outside our scope.</p>
<p><strong>Bug Fixes</strong></p>
<p><strong>WAV Playback Mode Selection</strong></p>
<p>Fixed an issue where WAV files were incorrectly treated as sound effects, preventing seek operations.</p>
<p><strong>New Logic:</strong></p>
<ul>
<li>Files &lt; threshold (default 6s) → Sound effect mode (no seek)</li>
<li>Files &gt;= threshold → Music mode (full seek support)</li>
<li>Configurable via <code>AP_DS_WAV_THRESHOLD</code> environment variable</li>
</ul>
<p><strong>Validation:</strong></p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python">WAV_THRESHOLD <span class="token operator">=</span> <span class="token builtin">int</span><span class="token punctuation">(</span>os<span class="token punctuation">.</span>environ<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'AP_DS_WAV_THRESHOLD'</span><span class="token punctuation">,</span> <span class="token string">'6'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> WAV_THRESHOLD <span class="token operator">&gt;=</span> <span class="token number">30</span><span class="token punctuation">:</span>  <span class="token comment"># Reset to default to prevent memory issues</span>
    WAV_THRESHOLD <span class="token operator">=</span> <span class="token number">6</span>
<span class="token keyword">elif</span> WAV_THRESHOLD <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">:</span>
    WAV_THRESHOLD <span class="token operator">=</span> <span class="token number">6</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>Error Message Decision</strong></p>
<p><strong>Design Decision: Keep Existing Simple Error Format</strong></p>
<p><strong>Proposed Change Rejected:</strong> Structured error messages with causes and suggestions were considered but rejected.</p>
<p><strong>Reasons:</strong></p>
<ol>
<li><p><strong>Limited Help for Complex Errors</strong></p>
<ul>
<li>Simple errors are easy to debug</li>
<li>Complex errors cannot be accurately diagnosed by the library</li>
<li>LLM integration for error analysis was considered but rejected due to cost and security concerns</li>
</ul>
</li>
<li><p><strong>Target Users Are Developers</strong></p>
<ul>
<li>Developers can read error messages</li>
<li>Beginners can ask ChatGPT or search engines</li>
<li>Pre-written suggestions add little value</li>
</ul>
</li>
<li><p><strong>Maintenance Burden</strong></p>
<ul>
<li>Modifying all error paths is time-consuming</li>
<li>High risk of introducing new bugs</li>
<li>Existing format works: <code>raise RuntimeError(f"Failed to load: {file_path}")</code></li>
</ul>
</li>
</ol>
<p><strong>Final Decision:</strong> Maintain existing simple exception format with clear error messages.</p>
<p><strong>SSL Certificate Issue: R12 Certificate Compatibility</strong></p>
<p><strong>Problem:</strong> On some Windows systems, R12 certificates cause verification failures during SDL2 download.</p>
<p><strong>Solution Implemented:</strong></p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token keyword">def</span> <span class="token function">download_with_ssl</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token keyword">try</span><span class="token punctuation">:</span>
        <span class="token comment"># First attempt: Standard SSL verification</span>
        <span class="token keyword">return</span> urllib<span class="token punctuation">.</span>request<span class="token punctuation">.</span>urlopen<span class="token punctuation">(</span>url<span class="token punctuation">)</span>
    <span class="token keyword">except</span> <span class="token punctuation">(</span>URLError<span class="token punctuation">,</span> SSLError<span class="token punctuation">)</span> <span class="token keyword">as</span> e<span class="token punctuation">:</span>
        <span class="token comment"># Fallback: Unverified context</span>
        ssl_context <span class="token operator">=</span> ssl<span class="token punctuation">.</span>create_default_context<span class="token punctuation">(</span><span class="token punctuation">)</span>
        ssl_context<span class="token punctuation">.</span>check_hostname <span class="token operator">=</span> <span class="token boolean">False</span>
        ssl_context<span class="token punctuation">.</span>verify_mode <span class="token operator">=</span> ssl<span class="token punctuation">.</span>CERT_NONE
        opener <span class="token operator">=</span> urllib<span class="token punctuation">.</span>request<span class="token punctuation">.</span>build_opener<span class="token punctuation">(</span>
            urllib<span class="token punctuation">.</span>request<span class="token punctuation">.</span>HTTPSHandler<span class="token punctuation">(</span>context<span class="token operator">=</span>ssl_context<span class="token punctuation">)</span>
        <span class="token punctuation">)</span>
        urllib<span class="token punctuation">.</span>request<span class="token punctuation">.</span>install_opener<span class="token punctuation">(</span>opener<span class="token punctuation">)</span>
        <span class="token keyword">return</span> urllib<span class="token punctuation">.</span>request<span class="token punctuation">.</span>urlopen<span class="token punctuation">(</span>url<span class="token punctuation">)</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>Security Rationale:</strong></p>
<ul>
<li>Standard verification ALWAYS tried first</li>
<li>Fallback only activates when legitimate certificate issues prevent installation</li>
<li>Downloaded files are standard SDL2 libraries with limited capabilities</li>
<li>Any malicious behavior would be detected by antivirus software</li>
</ul>
<hr>
<h3>v2.3.6 (February 27, 2026) - Documentation Update</h3>
<p>This version updates the PyPi documentation, adding detailed license information and version history, and adding more examples.</p>
<hr>
<h3>v2.4.0 (March 1, 2026) - Audio Effects &amp; Engineering Improvements</h3>
<p><strong>✅ This version introduces professional audio transitions and significant internal engineering upgrades.</strong></p>
<hr>
<h4>🎵 New Audio Control Features</h4>
<p><strong>Fade In/Out Functions:</strong></p>
<table>
<thead>
<tr>
<th>Function</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><code>fadein_music(aid, loops=-1, ms=0)</code></td>
<td>Fade in music over specified milliseconds</td>
</tr>
<tr>
<td><code>fadein_music_pos(aid, loops=-1, ms=0, position=0.0)</code></td>
<td>Fade in from specific position</td>
</tr>
<tr>
<td><code>fadeout_music(ms=0)</code></td>
<td>Fade out currently playing music</td>
</tr>
<tr>
<td><code>is_music_playing()</code></td>
<td>Check if music is currently playing</td>
</tr>
<tr>
<td><code>is_music_paused()</code></td>
<td>Check if music is paused</td>
</tr>
<tr>
<td><code>get_music_fading()</code></td>
<td>Get current fade state (fading in/out/none)</td>
</tr>
</tbody></table>
<p><strong>Implementation Details:</strong></p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token comment"># Fade in over 2 seconds</span>
aid <span class="token operator">=</span> lib<span class="token punctuation">.</span>play_from_file<span class="token punctuation">(</span><span class="token string">"song.mp3"</span><span class="token punctuation">)</span>
lib<span class="token punctuation">.</span>fadein_music<span class="token punctuation">(</span>aid<span class="token punctuation">,</span> loops<span class="token operator">=</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> ms<span class="token operator">=</span><span class="token number">2000</span><span class="token punctuation">)</span>

<span class="token comment"># Fade in from 30-second mark</span>
lib<span class="token punctuation">.</span>fadein_music_pos<span class="token punctuation">(</span>aid<span class="token punctuation">,</span> loops<span class="token operator">=</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> ms<span class="token operator">=</span><span class="token number">1500</span><span class="token punctuation">,</span> position<span class="token operator">=</span><span class="token number">30.0</span><span class="token punctuation">)</span>

<span class="token comment"># Fade out over 3 seconds</span>
lib<span class="token punctuation">.</span>fadeout_music<span class="token punctuation">(</span>ms<span class="token operator">=</span><span class="token number">3000</span><span class="token punctuation">)</span>

<span class="token comment"># Check states</span>
<span class="token keyword">if</span> lib<span class="token punctuation">.</span>is_music_playing<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"Music is playing"</span><span class="token punctuation">)</span>
    
fade_state <span class="token operator">=</span> lib<span class="token punctuation">.</span>get_music_fading<span class="token punctuation">(</span><span class="token punctuation">)</span>  <span class="token comment"># Returns MIX_NO_FADING, MIX_FADING_OUT, MIX_FADING_IN</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>Underlying SDL2 Functions:</strong></p>
<ul>
<li><code>Mix_FadeInMusic()</code> - Basic fade in</li>
<li><code>Mix_FadeInMusicPos()</code> - Positioned fade in  </li>
<li><code>Mix_FadeOutMusic()</code> - Fade out</li>
<li><code>Mix_PlayingMusic()</code> - Play state check</li>
<li><code>Mix_PausedMusic()</code> - Pause state check</li>
<li><code>Mix_FadingMusic()</code> - Fade state query</li>
</ul>
<hr>
<h4>🧠 Engineering Improvements</h4>
<p><strong>1. Smart Welcome Message</strong></p>
<p>The startup banner is now cleaner and user-controllable:</p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token comment"># Default behavior (shows once)</span>
<span class="token keyword">import</span> ap_ds  <span class="token comment"># Prints: AP_DS © - Audio Library By DVS v2.4.0 | https://www.apds.top</span>

<span class="token comment"># Silence it with environment variable</span>
<span class="token keyword">import</span> os
os<span class="token punctuation">.</span>environ<span class="token punctuation">[</span><span class="token string">'AP_DS_HIDE_SUPPORT_PROMPT'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">'1'</span>
<span class="token keyword">import</span> ap_ds  <span class="token comment"># No output</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>2. Centralized Version Management</strong></p>
<p>Version is now defined once in <code>setup.py</code> and automatically generates <code>_version.py</code>:</p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token comment"># setup.py</span>
VERSION <span class="token operator">=</span> <span class="token string">"2.4.0"</span>

<span class="token keyword">def</span> <span class="token function">write_version_file</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    version_file_path <span class="token operator">=</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token string">"ap_ds"</span><span class="token punctuation">,</span> <span class="token string">"_version.py"</span><span class="token punctuation">)</span>
    <span class="token keyword">with</span> <span class="token builtin">open</span><span class="token punctuation">(</span>version_file_path<span class="token punctuation">,</span> <span class="token string">"w"</span><span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span> <span class="token keyword">as</span> f<span class="token punctuation">:</span>
        f<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f'__version__ = "</span><span class="token interpolation"><span class="token punctuation">{</span>VERSION<span class="token punctuation">}</span></span><span class="token string">"\n'</span></span><span class="token punctuation">)</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>3. Robust Import System</strong></p>
<p>Two-layer fallback ensures compatibility across all Python environments:</p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token keyword">try</span><span class="token punctuation">:</span>
    <span class="token keyword">from</span> <span class="token punctuation">.</span>_version <span class="token keyword">import</span> __version__
<span class="token keyword">except</span> ImportError<span class="token punctuation">:</span>
    <span class="token keyword">try</span><span class="token punctuation">:</span>
        <span class="token keyword">from</span> _version <span class="token keyword">import</span> __version__
    <span class="token keyword">except</span> ImportError<span class="token punctuation">:</span>
        __version__ <span class="token operator">=</span> <span class="token string">"unknown"</span>

<span class="token comment"># Same pattern for core modules</span>
<span class="token keyword">try</span><span class="token punctuation">:</span>
    <span class="token keyword">from</span> <span class="token punctuation">.</span>player <span class="token keyword">import</span> <span class="token operator">*</span>
<span class="token keyword">except</span> ImportError<span class="token punctuation">:</span>
    <span class="token keyword">from</span> player <span class="token keyword">import</span> <span class="token operator">*</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p><strong>4. Unified Project URL</strong></p>
<p>All project references now point to the central hub: <strong><a href="https://www.apds.top/">https://www.apds.top</a></strong></p>
<hr>
<h4>📋 Full API Changes</h4>
<table>
<thead>
<tr>
<th>Function</th>
<th>Parameters</th>
<th>Return</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><code>fadein_music</code></td>
<td><code>aid: int, loops: int = -1, ms: int = 0</code></td>
<td><code>None</code></td>
<td>Fade in audio instance</td>
</tr>
<tr>
<td><code>fadein_music_pos</code></td>
<td><code>aid: int, loops: int = -1, ms: int = 0, position: float = 0.0</code></td>
<td><code>None</code></td>
<td>Fade in from position</td>
</tr>
<tr>
<td><code>fadeout_music</code></td>
<td><code>ms: int = 0</code></td>
<td><code>None</code></td>
<td>Fade out current music</td>
</tr>
<tr>
<td><code>is_music_playing</code></td>
<td><code>()</code></td>
<td><code>bool</code></td>
<td>Check playing state</td>
</tr>
<tr>
<td><code>is_music_paused</code></td>
<td><code>()</code></td>
<td><code>bool</code></td>
<td>Check paused state</td>
</tr>
<tr>
<td><code>get_music_fading</code></td>
<td><code>()</code></td>
<td><code>int</code></td>
<td>Get fade state (0=no fade, 1=fade out, 2=fade in)</td>
</tr>
</tbody></table>
<hr>
<h4>🔧 Environment Variables</h4>
<table>
<thead>
<tr>
<th>Variable</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><code>AP_DS_WAV_THRESHOLD</code></td>
<td><code>6</code></td>
<td>WAV threshold in seconds (from v2.3.5)</td>
</tr>
<tr>
<td><code>AP_DS_HIDE_SUPPORT_PROMPT</code></td>
<td>not set</td>
<td>Set to <code>1</code> to hide startup message</td>
</tr>
</tbody></table>
<hr>
<h4>⚡ Performance &amp; Compatibility</h4>
<ul>
<li><strong>Zero API breakage</strong> – All existing code continues to work</li>
<li><strong>No size increase</strong> – Still under 4MB across all platforms</li>
<li><strong>Full backward compatibility</strong> – v2.3.x applications run unchanged</li>
<li><strong>Python 3.7+ support</strong> – Maintained</li>
</ul>
<hr>
<h4>📦 Migration Guide</h4>
<p>No migration needed. Simply upgrade and enjoy the new features:</p>
<div class="code-block"><pre class="language-bash" tabindex="0"><code class="language-bash">pip <span class="token function">install</span> <span class="token parameter variable">--upgrade</span> ap_ds
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<p>To use the new fade functions in existing code:</p>
<div class="code-block"><pre class="language-python" tabindex="0"><code class="language-python"><span class="token comment"># Before (v2.3.x)</span>
aid <span class="token operator">=</span> lib<span class="token punctuation">.</span>play_from_file<span class="token punctuation">(</span><span class="token string">"song.mp3"</span><span class="token punctuation">)</span>
time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span>
lib<span class="token punctuation">.</span>stop_audio<span class="token punctuation">(</span>aid<span class="token punctuation">)</span>

<span class="token comment"># After (v2.4.0) - Professional transitions!</span>
aid <span class="token operator">=</span> lib<span class="token punctuation">.</span>play_from_file<span class="token punctuation">(</span><span class="token string">"song.mp3"</span><span class="token punctuation">)</span>
lib<span class="token punctuation">.</span>fadeout_music<span class="token punctuation">(</span>ms<span class="token operator">=</span><span class="token number">3000</span><span class="token punctuation">)</span>  <span class="token comment"># Smooth exit</span>
</code></pre><button class="copy-btn"><i class="fa fa-clipboard"></i> Copy</button></div>
<hr>
<h4>🎯 Summary</h4>
<p>v2.4.0 transforms ap_ds from a "playback library" into a <strong>professional audio tool</strong> with:</p>
<ul>
<li>Smooth audio transitions (fade in/out)</li>
<li>Complete state querying</li>
<li>Cleaner, more professional startup</li>
<li>Industrial-strength version management</li>
<li>Bulletproof import system</li>
</ul>
<p><strong>All while maintaining the core promise: lightweight, zero external Python dependencies, and cross-platform compatibility.</strong></p>
<hr>
<h3>v2.4.1 (March 1, 2026) - Documentation Update</h3>
<p>This version updates the PyPI documentation to fully reflect the new features introduced in v2.4.0, including detailed API descriptions, usage examples, and environment variable documentation.</p>
<p><strong>Changes:</strong></p>
<ul>
<li>Updated PyPI project description with complete 2.4.0 feature documentation</li>
<li>Added detailed examples for all new fade functions</li>
<li>Documented <code>AP_DS_HIDE_SUPPORT_PROMPT</code> environment variable</li>
<li>Improved quick start guide with common usage patterns</li>
</ul>
<p><strong>Note:</strong> This release contains no code changes from v2.4.0—only documentation improvements.</p>
<hr>
<h2>Final Notes</h2>
<h2>Final Notes</h2>
<p>ap_ds is built on a simple philosophy: <strong>focus on playback and parsing, stay lightweight, and let developers build great applications.</strong></p>
<p>We welcome feedback, bug reports, and contributions. For questions or issues, please reach out through the official channels.</p>
<p><strong>Thank you for using ap_ds!</strong></p>
</div>
        </div>

        <div class="content-section" id="license">
            <h2 class="text-2xl font-bold mb-6">6. Open source license</h2>

<p>For detailed information, please refer to: AP_DS_LICENSE.MD or AP_DS_LICENSE_v2.0_ZHCN.MD</p>
<p>For instructions, please refer to: AP_DS_GUIDE_v2.0_ZHCN.MD or AP_DS_GUIDE_v2.0_EN.MD</p>
<p>Thank you.</p>
        </div>

        <div class="content-section" id="faq">
            <h2 class="text-2xl font-bold mb-6">7. Frequently asked questions</h2>
            <div class="space-y-5">
                <div><p class="font-semibold">Q: Can a company integrate it in commercial products?</p><div class="success p-3">✅ Absolutely, no payment / notice / authorisation required.</div></div>
                <div><p class="font-semibold">Q: Can I modify and redistribute it?</p><div class="success p-3">✅ Yes, but you must use an independent brand, retain copyright, attribute, and provide maintainer statement.</div></div>
                <div><p class="font-semibold">Q: Do I have to open‑source my modifications?</p><div class="warning p-3">❌ No, you may distribute closed‑source.</div></div>
                <div><p class="font-semibold">Q: Do I need to pay for cloud service usage?</p><div class="warning p-3">❌ No, but contributions are welcome.</div></div>
                <div><p class="font-semibold">Q: What if I get sued for patent infringement?</p><div class="note p-3">📞 Contact the author immediately: me@dvsyun.top (backup dvs6666@163.com)</div></div>
                <div><p class="font-semibold">Q: Why such strict brand protection?</p><div class="note p-3">To protect users from confusion and ensure clear responsibility for each version.</div></div>
            </div>
        </div>

        <div class="content-section" id="contact">
            <h2 class="text-2xl font-bold mb-6">8. Contact &amp; support</h2>
            <div class="grid md:grid-cols-2 gap-6">
                <div class="bg-blue-50 p-6 rounded-2xl">
                    <h4 class="font-bold text-lg">📧 Licensing inquiries</h4>
                    <p>me@dvsyun.top or dvs6666@163.com · response within 7 working days</p>
                </div>
                <div class="bg-green-50 p-6 rounded-2xl">
                    <h4 class="font-bold text-lg">🛠️ Technical support</h4>
                    <p>GitHub Issues · docs at official site · emergency email</p>
                </div>
            </div>
            <div class="mt-6 p-6 bg-gray-50 rounded-2xl space-y-1">
                <p><i class="fa fa-globe text-blue-600 mr-2"></i><strong>Website:</strong> <a href="https://www.apds.top/" class="text-blue-700 underline">https://www.apds.top</a> (root domain)</p>
                <p><i class="fa fa-python text-green-600 mr-2"></i><strong>PyPI:</strong> <a href="https://pypi.org/project/ap_ds/" class="text-blue-700 underline">https://pypi.org/project/ap_ds/</a></p>
                <p><i class="fa fa-user text-purple-600 mr-2"></i><strong>Developer:</strong> <a href="https://dvsyun.top/me/dvs" class="text-blue-700 underline">Dvs (DvsXT)</a></p>
            </div>
        </div>

        <footer class="mt-12 pt-8 text-center text-gray-500 border-t">
            <p>© 2026 Dvs (DvsXT) · ap_ds · 2.5MB ends bloat</p>
            <p class="italic text-sm mt-2">“We don't do big and comprehensive, we only do small and excellent.” · domain www.apds.top</p>
        </footer>
    </div>



</body></html>