The Unofficial Tinycards Deck Exporter is a tool to export Tinycards decks.
Tinycards was an application (and website) created by Duolingo that enabled users to create and share flashcard decks. It served as a companion tool to their main application (Duolingo) for the memorization of language vocabulary but also for any other knowledge area, as it was not language-restricted.
On June 1, 2020, Duolingo announced that Tinycards would be disabled on September 1, 2020. The creation of new decks and edition of unfinished decks was disabled at the time of the announcement.
Duolingo provided a way for the users to download their existing data in CSV, a format received with strangeness by users accustomed to the user-friendly design of Tinycards. From the comments it was visible that many users perceived the cards as existing on their own and not as a group of different types of information rendered on the screen to create virtual cards that can be represented in different platforms: "I can see the data in the CSV, but I don't see the cards". A forum thread was created by users just to help each other make sense of the data exported.
This motivated the creation of the deck exporter, for users to keep both their data and the cards as they were used to see them in Tinycards.
There are two ways of using it: with a bookmarklet or with Tampermonkey. Both of them will create a zip file that you can download with the exported deck. The zip file will contain, among other relevant data, the multimedia resources associated with the deck you're exporting, the cards, a CSV file and an HTML file, which you can use to easily process the exported info and move it to a new flashcard system of your choice.
Create a new bookmark in your bookmarks toolbar, give it a name (e.g. "Export"), and copy this code to the URL field:
javascript:(function()%7Bconst%20proxyAddress%3D%22https%3A%2F%2Fapi.allorigins.win%2Fraw%3Furl%3D%22%3Bvar%20logData%3D%22%22%2CerrorsFound%3D!1%2CerrorsFileDownload%3D!1%2CerrorGettingDeckData%3D!1%3Bfunction%20log(e%2Cr%2Ct)%7Bswitch(r%3D(new%20Date).toLocaleString()%2B%22%20%22%2Br%2Cvoid%200!%3D%3Dt%26%26(t%3DJSON.stringify(t%2Cnull%2C4))%2Ce)%7Bcase%22log%22%3Avoid%200%3D%3D%3Dt%3Fconsole.log(r)%3Aconsole.log(r%2Ct)%3Bbreak%3Bcase%22error%22%3AerrorsFound%3D!0%2Cvoid%200%3D%3D%3Dt%3Fconsole.error(r)%3Aconsole.error(r%2Ct)%3Bbreak%3Bdefault%3Aconsole.log(%22Unknown%20log%20type%3A%20%22%2Ce)%2Cvoid%200%3D%3D%3Dt%3Fconsole.log(%22Message%20to%20log%20was%3A%20%22%2Cr)%3Aconsole.log(%22Message%20to%20log%20was%3A%20%22%2Cr%2Ct)%7DlogData%2B%3Dvoid%200%3D%3D%3Dt%3F%22%5Cn%22%2Br%3A%22%5Cn%22%2Br%2Bt%7Dfunction%20loadScripts()%7Btry%7Bfor(var%20scriptsJS%3D%5B%22https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fjszip%2F3.3.0%2Fjszip.min.js%22%2C%22https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fjszip-utils%2F0.1.0%2Fjszip-utils.min.js%22%2C%22https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2FFileSaver.js%2F1.3.8%2FFileSaver.js%22%2C%22https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fdom-to-image%2F2.6.0%2Fdom-to-image.min.js%22%5D%2Cindex%3D0%3Bindex%3CscriptsJS.length%3B%2B%2Bindex)%7Bvar%20script%3Ddocument.createElement(%22script%22)%3Bscript.src%3DscriptsJS%5Bindex%5D%2Cscript.type%3D%22text%2Fjavascript%22%2CinjectScript(script.src).then(()%3D%3E%7Blog(%22log%22%2C%22Script%20loaded!%22)%7D).catch(e%3D%3E%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20injectScript%3A%20%22%2Ce)%7D)%7Dfunction%20injectScript(e)%7Breturn%20new%20Promise((r%2Ct)%3D%3E%7Blog(%22log%22%2C%22Loading%20script%3A%20%22%2Ce)%3Bconst%20o%3Ddocument.createElement(%22script%22)%3Bo.src%3De%2Co.addEventListener(%22load%22%2Cr)%2Co.addEventListener(%22error%22%2Ce%3D%3Et(e.error))%2Cdocument.head.appendChild(o)%7D)%7Dvar%20scriptsJQuery%3D%5B%22https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fjquery%2F3.5.1%2Fjquery.min.js%22%2C%22https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fjquery.blockUI%2F2.70%2Fjquery.blockUI.min.js%22%5D%3B(async()%3D%3E%7Bfor(let%20i%3D0%3Bi%3CscriptsJQuery.length%3Bi%2B%2B)%7Bconst%20resp%3Dawait%20fetch(scriptsJQuery%5Bi%5D)%2Ctext%3Dawait%20resp.text()%3Beval(text)%7D%7D)()%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20loadScripts%3A%20%22%2Ce)%7D%7Dfunction%20updateProgress(e)%7Btry%7Bif(void%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20updateProgress%3A%20message%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bdocument.querySelectorAll(%22.blockMsg%22)%5B0%5D.innerText%3De%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20updateProgress%3A%20%22%2Ce)%7D%7Dasync%20function%20doIt()%7Btry%7B!function%20e(r)%7Bwindow.jQuery%26%26window.%24.blockUI%3Fr()%3AsetTimeout(function()%7Be(r)%7D%2C100)%7D(function()%7B!async%20function()%7Btry%7Blog(%22log%22%2C%22Starting%20export%22)%3Bvar%20e%3Dwindow.location.pathname.split(%22%2Fdecks%2F%22).pop().split(%22%2F%22)%5B0%5D%3B0%3D%3De.length%7C%7C0%3D%3Ddocument.getElementsByClassName(%22_15CbF%22).length%3Falert(%22This%20is%20not%20a%20deck%20page!%20You%20need%20to%20go%20to%20the%20Tinycards%20page%20of%20the%20deck%20you%20want%20to%20export!%22)%3A(window.%24.blockUI(%7Bmessage%3A%22Exporting%20deck...%22%7D)%2Cdocument.getElementsByClassName(%22_15CbF%22)%5B1%5D.click()%2CupdateProgress(%22Retrieving%20style%20sheets...%22)%2Cawait%20embedStyleSheets()%2CupdateProgress(%22Retrieving%20fonts...%22)%2Cawait%20embedFonts()%2CupdateProgress(%22Retrieving%20images...%22)%2CproxifyImages()%2CembedImages()%2Cwindow.%24.getJSON(%22https%3A%2F%2Ftinycards.duolingo.com%2Fapi%2F1%2Fdecks%2Fuuid%3FcompactId%3D%22%2Be%2Cfunction(e)%7Bvar%20r%3De.uuid%3BupdateProgress(%22Retrieving%20deck's%20information...%22)%2CgetDeck(r)%7D))%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20startExport%3A%20%22%2Ce)%7D%7D()%7D)%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20doIt%3A%20%22%2Ce)%7D%7Dfunction%20getDeck(e)%7Btry%7Bif(void%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20getDeck%3A%20deckLongId%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Blog(%22log%22%2C%22Getting%20deck%22)%2Cwindow.%24.getJSON(%22https%3A%2F%2Ftinycards.duolingo.com%2Fapi%2F1%2Fdecks%2F%22%2Be%2B%22%3Fattribution%3Dtrue%26expand%3Dtrue%22%2Casync%20function(e)%7Blog(%22log%22%2C%22deckData%3A%20%22%2Ce)%3Bvar%20r%3De.cardCount%2Ct%3Dnull!%3De.coverImageUrl%3Fe.coverImageUrl%3Ae.imageUrl%2Co%3De.description%2Cn%3De.fullname%2Ca%3De.name%2Ci%3De.picture.replace(%22https%22%2CproxyAddress%2B%22https%22)%2Cs%3De.username%2Cl%3De.slug%2B%22_%22%2Be.compactId%2Cd%3D%5B%5B%22Deck%20name%22%2Ca%5D%2C%5B%22Deck%20description%22%2Co%5D%2C%5B%22Creator%20username%22%2Cs%5D%2C%5B%22Creator%20name%22%2Cn%5D%2C%5B%22Number%20of%20cards%22%2Cr%5D%2C%5B%22Deck%20URL%22%2Cwindow.location%5D%5D.map(e%3D%3E'%22'%2Be.join('%22%2C%22')%2B'%22').join(%22%5Cn%22)%3Blog(%22log%22%2C%22deckMainInfo%3A%20%22%2Cd)%3Bvar%20c%3Dnew%20JSZip%3Bc.file(%22deckFullInfo.json%22%2CJSON.stringify(e%2Cnull%2C4))%2Cc.file(%22coverImage.jpg%22%2Ct.startsWith(%22data%3A%22)%3Ft.replace(%2F%5E%5B%5E%2C%5D%2B%2C%2F%2C%22%22)%3AgetBinaryFile(t)%2Ct.startsWith(%22data%3A%22)%3F%7Bbase64%3A!0%7D%3A%7Bbinary%3A!0%7D)%2Cc.file(%22creatorPicture.png%22%2Ci.startsWith(%22data%3A%22)%3Fi.replace(%2F%5E%5B%5E%2C%5D%2B%2C%2F%2C%22%22)%3AgetBinaryFile(i)%2Ci.startsWith(%22data%3A%22)%3F%7Bbase64%3A!0%7D%3A%7Bbinary%3A!0%7D)%2CupdateProgress(%22Retrieving%20cards'%20info...%22)%2Cc%3Dawait%20getDeckCardsInfo(e%2Cd%2Cc)%2CupdateProgress(%22Retrieving%20cards...%22)%2Cc%3Dawait%20everyoneSmile(c)%2CupdateProgress(%22Almost%20done.%20Generating%20the%20zip%20file...%22)%2Cawait%20new%20Promise(e%3D%3EsetTimeout(e%2C1e3))%2Clog(%22log%22%2C%22Generating%20zip%20file%22)%2Cc.file(%22log.txt%22%2ClogData)%2Cc.generateAsync(%7Btype%3A%22blob%22%7D).then(function(e)%7Bwindow.%24.unblockUI()%2CerrorGettingDeckData%3Falert(%22Could%20not%20download%20deck%20data.%20Please%20try%20again.%5CnYou%20can%20also%20check%20for%20errors%20found%20in%20the%20browser's%20console%20(F12)%20or%20in%20the%20log%20file%20included%20in%20the%20zip.%22)%3AerrorsFileDownload%3Falert(%22Some%20files%20could%20not%20be%20downloaded.%20Please%20check%20the%20zip%20file%20contents.%5CnYou%20can%20also%20check%20for%20errors%20found%20in%20the%20browser's%20console%20(F12)%20or%20in%20the%20log%20file%20included%20in%20the%20zip.%22)%3AerrorsFound%26%26alert(%22Some%20errors%20were%20found%20during%20the%20export%20process.%20Please%20check%20the%20browser's%20console%20(F12)%20or%20the%20log%20file%20in%20the%20zip.%22)%2CsaveAs(e%2Cl)%2CsetTimeout(function()%7Bwindow.location.reload()%7D%2C2e3)%7D).catch(e%3D%3E%7BerrorsFound%3D!0%2Cwindow.%24.unblockUI()%2Clog(%22error%22%2C%22ERROR%3A%20getDeck%3A%20zip.generateAsync%3A%20%22%2Ce)%7D)%7D).fail(function(e%2Cr%2Ct)%7BerrorGettingDeckData%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20getDeck%3A%20error%20getting%20deck%20data%3A%20%22%2Cr%2B%22%2C%20%22%2Bt)%7D)%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20getDeck%3A%20%22%2Ce)%7D%7Dasync%20function%20getDeckCardsInfo(e%2Cr%2Ct)%7Btry%7Bif(void%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20getDeckCardsInfo%3A%20deckData%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bif(void%200%3D%3D%3Dr)throw%20log(%22error%22%2C%22ERROR%3A%20getDeckCardsInfo%3A%20deckMainInfo%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bif(void%200%3D%3D%3Dt)throw%20log(%22error%22%2C%22ERROR%3A%20getDeckCardsInfo%3A%20zip%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Blog(%22log%22%2C%22Getting%20deck%20cards%20info%22)%3Bfor(var%20o%3D%22%22%2Cn%3De.cards%2Ca%3D0%3Ba%3Cn.length%3Ba%2B%2B)%7Bvar%20i%3Dn%5Ba%5D%3Blog(%22log%22%2C%22card%20number%3A%20%22%2Ca)%3Bvar%20s%3D%22%22%2Cl%3D%22%22%2Cd%3D%22%22%2Cc%3D%22%22%2Cg%3Di.sides%3Blog(%22log%22%2C%22sides%20length%3A%20%22%2Cg.length)%3Bfor(var%20u%3D0%3Bu%3Cg.length%3Bu%2B%2B)%7Bvar%20f%3Dg%5Bu%5D%3Blog(%22log%22%2C%22side%3A%20%22%2Cf)%3Bvar%20p%3DNumber(a%2B1)%2Cm%3Dn.length.toString().length%2Ch%3D%22cardsUI%2Fcard_%22%2Bzerofy(p%2Cm)%2B%22_%22%2B(u%3F%22back%22%3A%22front%22)%2B%22.png%22%3Bu%3Fd%3Dh%3As%3Dh%3Bfor(var%20y%3D%22%22%2CR%3D0%3BR%3Cf.concepts.length%3BR%2B%2B)%7Bvar%20v%3Df.concepts%5BR%5D%3Blog(%22log%22%2C%22side%3A%20%22%2Cf)%3Bvar%20w%3Dv.fact%3Blog(%22log%22%2C%22fact%3A%20%22%2Cw)%3Bvar%20b%3DNumber(u%2B1)%2Cx%3Dg.length.toString().length%2CE%3DNumber(R%2B1)%2CS%3Df.concepts.length.toString().length%2Ck%3D%22%22%3B%22IMAGE%22%3D%3Dw.type%3F(k%3D%22card_%22%2Bzerofy(p%2Cm)%2B%22_side_%22%2Bzerofy(b%2Cx)%2B%22_concept_%22%2Bzerofy(E%2CS)%2B%22.jpg%22%2Clog(%22log%22%2C%22found%20image%20side%20at%20url%3A%20%22%2Cw.imageUrl)%2Ct.file(%22cards%2F%22%2Bk%2Cw.imageUrl.startsWith(%22data%3A%22)%3Fw.imageUrl.replace(%2F%5E%5B%5E%2C%5D%2B%2C%2F%2C%22%22)%3AgetBinaryFile(w.imageUrl)%2Cw.imageUrl.startsWith(%22data%3A%22)%3F%7Bbase64%3A!0%7D%3A%7Bbinary%3A!0%7D))%3A%22TEXT%22%3D%3Dw.type%3F(k%3D%22card_%22%2Bzerofy(p%2Cm)%2B%22_side_%22%2Bzerofy(b%2Cx)%2B%22_concept_%22%2Bzerofy(E%2CS)%2B%22.txt%22%2Clog(%22log%22%2C%22found%20text%20side%3A%20%22%2Cw.text)%2Cy%3Dy.concat(R%3F%22%20%2F%20%22%3A%22%22).concat(w.text)%2Ct.file(%22cards%2F%22%2Bk%2Cw.text)%2Cvoid%200!%3D%3Dw.ttsUrl%26%26(k%3D%22card_%22%2Bzerofy(p%2Cm)%2B%22_side_%22%2Bzerofy(b%2Cx)%2B%22_concept_%22%2Bzerofy(E%2CS)%2B%22.mp3%22%2Clog(%22log%22%2C%22found%20tts%3A%20%22%2Cw.ttsUrl)%2Ct.file(%22cards%2F%22%2Bk%2Cw.ttsUrl.startsWith(%22data%3A%22)%3Fw.ttsUrl.replace(%2F%5E%5B%5E%2C%5D%2B%2C%2F%2C%22%22)%3AgetBinaryFile(w.ttsUrl)%2Cw.ttsUrl.startsWith(%22data%3A%22)%3F%7Bbase64%3A!0%7D%3A%7Bbinary%3A!0%7D)))%3Alog(%22error%22%2C%22ERROR%3A%20getDeckCardsInfo%3A%20Unexpected%20concept%20type%3A%20%22%2Bw.type%2Cw)%3Bfor(var%20P%3Dv.noteFacts%2CC%3D0%3BC%3CP.length%3BC%2B%2B)%7Bvar%20F%3DP%5BC%5D%2CO%3DNumber(C%2B1)%2CI%3DP.length.toString().length%2CT%3D%22card_%22%2Bzerofy(p%2Cm)%2B%22_side_%22%2Bzerofy(b%2Cx)%2B%22_concept_%22%2Bzerofy(E%2CS)%2B%22_noteFact_%22%2Bzerofy(O%2CI)%2B%22.txt%22%3Blog(%22log%22%2C%22found%20note%20fact%3A%20%22%2CF)%2Ct.file(%22cards%2F%22%2BT%2CF)%7D%7Du%3Fc%3Dy%3Al%3Dy%7Do%3Do%2B'%22'%2Bs%2B'%22%2C%22'%2Bd%2B'%22%2C%22'%2Bl%2B'%22%2C%22'%2Bc%2B'%22%5Cn'%7Dt.file(%22cardsInfo.csv%22%2Cr%2B'%5Cn%22%22%5Cn%22%22%5Cn%22Front%20Card%20Image%22%2C%22Front%20Card%20Text%22%2C%22Back%20Card%20Image%22%2C%22Back%20Card%20Text%22%5Cn'%2Bo)%3Bvar%20D%3D%22%3C!DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3Cmeta%20charset%3D'utf-8'%2F%3E%3Cstyle%3Etable%2C%20th%2C%20td%20%7Bborder%3A%200px%20solid%20gray%3B%20border-collapse%3A%20collapse%3B%7D%20%23cards%20td%20%7Bmax-width%3A%20300px%3B%20min-width%3A%20200px%3B%7D%20%23deckInfo%20%7Bmargin-bottom%3A%2010px%3B%7D%20%23deckInfo%20td%20%7Bpadding%3A0%2020px%200%200%3B%7D%20img%20%7Bbox-shadow%3A%200%208px%2016px%200%20rgba(0%2C0%2C0%2C0.2)%3B%20border-radius%3A%2025px%2025px%2025px%2025px%7D%3C%2Fstyle%3E%3C%2Fhead%3E%3Cbody%3E%3Ch1%3E%22%2Br.split(%22%5Cn%22%2C1)%5B0%5D.split(%22%2C%22)%5B1%5D.replace(%2F(%5E%22)%7C(%22%24)%2Fg%2C%22%22)%2B%22%3C%2Fh1%3E%3Cdiv%3E%3Ctable%20id%3D'deckInfo'%3E%22%2Br.replace(%2F%5E%22%2Fgm%2C%22%3Ctr%3E%3Ctd%3E%22).replace(%2F%22%24%2Fgm%2C%22%3C%2Ftd%3E%3C%2Ftr%3E%22).replace(%2F%22%2C%22%2Fg%2C%22%3C%2Ftd%3E%3Ctd%3E%22).concat(%22%3C%2Ftable%3E%3C%2Fdiv%3E%22).replace(%2F(http%5B%5E%3C%5D%2B)(%3F%3D%3C)%2F%2C%22%3Ca%20href%3D'%241'%3E%241%3C%2Fa%3E%22)%2B%22%3Cdiv%3E%3Cp%3E%3Ca%20href%3D'.%2F'%3EBase%20folder%3C%2Fa%3E%3C%2Fp%3E%3C%2Fdiv%3E%5Cn%3Cdiv%3E%3Ctable%20id%3D'cards'%3E%22%2B'%22Front%20Card%20Image%22%2C%22Back%20Card%20Image%22%2C%22Front%20Card%20Text%22%2C%22Back%20Card%20Text%22%5Cn'.replace(%2F%5E%22%2Fgm%2C%22%3Ctr%3E%3Cth%3E%22).replace(%2F%22%24%2Fgm%2C%22%3C%2Fth%3E%3C%2Ftr%3E%22).replace(%2F%22%2C%22%2Fg%2C%22%3C%2Fth%3E%3Cth%3E%22)%2Bo.replace(%2F%5E%22%2Fgm%2C%22%3Ctr%3E%3Ctd%3E%22).replace(%2F%22%24%2Fgm%2C%22%3C%2Ftd%3E%3C%2Ftr%3E%22).replace(%2F%22%2C%22%2Fg%2C%22%3C%2Ftd%3E%3Ctd%3E%22).replace(%2F%3Ctd%3EcardsUI%5C%2F%2Fg%2C%22%3Ctd%3E%3Cimg%20src%3D'.%2FcardsUI%2F%22).replace(%2F.png%3C%5C%2Ftd%3E%2Fg%2C%22.png'%2F%3E%3C%2Ftd%3E%22).replace(%2Fsrc%3D%5C'(%5B%5E%5C'%5D%2B)%5C'%2Fg%2Cfunction(e%2Cr)%7Breturn%22alt%3D'%22%2Br.replace(%2F%5C.%5C%2Fcards%5B%5E%5C%2F%5D%2B%5C%2F(%5B%5E%5C.%5D%2B)%5C.png%2Fg%2C%22%241%22).replace(%2F_%2Fg%2C%22%20%22)%2B%22'%20src%3D'%22%2Br%2B%22'%22%7D)%2B%22%3C%2Ftable%3E%3C%2Fdiv%3E%3C%2Fbody%3E%3C%2Fhtml%3E%22%3Breturn%20t.file(%22cardsInfo.html%22%2CD)%2Ct%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20getDeckCardsInfo%3A%20%22%2Ce)%7D%7Dfunction%20getBinaryFile(e)%7Btry%7Bif(void%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20getBinaryFile%3A%20url%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Breturn%20e.startsWith(%22data%3A%22)%3Flog(%22log%22%2C%22Getting%20binary%20file%3A%20data%20url%20received%22)%3Alog(%22log%22%2C%22Getting%20binary%20file%3A%20%22%2Ce)%2Cnew%20Promise(function(r%2Ct)%7BJSZipUtils.getBinaryContent(e%2Cfunction(e%2Co)%7Be%3Ft(e)%3Ar(o)%7D)%7D).catch(function(e)%7Breturn%20errorsFileDownload%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20getBinaryContent%3A%20%22%2Be)%2C%22ERROR%3A%20could%20not%20download%20this%20file%3A%20%22%2Be%7D)%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20getBinaryFile%3A%20%22%2Ce)%7D%7Dasync%20function%20flipCards()%7Btry%7Blog(%22log%22%2C%22Flipping%20cards%22)%3Bvar%20e%3Ddocument.querySelectorAll(%22.ALWo1%22)%3Bfor(let%20r%20of%20e)r.classList.contains(%22PemDv%22)%3F(r.style.transform%3D%22rotateY(180deg)%22%2Cr.classList.remove(%22PemDv%22))%3A(r.style.transform%3D%22rotateY(0deg)%22%2Cr.classList.add(%22PemDv%22))%2Cr.removeAttribute(%22style%22)%3Bawait%20new%20Promise(e%3D%3EsetTimeout(e%2C1e3))%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20flipCards%3A%20%22%2Ce)%7D%7Dfunction%20proxifyImages()%7Btry%7Blog(%22log%22%2C%22Proxifying%20images%22)%3Bvar%20e%3Ddocument.querySelectorAll(%22img%22)%3Bfor(let%20r%20of%20e)r.src.startsWith(proxyAddress)%7C%7Cr.src.startsWith(%22data%3A%22)%7C%7C(r.src%3DproxyAddress%2Br.src)%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20flipCards%3A%20%22%2Ce)%7D%7Dfunction%20embedImages()%7Btry%7Bfunction%20e(e%2Cr%2Ct)%7Btry%7Bif(void%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20convertImgToBase64%3A%20url%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bif(void%200%3D%3D%3Dr)throw%20log(%22error%22%2C%22ERROR%3A%20convertImgToBase64%3A%20callback%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bvar%20o%3Ddocument.createElement(%22CANVAS%22)%2Cn%3Do.getContext(%222d%22)%2Ca%3Dnew%20Image%3Ba.crossOrigin%3D%22Anonymous%22%2Ca.onload%3Dfunction()%7Bo.height%3Da.height%2Co.width%3Da.width%2Cn.drawImage(a%2C0%2C0)%3Bvar%20e%3Do.toDataURL(t%7C%7C%22image%2Fpng%22)%3Br.call(this%2Ce)%2Co%3Dnull%7D%2Ca.src%3De%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20convertImgToBase64%3A%20%22%2Ce)%7D%7Dlog(%22log%22%2C%22Embedding%20images%22)%3Bvar%20r%3Ddocument.querySelectorAll(%22img%22)%3Bfor(let%20t%20of%20r)e(t.src%2Cfunction(e)%7Bt.src%3De%7D)%2Ct.removeAttribute(%22srcset%22)%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20embedImages%3A%20%22%2Ce)%7D%7Dasync%20function%20everyoneSmile(e)%7Btry%7Bif(log(%22log%22%2C%22Everyone%20smile%22)%2Cvoid%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20everyoneSmile%3A%20zip%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Breturn%20e%3Dawait%20cardsSayCheese(e%2C%22front%22)%2Ce%3Dawait%20allTogetherNow(e%2C%22front%22)%2Cawait%20flipCards()%2Ce%3Dawait%20cardsSayCheese(e%2C%22back%22)%2Ce%3Dawait%20allTogetherNow(e%2C%22back%22)%2Cawait%20flipCards()%2Ce%7Dcatch(e)%7Blog(%22error%22%2C%22ERROR%3A%20everyoneSmile%3A%20%22%2Ce)%7D%7Dasync%20function%20convertToPng(e%2Cr%2Ct)%7Btry%7Bif(log(%22log%22%2C%22Converting%20to%20png%22)%2Cvoid%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20convertToPng%3A%20element%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bif(r%26%26void%200%3D%3D%3Dt)throw%20log(%22error%22%2C%22ERROR%3A%20convertToPng%3A%20width%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Blet%20o%3De.style.position%2Cn%3De.style.left%3Br%26%26(e.style.position%3D%22absolute%22%2Ce.style.left%3D%22-9999px%22%2Ce.style.width%3Dt%2B%22px%22%2Cdocument.body.appendChild(e))%3Bconst%20a%3Dawait%20domtoimage.toPng(e%2C%7Bstyle%3A%7Bposition%3Ao%2Cleft%3An%7D%7D).catch(function(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20convertToPng%3A%20domtoimage%3A%20%22%2Ce)%7D)%3Breturn%20r%26%26document.body.removeChild(e)%2Ca%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20convertToPng%3A%20%22%2Ce)%7D%7Dasync%20function%20cardsSayCheese(e%2Cr)%7Btry%7Bif(log(%22log%22%2C%22Cards%20say%20cheese%22)%2Cvoid%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20cardsSayCheese%3A%20zip%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bif(void%200%3D%3D%3Dr)throw%20log(%22error%22%2C%22ERROR%3A%20cardsSayCheese%3A%20side%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bvar%20t%3Ddocument.querySelectorAll(%22.PemDv%22)%2Co%3Dt.length.toString().length%2Cn%3D0%3Bfor(let%20i%20of%20t)%7BupdateProgress(%22Retrieving%20card's%20%22%2Br%2B%22%20%22%2B(n%2B%3D1)%2B%22%2F%22%2Bt.length%2B%22...%22)%3Bvar%20a%3Dawait%20convertToPng(i)%3Bvoid%200%3D%3D%3Da%3Flog(%22error%22%2C%22ERROR%3A%20cardsSayCheese%3A%20data%20returned%20from%20convertToPng%20is%20undefined%22)%3Ae.file(%22cardsUI%2Fcard_%22%2Bzerofy(n%2Co)%2B%22_%22%2Br%2B%22.png%22%2Ca.startsWith(%22data%3A%22)%3Fa.replace(%2F%5E%5B%5E%2C%5D%2B%2C%2F%2C%22%22)%3AgetBinaryFile(a)%2Ca.startsWith(%22data%3A%22)%3F%7Bbase64%3A!0%7D%3A%7Bbinary%3A!0%7D)%7Dreturn%20e%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20cardsSayCheese%3A%20%22%2Ce)%7D%7Dfunction%20zerofy(e%2Cr)%7Btry%7Bif(void%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20zerofy%3A%20number%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bif(void%200%3D%3D%3Dr)throw%20log(%22error%22%2C%22ERROR%3A%20zerofy%3A%20length%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bfor(var%20t%3D%22%22%2Be%3Bt.length%3Cr%3B)t%3D%220%22%2Bt%3Breturn%20t%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20zerofy%3A%20%22%2Ce)%7D%7Dasync%20function%20allTogetherNow(e%2Cr)%7Btry%7Bif(log(%22log%22%2C%22All%20together%20now%22)%2Cvoid%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20allTogetherNow%3A%20zip%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bif(void%200%3D%3D%3Dr)throw%20log(%22error%22%2C%22ERROR%3A%20allTogetherNow%3A%20side%20is%20undefined%22)%2C%22Parameter%20undefined%22%3BupdateProgress(%22Retrieving%20deck's%20%22%2Br%2B%22.%20This%20may%20take%20a%20while%20and%20slow%20down%20your%20browser%20temporarily.%20Please%20wait...%22)%2Cawait%20new%20Promise(e%3D%3EsetTimeout(e%2C100))%3Bvar%20t%3Ddocument.querySelectorAll(%22.ALWo1%3Anot(.PemDv)%22)%3Bfor(let%20e%20of%20t)e.style.display%3D%22none%22%3Bvar%20o%3Ddocument.querySelector(%22body%22).cloneNode(!0)%2Cn%3Do.querySelector(%22%23export%22)%3Bnull!%3Dn%26%26n.parentNode.removeChild(n)%3Bvar%20a%3Do.querySelectorAll(%22.blockOverlay%2C%20.blockMsg%22)%3Bif(null!%3Da)for(let%20e%20of%20a)null!%3De%26%26e.parentNode.removeChild(e)%3Bawait%20new%20Promise(e%3D%3EsetTimeout(e%2C100))%3Bvar%20i%3Dawait%20convertToPng(o%2C!0%2Cdocument.querySelector(%22body%22).clientWidth)%3Bawait%20new%20Promise(e%3D%3EsetTimeout(e%2C100))%3Bfor(let%20e%20of%20t)e.removeAttribute(%22style%22)%3Breturn%20void%200%3D%3D%3Di%3Flog(%22error%22%2C%22ERROR%3A%20allTogetherNow%3A%20data%20returned%20from%20convertToPng%20is%20undefined%22)%3Ae.file(%22deck%22%2Br.charAt(0).toUpperCase()%2Br.slice(1)%2B%22.png%22%2Ci.startsWith(%22data%3A%22)%3Fi.replace(%2F%5E%5B%5E%2C%5D%2B%2C%2F%2C%22%22)%3AgetBinaryFile(i)%2Ci.startsWith(%22data%3A%22)%3F%7Bbase64%3A!0%7D%3A%7Bbinary%3A!0%7D)%2Ce%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20allTogetherNow%3A%20%22%2Ce)%7D%7Dasync%20function%20getBase64File(e)%7Btry%7Bif(log(%22log%22%2C%22Getting%20a%20base64%20representation%20of%3A%20%22%2Ce)%2Cvoid%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20getBase64File%3A%20url%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bconst%20r%3Dawait%20fetch(e)%2Ct%3Dawait%20r.blob()%2Co%3Dnew%20FileReader%3Breturn%20await%20new%20Promise((e%2Cr)%3D%3E%7Bo.onload%3De%2Co.onerror%3Dr%2Co.readAsDataURL(t)%7D)%2Co.result%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20getBase64File%3A%20%22%2Ce)%7D%7Dasync%20function%20embedFonts()%7Btry%7Blog(%22log%22%2C%22Embedding%20fonts%22)%3Bvar%20e%3Ddocument.querySelectorAll(%22style%5Btype%3D'text%2Fcss'%5D%22)%3Bfor(let%20c%20of%20e)%7Bc.textContent%3Dc.textContent.replace(%2Furl%5C(%5C%2F%5C%2F%5B%5E%2C%5D%2B(woff%7Ctruetype%7Csvg)%22%5C)%2C%3F%2Fg%2C%22%22)%2Cc.textContent%3Dc.textContent.replace(%2Fformat%5C(%22woff2%5C%22%5C)%2C%2Fg%2C'format(%22woff2%22)')%2Cc.textContent%3Dc.textContent.replace(%2F%40font-face%2Fg%2C%22%5Cn%40font-face%22)%3Bfor(var%20r%2Ct%3D%2Furl%5C(%5C%2F%5C%2F%5B%5E)%5D%2B%5C)%2Fg%2Co%3D%5B%5D%3Bnull!%3D%3D(r%3Dt.exec(c.textContent))%3B)r%5B0%5D%3Dr%5B0%5D.replace(%2F%5C)%24%2F%2C%22%22).replace(%2F%5Eurl%5C(%2F%2C%22%22)%2Co.push(r%5B0%5D)%3Bfor(var%20n%3D%5B...new%20Set(o)%5D.sort()%2Ca%3D0%3Ba%3Cn.length%3Ba%2B%2B)%7Bvar%20i%3Dn%5Ba%5D%2Cs%3D%22%22%3Bi.startsWith(proxyAddress)%7C%7C(s%3DproxyAddress%2B%22https%3A%22%2Bi)%3Bvar%20l%3Dawait%20getBase64File(s)%2Cd%3Dnew%20RegExp(i%2C%22g%22)%3Bc.textContent%3Dc.textContent.replace(d%2Cl)%7D%7D%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20embedFonts%3A%20%22%2Ce)%7D%7Dasync%20function%20embedStyleSheets()%7Btry%7Basync%20function%20e(e)%7Bif(void%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20getExternalCSS%3A%20url%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bvar%20r%3Dnew%20XMLHttpRequest%3Breturn%20new%20Promise(function(t%2Co)%7Btry%7Br.onreadystatechange%3Dfunction()%7B4%3D%3Dr.readyState%26%26(r.status%3E%3D300%3Fo(%22ERROR%3A%20status%20code%20%3D%20%22%2Br.status)%3At(r.responseText))%7D%2Cr.open(%22get%22%2Ce)%2Cr.send()%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20embedStyleSheets%3A%20getExternalCSS%3A%20Promise%3A%20%22%2Ce)%7D%7D)%7Dlog(%22log%22%2C%22Embedding%20style%20sheets%22)%3Bvar%20r%3Ddocument.querySelectorAll(%22LINK%5Bhref*%3D'.css'%5D%22)%3Bfor(let%20o%20of%20r)%7Bvar%20t%3Do.href%3Bt.startsWith(%22moz-extension%22)%7C%7C(t.startsWith(proxyAddress)%7C%7C(t%3DproxyAddress%2Bt)%2Cawait%20e(t).then(function(e)%7Bvoid%200%3D%3D%3De%26%26log(%22error%22%2C%22ERROR%3A%20getExternalCSS%3A%20result%20is%20undefined%22)%3Bvar%20r%3Ddocument.head%7C%7Cdocument.getElementsByTagName(%22head%22)%5B0%5D%2Ct%3Ddocument.createElement(%22style%22)%3Bt.type%3D%22text%2Fcss%22%2Ct.styleSheet%3Ft.styleSheet.cssText%3De%3At.appendChild(document.createTextNode(e))%2Cr.appendChild(t)%7D%2Cfunction(e)%7Blog(%22error%22%2C%22ERROR%3A%20embedStyleSheets%3A%20%22%2Ce)%7D)%2Co.remove())%7D%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20embedStyleSheets%3A%20%22%2Ce)%7D%7DloadScripts()%2CdoIt()%3B%7D)()%3B
The link you have now on your bookmarks toolbar is called a bookmarklet.
Then visit the Tinycards deck page you want to export and click on the bookmarklet from your bookmarks toolbar.
If you're familiar with Tampermonkey, use the following code:
// ==UserScript==
// @name The Unofficial Tinycards Deck Exporter
// @namespace http://tampermonkey.net/
// @version 1.0.0
// @description Adds an Export button to a deck's page
// @description https://github.com/joaocarvalhomiranda/TheUnofficialTinycardsDeckExporter
// @author Joao Miranda
// @include https://tinycards.duolingo.com/decks/*
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @require https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant GM_addStyle
/* globals jQuery, $, waitForKeyElements */
// ==/UserScript==
(function() {
'use strict';
waitForKeyElements (".DFnrK", insertButton);
function insertButton (node) {
// get the deck long id
var deckShortId = window.location.pathname.split('/decks/').pop().split('/')[0];
// check if we are in a cards page
// _15CbF is the class for the tab pair Lessons/Cards in the page
if (deckShortId.length != 0 && document.getElementsByClassName('_15CbF').length != 0) {
var element = document.createElement('a');
element.id = 'export';
element.innerHTML = '<button class="_3qc77 _3cTMR _1wpPZ">Export</button>';
element.href = "javascript:(function()%7Bconst%20proxyAddress%3D%22https%3A%2F%2Fapi.allorigins.win%2Fraw%3Furl%3D%22%3Bvar%20logData%3D%22%22%2CerrorsFound%3D!1%2CerrorsFileDownload%3D!1%2CerrorGettingDeckData%3D!1%3Bfunction%20log(e%2Cr%2Ct)%7Bswitch(r%3D(new%20Date).toLocaleString()%2B%22%20%22%2Br%2Cvoid%200!%3D%3Dt%26%26(t%3DJSON.stringify(t%2Cnull%2C4))%2Ce)%7Bcase%22log%22%3Avoid%200%3D%3D%3Dt%3Fconsole.log(r)%3Aconsole.log(r%2Ct)%3Bbreak%3Bcase%22error%22%3AerrorsFound%3D!0%2Cvoid%200%3D%3D%3Dt%3Fconsole.error(r)%3Aconsole.error(r%2Ct)%3Bbreak%3Bdefault%3Aconsole.log(%22Unknown%20log%20type%3A%20%22%2Ce)%2Cvoid%200%3D%3D%3Dt%3Fconsole.log(%22Message%20to%20log%20was%3A%20%22%2Cr)%3Aconsole.log(%22Message%20to%20log%20was%3A%20%22%2Cr%2Ct)%7DlogData%2B%3Dvoid%200%3D%3D%3Dt%3F%22%5Cn%22%2Br%3A%22%5Cn%22%2Br%2Bt%7Dfunction%20loadScripts()%7Btry%7Bfor(var%20scriptsJS%3D%5B%22https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fjszip%2F3.3.0%2Fjszip.min.js%22%2C%22https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fjszip-utils%2F0.1.0%2Fjszip-utils.min.js%22%2C%22https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2FFileSaver.js%2F1.3.8%2FFileSaver.js%22%2C%22https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fdom-to-image%2F2.6.0%2Fdom-to-image.min.js%22%5D%2Cindex%3D0%3Bindex%3CscriptsJS.length%3B%2B%2Bindex)%7Bvar%20script%3Ddocument.createElement(%22script%22)%3Bscript.src%3DscriptsJS%5Bindex%5D%2Cscript.type%3D%22text%2Fjavascript%22%2CinjectScript(script.src).then(()%3D%3E%7Blog(%22log%22%2C%22Script%20loaded!%22)%7D).catch(e%3D%3E%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20injectScript%3A%20%22%2Ce)%7D)%7Dfunction%20injectScript(e)%7Breturn%20new%20Promise((r%2Ct)%3D%3E%7Blog(%22log%22%2C%22Loading%20script%3A%20%22%2Ce)%3Bconst%20o%3Ddocument.createElement(%22script%22)%3Bo.src%3De%2Co.addEventListener(%22load%22%2Cr)%2Co.addEventListener(%22error%22%2Ce%3D%3Et(e.error))%2Cdocument.head.appendChild(o)%7D)%7Dvar%20scriptsJQuery%3D%5B%22https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fjquery%2F3.5.1%2Fjquery.min.js%22%2C%22https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fjquery.blockUI%2F2.70%2Fjquery.blockUI.min.js%22%5D%3B(async()%3D%3E%7Bfor(let%20i%3D0%3Bi%3CscriptsJQuery.length%3Bi%2B%2B)%7Bconst%20resp%3Dawait%20fetch(scriptsJQuery%5Bi%5D)%2Ctext%3Dawait%20resp.text()%3Beval(text)%7D%7D)()%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20loadScripts%3A%20%22%2Ce)%7D%7Dfunction%20updateProgress(e)%7Btry%7Bif(void%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20updateProgress%3A%20message%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bdocument.querySelectorAll(%22.blockMsg%22)%5B0%5D.innerText%3De%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20updateProgress%3A%20%22%2Ce)%7D%7Dasync%20function%20doIt()%7Btry%7B!function%20e(r)%7Bwindow.jQuery%26%26window.%24.blockUI%3Fr()%3AsetTimeout(function()%7Be(r)%7D%2C100)%7D(function()%7B!async%20function()%7Btry%7Blog(%22log%22%2C%22Starting%20export%22)%3Bvar%20e%3Dwindow.location.pathname.split(%22%2Fdecks%2F%22).pop().split(%22%2F%22)%5B0%5D%3B0%3D%3De.length%7C%7C0%3D%3Ddocument.getElementsByClassName(%22_15CbF%22).length%3Falert(%22This%20is%20not%20a%20deck%20page!%20You%20need%20to%20go%20to%20the%20Tinycards%20page%20of%20the%20deck%20you%20want%20to%20export!%22)%3A(window.%24.blockUI(%7Bmessage%3A%22Exporting%20deck...%22%7D)%2Cdocument.getElementsByClassName(%22_15CbF%22)%5B1%5D.click()%2CupdateProgress(%22Retrieving%20style%20sheets...%22)%2Cawait%20embedStyleSheets()%2CupdateProgress(%22Retrieving%20fonts...%22)%2Cawait%20embedFonts()%2CupdateProgress(%22Retrieving%20images...%22)%2CproxifyImages()%2CembedImages()%2Cwindow.%24.getJSON(%22https%3A%2F%2Ftinycards.duolingo.com%2Fapi%2F1%2Fdecks%2Fuuid%3FcompactId%3D%22%2Be%2Cfunction(e)%7Bvar%20r%3De.uuid%3BupdateProgress(%22Retrieving%20deck's%20information...%22)%2CgetDeck(r)%7D))%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20startExport%3A%20%22%2Ce)%7D%7D()%7D)%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20doIt%3A%20%22%2Ce)%7D%7Dfunction%20getDeck(e)%7Btry%7Bif(void%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20getDeck%3A%20deckLongId%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Blog(%22log%22%2C%22Getting%20deck%22)%2Cwindow.%24.getJSON(%22https%3A%2F%2Ftinycards.duolingo.com%2Fapi%2F1%2Fdecks%2F%22%2Be%2B%22%3Fattribution%3Dtrue%26expand%3Dtrue%22%2Casync%20function(e)%7Blog(%22log%22%2C%22deckData%3A%20%22%2Ce)%3Bvar%20r%3De.cardCount%2Ct%3Dnull!%3De.coverImageUrl%3Fe.coverImageUrl%3Ae.imageUrl%2Co%3De.description%2Cn%3De.fullname%2Ca%3De.name%2Ci%3De.picture.replace(%22https%22%2CproxyAddress%2B%22https%22)%2Cs%3De.username%2Cl%3De.slug%2B%22_%22%2Be.compactId%2Cd%3D%5B%5B%22Deck%20name%22%2Ca%5D%2C%5B%22Deck%20description%22%2Co%5D%2C%5B%22Creator%20username%22%2Cs%5D%2C%5B%22Creator%20name%22%2Cn%5D%2C%5B%22Number%20of%20cards%22%2Cr%5D%2C%5B%22Deck%20URL%22%2Cwindow.location%5D%5D.map(e%3D%3E'%22'%2Be.join('%22%2C%22')%2B'%22').join(%22%5Cn%22)%3Blog(%22log%22%2C%22deckMainInfo%3A%20%22%2Cd)%3Bvar%20c%3Dnew%20JSZip%3Bc.file(%22deckFullInfo.json%22%2CJSON.stringify(e%2Cnull%2C4))%2Cc.file(%22coverImage.jpg%22%2Ct.startsWith(%22data%3A%22)%3Ft.replace(%2F%5E%5B%5E%2C%5D%2B%2C%2F%2C%22%22)%3AgetBinaryFile(t)%2Ct.startsWith(%22data%3A%22)%3F%7Bbase64%3A!0%7D%3A%7Bbinary%3A!0%7D)%2Cc.file(%22creatorPicture.png%22%2Ci.startsWith(%22data%3A%22)%3Fi.replace(%2F%5E%5B%5E%2C%5D%2B%2C%2F%2C%22%22)%3AgetBinaryFile(i)%2Ci.startsWith(%22data%3A%22)%3F%7Bbase64%3A!0%7D%3A%7Bbinary%3A!0%7D)%2CupdateProgress(%22Retrieving%20cards'%20info...%22)%2Cc%3Dawait%20getDeckCardsInfo(e%2Cd%2Cc)%2CupdateProgress(%22Retrieving%20cards...%22)%2Cc%3Dawait%20everyoneSmile(c)%2CupdateProgress(%22Almost%20done.%20Generating%20the%20zip%20file...%22)%2Cawait%20new%20Promise(e%3D%3EsetTimeout(e%2C1e3))%2Clog(%22log%22%2C%22Generating%20zip%20file%22)%2Cc.file(%22log.txt%22%2ClogData)%2Cc.generateAsync(%7Btype%3A%22blob%22%7D).then(function(e)%7Bwindow.%24.unblockUI()%2CerrorGettingDeckData%3Falert(%22Could%20not%20download%20deck%20data.%20Please%20try%20again.%5CnYou%20can%20also%20check%20for%20errors%20found%20in%20the%20browser's%20console%20(F12)%20or%20in%20the%20log%20file%20included%20in%20the%20zip.%22)%3AerrorsFileDownload%3Falert(%22Some%20files%20could%20not%20be%20downloaded.%20Please%20check%20the%20zip%20file%20contents.%5CnYou%20can%20also%20check%20for%20errors%20found%20in%20the%20browser's%20console%20(F12)%20or%20in%20the%20log%20file%20included%20in%20the%20zip.%22)%3AerrorsFound%26%26alert(%22Some%20errors%20were%20found%20during%20the%20export%20process.%20Please%20check%20the%20browser's%20console%20(F12)%20or%20the%20log%20file%20in%20the%20zip.%22)%2CsaveAs(e%2Cl)%2CsetTimeout(function()%7Bwindow.location.reload()%7D%2C2e3)%7D).catch(e%3D%3E%7BerrorsFound%3D!0%2Cwindow.%24.unblockUI()%2Clog(%22error%22%2C%22ERROR%3A%20getDeck%3A%20zip.generateAsync%3A%20%22%2Ce)%7D)%7D).fail(function(e%2Cr%2Ct)%7BerrorGettingDeckData%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20getDeck%3A%20error%20getting%20deck%20data%3A%20%22%2Cr%2B%22%2C%20%22%2Bt)%7D)%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20getDeck%3A%20%22%2Ce)%7D%7Dasync%20function%20getDeckCardsInfo(e%2Cr%2Ct)%7Btry%7Bif(void%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20getDeckCardsInfo%3A%20deckData%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bif(void%200%3D%3D%3Dr)throw%20log(%22error%22%2C%22ERROR%3A%20getDeckCardsInfo%3A%20deckMainInfo%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bif(void%200%3D%3D%3Dt)throw%20log(%22error%22%2C%22ERROR%3A%20getDeckCardsInfo%3A%20zip%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Blog(%22log%22%2C%22Getting%20deck%20cards%20info%22)%3Bfor(var%20o%3D%22%22%2Cn%3De.cards%2Ca%3D0%3Ba%3Cn.length%3Ba%2B%2B)%7Bvar%20i%3Dn%5Ba%5D%3Blog(%22log%22%2C%22card%20number%3A%20%22%2Ca)%3Bvar%20s%3D%22%22%2Cl%3D%22%22%2Cd%3D%22%22%2Cc%3D%22%22%2Cg%3Di.sides%3Blog(%22log%22%2C%22sides%20length%3A%20%22%2Cg.length)%3Bfor(var%20u%3D0%3Bu%3Cg.length%3Bu%2B%2B)%7Bvar%20f%3Dg%5Bu%5D%3Blog(%22log%22%2C%22side%3A%20%22%2Cf)%3Bvar%20p%3DNumber(a%2B1)%2Cm%3Dn.length.toString().length%2Ch%3D%22cardsUI%2Fcard_%22%2Bzerofy(p%2Cm)%2B%22_%22%2B(u%3F%22back%22%3A%22front%22)%2B%22.png%22%3Bu%3Fd%3Dh%3As%3Dh%3Bfor(var%20y%3D%22%22%2CR%3D0%3BR%3Cf.concepts.length%3BR%2B%2B)%7Bvar%20v%3Df.concepts%5BR%5D%3Blog(%22log%22%2C%22side%3A%20%22%2Cf)%3Bvar%20w%3Dv.fact%3Blog(%22log%22%2C%22fact%3A%20%22%2Cw)%3Bvar%20b%3DNumber(u%2B1)%2Cx%3Dg.length.toString().length%2CE%3DNumber(R%2B1)%2CS%3Df.concepts.length.toString().length%2Ck%3D%22%22%3B%22IMAGE%22%3D%3Dw.type%3F(k%3D%22card_%22%2Bzerofy(p%2Cm)%2B%22_side_%22%2Bzerofy(b%2Cx)%2B%22_concept_%22%2Bzerofy(E%2CS)%2B%22.jpg%22%2Clog(%22log%22%2C%22found%20image%20side%20at%20url%3A%20%22%2Cw.imageUrl)%2Ct.file(%22cards%2F%22%2Bk%2Cw.imageUrl.startsWith(%22data%3A%22)%3Fw.imageUrl.replace(%2F%5E%5B%5E%2C%5D%2B%2C%2F%2C%22%22)%3AgetBinaryFile(w.imageUrl)%2Cw.imageUrl.startsWith(%22data%3A%22)%3F%7Bbase64%3A!0%7D%3A%7Bbinary%3A!0%7D))%3A%22TEXT%22%3D%3Dw.type%3F(k%3D%22card_%22%2Bzerofy(p%2Cm)%2B%22_side_%22%2Bzerofy(b%2Cx)%2B%22_concept_%22%2Bzerofy(E%2CS)%2B%22.txt%22%2Clog(%22log%22%2C%22found%20text%20side%3A%20%22%2Cw.text)%2Cy%3Dy.concat(R%3F%22%20%2F%20%22%3A%22%22).concat(w.text)%2Ct.file(%22cards%2F%22%2Bk%2Cw.text)%2Cvoid%200!%3D%3Dw.ttsUrl%26%26(k%3D%22card_%22%2Bzerofy(p%2Cm)%2B%22_side_%22%2Bzerofy(b%2Cx)%2B%22_concept_%22%2Bzerofy(E%2CS)%2B%22.mp3%22%2Clog(%22log%22%2C%22found%20tts%3A%20%22%2Cw.ttsUrl)%2Ct.file(%22cards%2F%22%2Bk%2Cw.ttsUrl.startsWith(%22data%3A%22)%3Fw.ttsUrl.replace(%2F%5E%5B%5E%2C%5D%2B%2C%2F%2C%22%22)%3AgetBinaryFile(w.ttsUrl)%2Cw.ttsUrl.startsWith(%22data%3A%22)%3F%7Bbase64%3A!0%7D%3A%7Bbinary%3A!0%7D)))%3Alog(%22error%22%2C%22ERROR%3A%20getDeckCardsInfo%3A%20Unexpected%20concept%20type%3A%20%22%2Bw.type%2Cw)%3Bfor(var%20P%3Dv.noteFacts%2CC%3D0%3BC%3CP.length%3BC%2B%2B)%7Bvar%20F%3DP%5BC%5D%2CO%3DNumber(C%2B1)%2CI%3DP.length.toString().length%2CT%3D%22card_%22%2Bzerofy(p%2Cm)%2B%22_side_%22%2Bzerofy(b%2Cx)%2B%22_concept_%22%2Bzerofy(E%2CS)%2B%22_noteFact_%22%2Bzerofy(O%2CI)%2B%22.txt%22%3Blog(%22log%22%2C%22found%20note%20fact%3A%20%22%2CF)%2Ct.file(%22cards%2F%22%2BT%2CF)%7D%7Du%3Fc%3Dy%3Al%3Dy%7Do%3Do%2B'%22'%2Bs%2B'%22%2C%22'%2Bd%2B'%22%2C%22'%2Bl%2B'%22%2C%22'%2Bc%2B'%22%5Cn'%7Dt.file(%22cardsInfo.csv%22%2Cr%2B'%5Cn%22%22%5Cn%22%22%5Cn%22Front%20Card%20Image%22%2C%22Front%20Card%20Text%22%2C%22Back%20Card%20Image%22%2C%22Back%20Card%20Text%22%5Cn'%2Bo)%3Bvar%20D%3D%22%3C!DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3Cmeta%20charset%3D'utf-8'%2F%3E%3Cstyle%3Etable%2C%20th%2C%20td%20%7Bborder%3A%200px%20solid%20gray%3B%20border-collapse%3A%20collapse%3B%7D%20%23cards%20td%20%7Bmax-width%3A%20300px%3B%20min-width%3A%20200px%3B%7D%20%23deckInfo%20%7Bmargin-bottom%3A%2010px%3B%7D%20%23deckInfo%20td%20%7Bpadding%3A0%2020px%200%200%3B%7D%20img%20%7Bbox-shadow%3A%200%208px%2016px%200%20rgba(0%2C0%2C0%2C0.2)%3B%20border-radius%3A%2025px%2025px%2025px%2025px%7D%3C%2Fstyle%3E%3C%2Fhead%3E%3Cbody%3E%3Ch1%3E%22%2Br.split(%22%5Cn%22%2C1)%5B0%5D.split(%22%2C%22)%5B1%5D.replace(%2F(%5E%22)%7C(%22%24)%2Fg%2C%22%22)%2B%22%3C%2Fh1%3E%3Cdiv%3E%3Ctable%20id%3D'deckInfo'%3E%22%2Br.replace(%2F%5E%22%2Fgm%2C%22%3Ctr%3E%3Ctd%3E%22).replace(%2F%22%24%2Fgm%2C%22%3C%2Ftd%3E%3C%2Ftr%3E%22).replace(%2F%22%2C%22%2Fg%2C%22%3C%2Ftd%3E%3Ctd%3E%22).concat(%22%3C%2Ftable%3E%3C%2Fdiv%3E%22).replace(%2F(http%5B%5E%3C%5D%2B)(%3F%3D%3C)%2F%2C%22%3Ca%20href%3D'%241'%3E%241%3C%2Fa%3E%22)%2B%22%3Cdiv%3E%3Cp%3E%3Ca%20href%3D'.%2F'%3EBase%20folder%3C%2Fa%3E%3C%2Fp%3E%3C%2Fdiv%3E%5Cn%3Cdiv%3E%3Ctable%20id%3D'cards'%3E%22%2B'%22Front%20Card%20Image%22%2C%22Back%20Card%20Image%22%2C%22Front%20Card%20Text%22%2C%22Back%20Card%20Text%22%5Cn'.replace(%2F%5E%22%2Fgm%2C%22%3Ctr%3E%3Cth%3E%22).replace(%2F%22%24%2Fgm%2C%22%3C%2Fth%3E%3C%2Ftr%3E%22).replace(%2F%22%2C%22%2Fg%2C%22%3C%2Fth%3E%3Cth%3E%22)%2Bo.replace(%2F%5E%22%2Fgm%2C%22%3Ctr%3E%3Ctd%3E%22).replace(%2F%22%24%2Fgm%2C%22%3C%2Ftd%3E%3C%2Ftr%3E%22).replace(%2F%22%2C%22%2Fg%2C%22%3C%2Ftd%3E%3Ctd%3E%22).replace(%2F%3Ctd%3EcardsUI%5C%2F%2Fg%2C%22%3Ctd%3E%3Cimg%20src%3D'.%2FcardsUI%2F%22).replace(%2F.png%3C%5C%2Ftd%3E%2Fg%2C%22.png'%2F%3E%3C%2Ftd%3E%22).replace(%2Fsrc%3D%5C'(%5B%5E%5C'%5D%2B)%5C'%2Fg%2Cfunction(e%2Cr)%7Breturn%22alt%3D'%22%2Br.replace(%2F%5C.%5C%2Fcards%5B%5E%5C%2F%5D%2B%5C%2F(%5B%5E%5C.%5D%2B)%5C.png%2Fg%2C%22%241%22).replace(%2F_%2Fg%2C%22%20%22)%2B%22'%20src%3D'%22%2Br%2B%22'%22%7D)%2B%22%3C%2Ftable%3E%3C%2Fdiv%3E%3C%2Fbody%3E%3C%2Fhtml%3E%22%3Breturn%20t.file(%22cardsInfo.html%22%2CD)%2Ct%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20getDeckCardsInfo%3A%20%22%2Ce)%7D%7Dfunction%20getBinaryFile(e)%7Btry%7Bif(void%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20getBinaryFile%3A%20url%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Breturn%20e.startsWith(%22data%3A%22)%3Flog(%22log%22%2C%22Getting%20binary%20file%3A%20data%20url%20received%22)%3Alog(%22log%22%2C%22Getting%20binary%20file%3A%20%22%2Ce)%2Cnew%20Promise(function(r%2Ct)%7BJSZipUtils.getBinaryContent(e%2Cfunction(e%2Co)%7Be%3Ft(e)%3Ar(o)%7D)%7D).catch(function(e)%7Breturn%20errorsFileDownload%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20getBinaryContent%3A%20%22%2Be)%2C%22ERROR%3A%20could%20not%20download%20this%20file%3A%20%22%2Be%7D)%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20getBinaryFile%3A%20%22%2Ce)%7D%7Dasync%20function%20flipCards()%7Btry%7Blog(%22log%22%2C%22Flipping%20cards%22)%3Bvar%20e%3Ddocument.querySelectorAll(%22.ALWo1%22)%3Bfor(let%20r%20of%20e)r.classList.contains(%22PemDv%22)%3F(r.style.transform%3D%22rotateY(180deg)%22%2Cr.classList.remove(%22PemDv%22))%3A(r.style.transform%3D%22rotateY(0deg)%22%2Cr.classList.add(%22PemDv%22))%2Cr.removeAttribute(%22style%22)%3Bawait%20new%20Promise(e%3D%3EsetTimeout(e%2C1e3))%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20flipCards%3A%20%22%2Ce)%7D%7Dfunction%20proxifyImages()%7Btry%7Blog(%22log%22%2C%22Proxifying%20images%22)%3Bvar%20e%3Ddocument.querySelectorAll(%22img%22)%3Bfor(let%20r%20of%20e)r.src.startsWith(proxyAddress)%7C%7Cr.src.startsWith(%22data%3A%22)%7C%7C(r.src%3DproxyAddress%2Br.src)%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20flipCards%3A%20%22%2Ce)%7D%7Dfunction%20embedImages()%7Btry%7Bfunction%20e(e%2Cr%2Ct)%7Btry%7Bif(void%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20convertImgToBase64%3A%20url%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bif(void%200%3D%3D%3Dr)throw%20log(%22error%22%2C%22ERROR%3A%20convertImgToBase64%3A%20callback%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bvar%20o%3Ddocument.createElement(%22CANVAS%22)%2Cn%3Do.getContext(%222d%22)%2Ca%3Dnew%20Image%3Ba.crossOrigin%3D%22Anonymous%22%2Ca.onload%3Dfunction()%7Bo.height%3Da.height%2Co.width%3Da.width%2Cn.drawImage(a%2C0%2C0)%3Bvar%20e%3Do.toDataURL(t%7C%7C%22image%2Fpng%22)%3Br.call(this%2Ce)%2Co%3Dnull%7D%2Ca.src%3De%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20convertImgToBase64%3A%20%22%2Ce)%7D%7Dlog(%22log%22%2C%22Embedding%20images%22)%3Bvar%20r%3Ddocument.querySelectorAll(%22img%22)%3Bfor(let%20t%20of%20r)e(t.src%2Cfunction(e)%7Bt.src%3De%7D)%2Ct.removeAttribute(%22srcset%22)%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20embedImages%3A%20%22%2Ce)%7D%7Dasync%20function%20everyoneSmile(e)%7Btry%7Bif(log(%22log%22%2C%22Everyone%20smile%22)%2Cvoid%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20everyoneSmile%3A%20zip%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Breturn%20e%3Dawait%20cardsSayCheese(e%2C%22front%22)%2Ce%3Dawait%20allTogetherNow(e%2C%22front%22)%2Cawait%20flipCards()%2Ce%3Dawait%20cardsSayCheese(e%2C%22back%22)%2Ce%3Dawait%20allTogetherNow(e%2C%22back%22)%2Cawait%20flipCards()%2Ce%7Dcatch(e)%7Blog(%22error%22%2C%22ERROR%3A%20everyoneSmile%3A%20%22%2Ce)%7D%7Dasync%20function%20convertToPng(e%2Cr%2Ct)%7Btry%7Bif(log(%22log%22%2C%22Converting%20to%20png%22)%2Cvoid%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20convertToPng%3A%20element%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bif(r%26%26void%200%3D%3D%3Dt)throw%20log(%22error%22%2C%22ERROR%3A%20convertToPng%3A%20width%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Blet%20o%3De.style.position%2Cn%3De.style.left%3Br%26%26(e.style.position%3D%22absolute%22%2Ce.style.left%3D%22-9999px%22%2Ce.style.width%3Dt%2B%22px%22%2Cdocument.body.appendChild(e))%3Bconst%20a%3Dawait%20domtoimage.toPng(e%2C%7Bstyle%3A%7Bposition%3Ao%2Cleft%3An%7D%7D).catch(function(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20convertToPng%3A%20domtoimage%3A%20%22%2Ce)%7D)%3Breturn%20r%26%26document.body.removeChild(e)%2Ca%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20convertToPng%3A%20%22%2Ce)%7D%7Dasync%20function%20cardsSayCheese(e%2Cr)%7Btry%7Bif(log(%22log%22%2C%22Cards%20say%20cheese%22)%2Cvoid%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20cardsSayCheese%3A%20zip%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bif(void%200%3D%3D%3Dr)throw%20log(%22error%22%2C%22ERROR%3A%20cardsSayCheese%3A%20side%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bvar%20t%3Ddocument.querySelectorAll(%22.PemDv%22)%2Co%3Dt.length.toString().length%2Cn%3D0%3Bfor(let%20i%20of%20t)%7BupdateProgress(%22Retrieving%20card's%20%22%2Br%2B%22%20%22%2B(n%2B%3D1)%2B%22%2F%22%2Bt.length%2B%22...%22)%3Bvar%20a%3Dawait%20convertToPng(i)%3Bvoid%200%3D%3D%3Da%3Flog(%22error%22%2C%22ERROR%3A%20cardsSayCheese%3A%20data%20returned%20from%20convertToPng%20is%20undefined%22)%3Ae.file(%22cardsUI%2Fcard_%22%2Bzerofy(n%2Co)%2B%22_%22%2Br%2B%22.png%22%2Ca.startsWith(%22data%3A%22)%3Fa.replace(%2F%5E%5B%5E%2C%5D%2B%2C%2F%2C%22%22)%3AgetBinaryFile(a)%2Ca.startsWith(%22data%3A%22)%3F%7Bbase64%3A!0%7D%3A%7Bbinary%3A!0%7D)%7Dreturn%20e%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20cardsSayCheese%3A%20%22%2Ce)%7D%7Dfunction%20zerofy(e%2Cr)%7Btry%7Bif(void%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20zerofy%3A%20number%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bif(void%200%3D%3D%3Dr)throw%20log(%22error%22%2C%22ERROR%3A%20zerofy%3A%20length%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bfor(var%20t%3D%22%22%2Be%3Bt.length%3Cr%3B)t%3D%220%22%2Bt%3Breturn%20t%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20zerofy%3A%20%22%2Ce)%7D%7Dasync%20function%20allTogetherNow(e%2Cr)%7Btry%7Bif(log(%22log%22%2C%22All%20together%20now%22)%2Cvoid%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20allTogetherNow%3A%20zip%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bif(void%200%3D%3D%3Dr)throw%20log(%22error%22%2C%22ERROR%3A%20allTogetherNow%3A%20side%20is%20undefined%22)%2C%22Parameter%20undefined%22%3BupdateProgress(%22Retrieving%20deck's%20%22%2Br%2B%22.%20This%20may%20take%20a%20while%20and%20slow%20down%20your%20browser%20temporarily.%20Please%20wait...%22)%2Cawait%20new%20Promise(e%3D%3EsetTimeout(e%2C100))%3Bvar%20t%3Ddocument.querySelectorAll(%22.ALWo1%3Anot(.PemDv)%22)%3Bfor(let%20e%20of%20t)e.style.display%3D%22none%22%3Bvar%20o%3Ddocument.querySelector(%22body%22).cloneNode(!0)%2Cn%3Do.querySelector(%22%23export%22)%3Bnull!%3Dn%26%26n.parentNode.removeChild(n)%3Bvar%20a%3Do.querySelectorAll(%22.blockOverlay%2C%20.blockMsg%22)%3Bif(null!%3Da)for(let%20e%20of%20a)null!%3De%26%26e.parentNode.removeChild(e)%3Bawait%20new%20Promise(e%3D%3EsetTimeout(e%2C100))%3Bvar%20i%3Dawait%20convertToPng(o%2C!0%2Cdocument.querySelector(%22body%22).clientWidth)%3Bawait%20new%20Promise(e%3D%3EsetTimeout(e%2C100))%3Bfor(let%20e%20of%20t)e.removeAttribute(%22style%22)%3Breturn%20void%200%3D%3D%3Di%3Flog(%22error%22%2C%22ERROR%3A%20allTogetherNow%3A%20data%20returned%20from%20convertToPng%20is%20undefined%22)%3Ae.file(%22deck%22%2Br.charAt(0).toUpperCase()%2Br.slice(1)%2B%22.png%22%2Ci.startsWith(%22data%3A%22)%3Fi.replace(%2F%5E%5B%5E%2C%5D%2B%2C%2F%2C%22%22)%3AgetBinaryFile(i)%2Ci.startsWith(%22data%3A%22)%3F%7Bbase64%3A!0%7D%3A%7Bbinary%3A!0%7D)%2Ce%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20allTogetherNow%3A%20%22%2Ce)%7D%7Dasync%20function%20getBase64File(e)%7Btry%7Bif(log(%22log%22%2C%22Getting%20a%20base64%20representation%20of%3A%20%22%2Ce)%2Cvoid%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20getBase64File%3A%20url%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bconst%20r%3Dawait%20fetch(e)%2Ct%3Dawait%20r.blob()%2Co%3Dnew%20FileReader%3Breturn%20await%20new%20Promise((e%2Cr)%3D%3E%7Bo.onload%3De%2Co.onerror%3Dr%2Co.readAsDataURL(t)%7D)%2Co.result%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20getBase64File%3A%20%22%2Ce)%7D%7Dasync%20function%20embedFonts()%7Btry%7Blog(%22log%22%2C%22Embedding%20fonts%22)%3Bvar%20e%3Ddocument.querySelectorAll(%22style%5Btype%3D'text%2Fcss'%5D%22)%3Bfor(let%20c%20of%20e)%7Bc.textContent%3Dc.textContent.replace(%2Furl%5C(%5C%2F%5C%2F%5B%5E%2C%5D%2B(woff%7Ctruetype%7Csvg)%22%5C)%2C%3F%2Fg%2C%22%22)%2Cc.textContent%3Dc.textContent.replace(%2Fformat%5C(%22woff2%5C%22%5C)%2C%2Fg%2C'format(%22woff2%22)')%2Cc.textContent%3Dc.textContent.replace(%2F%40font-face%2Fg%2C%22%5Cn%40font-face%22)%3Bfor(var%20r%2Ct%3D%2Furl%5C(%5C%2F%5C%2F%5B%5E)%5D%2B%5C)%2Fg%2Co%3D%5B%5D%3Bnull!%3D%3D(r%3Dt.exec(c.textContent))%3B)r%5B0%5D%3Dr%5B0%5D.replace(%2F%5C)%24%2F%2C%22%22).replace(%2F%5Eurl%5C(%2F%2C%22%22)%2Co.push(r%5B0%5D)%3Bfor(var%20n%3D%5B...new%20Set(o)%5D.sort()%2Ca%3D0%3Ba%3Cn.length%3Ba%2B%2B)%7Bvar%20i%3Dn%5Ba%5D%2Cs%3D%22%22%3Bi.startsWith(proxyAddress)%7C%7C(s%3DproxyAddress%2B%22https%3A%22%2Bi)%3Bvar%20l%3Dawait%20getBase64File(s)%2Cd%3Dnew%20RegExp(i%2C%22g%22)%3Bc.textContent%3Dc.textContent.replace(d%2Cl)%7D%7D%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20embedFonts%3A%20%22%2Ce)%7D%7Dasync%20function%20embedStyleSheets()%7Btry%7Basync%20function%20e(e)%7Bif(void%200%3D%3D%3De)throw%20log(%22error%22%2C%22ERROR%3A%20getExternalCSS%3A%20url%20is%20undefined%22)%2C%22Parameter%20undefined%22%3Bvar%20r%3Dnew%20XMLHttpRequest%3Breturn%20new%20Promise(function(t%2Co)%7Btry%7Br.onreadystatechange%3Dfunction()%7B4%3D%3Dr.readyState%26%26(r.status%3E%3D300%3Fo(%22ERROR%3A%20status%20code%20%3D%20%22%2Br.status)%3At(r.responseText))%7D%2Cr.open(%22get%22%2Ce)%2Cr.send()%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20embedStyleSheets%3A%20getExternalCSS%3A%20Promise%3A%20%22%2Ce)%7D%7D)%7Dlog(%22log%22%2C%22Embedding%20style%20sheets%22)%3Bvar%20r%3Ddocument.querySelectorAll(%22LINK%5Bhref*%3D'.css'%5D%22)%3Bfor(let%20o%20of%20r)%7Bvar%20t%3Do.href%3Bt.startsWith(%22moz-extension%22)%7C%7C(t.startsWith(proxyAddress)%7C%7C(t%3DproxyAddress%2Bt)%2Cawait%20e(t).then(function(e)%7Bvoid%200%3D%3D%3De%26%26log(%22error%22%2C%22ERROR%3A%20getExternalCSS%3A%20result%20is%20undefined%22)%3Bvar%20r%3Ddocument.head%7C%7Cdocument.getElementsByTagName(%22head%22)%5B0%5D%2Ct%3Ddocument.createElement(%22style%22)%3Bt.type%3D%22text%2Fcss%22%2Ct.styleSheet%3Ft.styleSheet.cssText%3De%3At.appendChild(document.createTextNode(e))%2Cr.appendChild(t)%7D%2Cfunction(e)%7Blog(%22error%22%2C%22ERROR%3A%20embedStyleSheets%3A%20%22%2Ce)%7D)%2Co.remove())%7D%7Dcatch(e)%7BerrorsFound%3D!0%2Clog(%22error%22%2C%22ERROR%3A%20embedStyleSheets%3A%20%22%2Ce)%7D%7DloadScripts()%2CdoIt()%3B%7D)()%3B";
node.prepend(element);
}
}
})();
If you're not familiar with Tampermonkey and you don't want to try it, use the bookmarklet method. If you would like to learn something new, give it a try.
It will create an Export button close to the deck information (look for the Pin button). If it doesn't show right away, refresh the page (Ctrl+F5).
To use the deck exporter, you need a modern desktop browser and an Internet connection. We recommend Google Chrome because, in the tests we made, it was able to manage large decks without using too much memory when performing the export. Firefox performed well only when the decks were not large and didn't have too many pictures.
For the deck exporter to run, the following websites need to be up and running and reachable from your network:
- Tinycards
Tinycards is a product from Duolingo. If you like Duolingo, support them with a Duolingo Plus subscription. - allOrigins
Exporting the decks requires using a secondary server for downloading some of the files. This can be done by setting up a local server yourself or using an existing server for that purpose available on the Web. This project uses allOrigins. If you like using the deck exporter without having to set up a local server, support allOrigins. - cdnjs
Where the libraries used are loaded from.
There are so many options that it really depends on you. Different systems appeal to different people, so try a few and stay with the one that you like.
On the Tinycards forum many different ones were suggested:
I'm using the Tampermonkey script but I don't see the Export button
It's created close to the deck information (look for the Pin button). If it doesn't show right away, refresh the page (Ctrl+F5).
I press Export but I don't get any zip file
Press F12 to see the browser's console and check for any errors in red.
The Tinycards page is gone. Can I still use this tool to export a Tinycards deck?
This tool only works on the Tinycards deck page that you want to export. If the deck page is no longer accessible the tool won't work.
allOrigins is down or not working any more
Try to find an alternative to it and replace it in the code. You can also set up your own server for dealing with the requests.
More information:
My browser crashed when I was using this tool
You were probably not using Chrome. We recommend Google Chrome because, in the tests we made, it was able to manage large decks without using too much memory when performing the export. Firefox performed well only when the decks were not large and didn't have too many pictures.
Can I download my unfinished decks with this tool?
No. This tool can only download publicly accessible decks.
Who was Cardlos?
Cardlos was the name of the Tinycards mascot. In a parallel dimension he was also known as Tiny.
This project would not be possible without Tinycards, allOrigins, cdnjs and the libraries and tools mentioned below.