Aller au contenu principal
SubtitleMatrix

Convertir ASS en JSON

Conversion de formatsAdvanced SubStation Alpha (ASS)
Ou collez le texte d'un sous-titre

Ce que cette conversion change

1 élément perdu ou à décider

  • Contenu propre au format

    le contenu que le format source garde hors de ses blocs (blocs hors sous-titres, texte d'en-tête, réglages par bloc, événements commentés) — le format cible n'a nulle part où le mettre

Ce rapport de pertes vient de la matrice de capacités de ces deux formats, pas du fichier particulier que vous avez chargé. Un fichier précis peut perdre davantage s'il utilise des fonctionnalités que le format autorise mais que la matrice ne modélise pas.

Cette page convertit un ASS en JSON. Le document produit décrit les mêmes sous-titres avec le schéma de ce site : un numéro de version, puis une entrée par Dialogue avec son début et sa fin en millisecondes entières, ses lignes et ses balises.

Le schéma a été conçu pour porter l'essentiel du script, d'où une liste de pertes courte. Ce qui n'a pas de clé est conservé pour le même format mais pas ailleurs : le titre et la table de styles entière passent, y compris les colonnes que le convertisseur ne modélise pas. Ce qui est perdu, c'est le reste du fichier : les autres lignes de [Script Info] comme PlayResX, WrapStyle ou Collisions, les événements Comment:, Picture: et Sound:, et les sections [Fonts] et [Graphics].

Une entrée abîmée passe sans erreur : en-tête absent, fins de ligne Windows ou BOM sont lus sans plainte. Un fichier ou une saison, avec un ZIP à la fin.

Exemples

Un fichier ASS typique, converti en JSON

Entrée

[Script Info]
Title: Example
ScriptType: v4.00+
WrapStyle: 0

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,Arial,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,2,2,10,10,10,1
Style: Title,Arial,36,&H0000FFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,2,2,10,10,10,1

[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,0:00:01.00,0:00:04.00,Default,,0,0,0,,Hello there.
Dialogue: 0,0:00:05.00,0:00:08.50,Default,,0,0,0,,{\i1}Italic{\i0} and {\b1}bold{\b0} text.
Dialogue: 0,0:00:09.00,0:00:12.00,Title,,0,0,0,,{\pos(320,240)}Positioned
Dialogue: 0,0:00:13.00,0:00:16.00,Default,,0,0,0,,{\k50}ka{\k30}ra{\k20}o{\k10}ke
Dialogue: 0,0:00:17.00,0:00:20.00,Default,,0,0,0,,Line one\NLine two
Dialogue: 1,0:00:21.00,0:00:24.00,Default,,0,0,0,,{\an7}Top left

Sortie

{
  "version": 1,
  "title": "Example",
  "styles": {
    "Default": {
      "name": "Default",
      "Name": "Default",
      "Fontname": "Arial",
      "Fontsize": "20",
      "PrimaryColour": "&H00FFFFFF",
      "SecondaryColour": "&H000000FF",
      "OutlineColour": "&H00000000",
      "BackColour": "&H00000000",
      "Bold": "0",
      "Italic": "0",
      "Underline": "0",
      "StrikeOut": "0",
      "ScaleX": "100",
      "ScaleY": "100",
      "Spacing": "0",
      "Angle": "0",
      "BorderStyle": "1",
      "Outline": "2",
      "Shadow": "2",
      "Alignment": "2",
      "MarginL": "10",
      "MarginR": "10",
      "MarginV": "10",
      "Encoding": "1",
      "fontFamily": "Arial",
      "fontSize": 20,
      "primaryColor": "#ffffff",
      "outlineColor": "#000000",
      "bold": false,
      "italic": false
    },
    "Title": {
      "name": "Title",
      "Name": "Title",
      "Fontname": "Arial",
      "Fontsize": "36",
      "PrimaryColour": "&H0000FFFF",
      "SecondaryColour": "&H000000FF",
      "OutlineColour": "&H00000000",
      "BackColour": "&H00000000",
      "Bold": "-1",
      "Italic": "0",
      "Underline": "0",
      "StrikeOut": "0",
      "ScaleX": "100",
      "ScaleY": "100",
      "Spacing": "0",
      "Angle": "0",
      "BorderStyle": "1",
      "Outline": "2",
      "Shadow": "2",
      "Alignment": "2",
      "MarginL": "10",
      "MarginR": "10",
      "MarginV": "10",
      "Encoding": "1",
      "fontFamily": "Arial",
      "fontSize": 36,
      "primaryColor": "#ffff00",
      "outlineColor": "#000000",
      "bold": true,
      "italic": false
    }
  },
  "cues": [
    {
      "start": 1000,
      "end": 4000,
      "lines": [
        "Hello there."
      ],
      "style": "Default"
    },
    {
      "start": 5000,
      "end": 8500,
      "lines": [
        {
          "text": "Italic and bold text.",
          "tags": [
            {
              "kind": "italic",
              "start": 0,
              "end": 6
            },
            {
              "kind": "bold",
              "start": 11,
              "end": 15
            }
          ]
        }
      ],
      "style": "Default"
    },
    {
      "start": 9000,
      "end": 12000,
      "lines": [
        "Positioned"
      ],
      "style": "Title",
      "position": {
        "x": 320,
        "y": 240
      }
    },
    {
      "start": 13000,
      "end": 16000,
      "lines": [
        {
          "text": "karaoke",
          "tags": [
            {
              "kind": "karaoke",
              "start": 0,
              "end": 2,
              "value": "50"
            },
            {
              "kind": "karaoke",
              "start": 2,
              "end": 4,
              "value": "30"
            },
            {
              "kind": "karaoke",
              "start": 4,
              "end": 5,
              "value": "20"
            },
            {
              "kind": "karaoke",
              "start": 5,
              "end": 7,
              "value": "10"
            }
          ]
        }
      ],
      "style": "Default"
    },
    {
      "start": 17000,
      "end": 20000,
      "lines": [
        "Line one",
        "Line two"
      ],
      "style": "Default"
    },
    {
      "start": 21000,
      "end": 24000,
      "lines": [
        "Top left"
      ],
      "style": "Default"
    }
  ]
}

La seule perte annoncée est le contenu propre au script : le texte se compare ligne par ligne.

La même conversion sur une entrée mal formée

Entrée

[Script Info]
; 一份真实的脏文件:BOM + CRLF + 认不出的覆写码 + Comment + 坏时间码
Title: Dirty sample
ScriptType: v4.00+

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,Arial,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,1,0,0,0,100,100,0,0,1,2,2,2,10,10,10,1

[Fonts]
fontname: Arial
!!!!!!!!!!!!!!!!!!!!!!!!!!!!

[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Comment: 0,0:00:00.00,0:00:01.00,Default,,0,0,0,,这是一条注释,不该变成字幕
Dialogue: 0,0:00:01.00,0:00:04.00,Default,,0,0,0,,Hello, world
Dialogue: 0,0:00:05.00,0:00:08.00,Default,,0,0,0,,{\fad(300,300)}Unmodelled override
Dialogue: 0,0:00:09.00,0:00:12.00,Default,,0,0,0,,{\an7\pos(320,240)}Both, wrong order
Dialogue: 0,0:00:13.00,0:00:16.5,Default,,0,0,0,,One decimal centisecond
Dialogue: 0,0:00:17.00,0:00:20.00,Default,,0,0,0,,Soft\nbreak
Dialogue: 0,0:00:xx.00,0:00:24.00,Default,,0,0,0,,Broken timecode

Sortie

{
  "version": 1,
  "title": "Dirty sample",
  "styles": {
    "Default": {
      "name": "Default",
      "Name": "Default",
      "Fontname": "Arial",
      "Fontsize": "20",
      "PrimaryColour": "&H00FFFFFF",
      "SecondaryColour": "&H000000FF",
      "OutlineColour": "&H00000000",
      "BackColour": "&H00000000",
      "Bold": "1",
      "Italic": "0",
      "Underline": "0",
      "StrikeOut": "0",
      "ScaleX": "100",
      "ScaleY": "100",
      "Spacing": "0",
      "Angle": "0",
      "BorderStyle": "1",
      "Outline": "2",
      "Shadow": "2",
      "Alignment": "2",
      "MarginL": "10",
      "MarginR": "10",
      "MarginV": "10",
      "Encoding": "1",
      "fontFamily": "Arial",
      "fontSize": 20,
      "primaryColor": "#ffffff",
      "outlineColor": "#000000",
      "bold": true,
      "italic": false
    }
  },
  "cues": [
    {
      "start": 1000,
      "end": 4000,
      "lines": [
        "Hello, world"
      ],
      "style": "Default"
    },
    {
      "start": 5000,
      "end": 8000,
      "lines": [
        "{\\fad(300,300)}Unmodelled override"
      ],
      "style": "Default"
    },
    {
      "start": 9000,
      "end": 12000,
      "lines": [
        "Both, wrong order"
      ],
      "style": "Default",
      "position": {
        "x": 320,
        "y": 240
      }
    },
    {
      "start": 13000,
      "end": 16500,
      "lines": [
        "One decimal centisecond"
      ],
      "style": "Default"
    },
    {
      "start": 17000,
      "end": 20000,
      "lines": [
        "Soft",
        "break"
      ],
      "style": "Default"
    }
  ]
}

C'est le genre de dégâts que portent les vrais fichiers : fins de ligne mélangées, espaces parasites, champs vides. Comparez avec l'exemple propre ci-dessus pour voir ce que l'analyseur pardonne.

Questions fréquentes

Pourquoi la table de styles d'un ASS survit-elle dans le JSON ?

Parce que le schéma possède un objet de styles, avec un nom, une police, une taille, des couleurs, le gras et l'italique. Les colonnes que le convertisseur ne modélise pas restent dans un champ libre, donc la table n'est pas tronquée au passage.

Que perd un ASS en devenant du JSON ?

Tout ce qui n'est ni un sous-titre ni la table de styles : les autres lignes de [Script Info] comme PlayResX, WrapStyle et Collisions, les événements Comment:, Picture: et Sound:, et les sections [Fonts] et [Graphics]. Le texte et les temps, eux, passent entièrement.

Les codes \pos et \an7 d'un ASS sont-ils conservés dans le JSON ?

Le schéma a un champ de position, donc un placement simple peut être porté par la structure. Les codes qui n'ont pas de champ correspondant restent dans les balises de la ligne, ce qui permet de les retrouver si le document revient vers un script.

Comment un Dialogue ASS de deux lignes est-il représenté dans le JSON ?

Par deux éléments dans le tableau lines du même sous-titre. Le début et la fin restent uniques, donc la paire garde sa synchronisation et son statut de sous-titre unique.

Les événements Comment: d'un ASS deviennent-ils des sous-titres JSON ?

Non : seuls les Dialogue sont des sous-titres. Une ligne Comment: est une note d'auteur et n'a pas d'entrée dans le JSON ; elle est comptée dans les pertes, pas convertie en sous-titre.

Les temps au centième d'un ASS changent-ils dans le JSON ?

Non : 0:00:04.13 devient 4130 millisecondes, puis revient au même centième si le document repart vers un script. Le schéma travaille en millisecondes entières, donc aucune précision n'est inventée ni perdue.

Peut-on traiter un script confidentiel par cette page ?

Oui : l'analyse et l'écriture restent dans le navigateur, et aucune requête ne transporte le texte ni les styles. La page continue de fonctionner réseau coupé une fois chargée.

Outils associés