<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>레몬그린 블로그</title>
    <link>https://lemongreen.tistory.com/</link>
    <description>04년생 개발새발 인생은 나처럼 살자</description>
    <language>ko</language>
    <pubDate>Sun, 12 Apr 2026 00:39:16 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>윤서아</managingEditor>
    <image>
      <title>레몬그린 블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/4734623/attach/e8072e017c1341b8a3254002a45bba83</url>
      <link>https://lemongreen.tistory.com</link>
    </image>
    <item>
      <title>크롬에서 광고 차단이 막히다? Manifest V3 업데이트와 해결 방법</title>
      <link>https://lemongreen.tistory.com/24</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dj4akP/btsKuJeuICf/CEkkiK5tjIKyEhB4z1FIQK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dj4akP/btsKuJeuICf/CEkkiK5tjIKyEhB4z1FIQK/img.jpg&quot; data-alt=&quot;크롬 웹 스토어에서 uBlock Origin의 사용이 불가능해졌다. 이미지 출처 https://www.pcworld.com/article/2490090&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dj4akP/btsKuJeuICf/CEkkiK5tjIKyEhB4z1FIQK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdj4akP%2FbtsKuJeuICf%2FCEkkiK5tjIKyEhB4z1FIQK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;크롬 웹 스토어에서 uBlock Origin의 사용이 불가능해졌다. 이미지 출처 https://www.pcworld.com/article/2490090&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크롬에서 드디어 Manifest V3 업데이트가 진행되었다. 전에도 유튜브에 애드블럭 관련 업데이트를 진행하거나, Manifest V3를 도입하겠다고 엄포를 놓은 크롬이었고, 결국 이번에 Manifest V3 업데이트가 진행되었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Manifest V3가 뭐고 어떻게 달라졌길래?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Manifest V3는 크롬 확장 프로그램의 구조와 기능을 정의하는 표준입니다. 이번에 V3으로 업데이트하면서, 보안과 성능을 향상시키겠다고 여러 변화가 있었는데. 그 중 몇몇 부분이 광고 차단기 확장 프로그램에 큰 타격을 주게 되었습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;웹 요청 수정 기능의 우선권 하락&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;V2의 &lt;code&gt;webRequest&lt;/code&gt; 대신에 V3에선 &lt;code&gt;declarativeNetRequest&lt;/code&gt;로 대체되었습니다. 이 API 변경의 가장 큰 문제는 브라우저가 웹 요청을 컨트롤할 최종 권한을 가지게 됩니다. 광고 차단 확장 프로그램에서 광고를 차단해도 크롬에서 그걸 무시하고 불러오게 할 수 있다는거죠.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사용할 수 있는 규칙 수의 제한&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, uBlock Origin이 정상적으로 작동하려면 최소 300,000개의 규칙을 사용할 수 있어야 합니다. 문제는 V3에서는 그 규칙의 제한이 30000개로 줄어들었습니다, 정상적인 광고 차단 환경을 조성할 수 없게 되었죠&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 크롬이 이러한 칼을 빼들겠다고 경고한 게 좀 되긴 했습니다. 문제는 최근 유튜브가 광고 차단기를 무력화할려고 온갖 방법을 시도한 후 Manifest V3를 적용하며 화룡점정이 된 게 제일 크죠.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;해결법?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 해결법들은 의외로 간단합니다. 이 패치는 &lt;b&gt;크롬 브라우저&lt;/b&gt;의 &lt;b&gt;확장 프로그램&lt;/b&gt;에만 적용된 거거든요.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Firefox 브라우저 사용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.mozilla.org/ko/firefox/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.mozilla.org/ko/firefox/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1730478116416&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;데스크톱, 모바일 또는 기업용 Firefox 다운로드 - Mozilla&quot; data-og-description=&quot;데스크톱, iOS, Android 중에서 선택하거나 모바일 다운로드 링크를 이메일로 보내드립니다.&quot; data-og-host=&quot;www.mozilla.org&quot; data-og-source-url=&quot;https://www.mozilla.org/ko/firefox/&quot; data-og-url=&quot;https://www.mozilla.org/ko/firefox/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/iSKwh/hyXsXjpP7W/S3z1P55VGItC2Jiuf6iw20/img.png?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260,https://scrap.kakaocdn.net/dn/yb1O9/hyXs1lOdLY/MxjA85g3DgMcGFZWnU7MLk/img.jpg?width=350&amp;amp;height=233&amp;amp;face=0_0_350_233,https://scrap.kakaocdn.net/dn/bpCDn7/hyXpva0Wj7/xEytGx8VWAzzrEEqf3PSH0/img.jpg?width=350&amp;amp;height=233&amp;amp;face=0_0_350_233&quot;&gt;&lt;a href=&quot;https://www.mozilla.org/ko/firefox/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.mozilla.org/ko/firefox/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/iSKwh/hyXsXjpP7W/S3z1P55VGItC2Jiuf6iw20/img.png?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260,https://scrap.kakaocdn.net/dn/yb1O9/hyXs1lOdLY/MxjA85g3DgMcGFZWnU7MLk/img.jpg?width=350&amp;amp;height=233&amp;amp;face=0_0_350_233,https://scrap.kakaocdn.net/dn/bpCDn7/hyXpva0Wj7/xEytGx8VWAzzrEEqf3PSH0/img.jpg?width=350&amp;amp;height=233&amp;amp;face=0_0_350_233');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;데스크톱, 모바일 또는 기업용 Firefox 다운로드 - Mozilla&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;데스크톱, iOS, Android 중에서 선택하거나 모바일 다운로드 링크를 이메일로 보내드립니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.mozilla.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 유일한 크로미움 계열이 아닌 브라우저이며 Manifest V2를 지원합니다. 제가 또 힙스터에다가 OSS를 사랑하기 때문에 제가 애용하는 브라우저이기도 합니다. 파이어폭스 브라우저는 Manifest V2 지원을 그대로 진행하고 있으니, 기존 확장 프로그램을 그대로 설치해서 사용하시면 됩니다. 설치 시 크롬에서 그대로 설정을 가져올 수도 있구요.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;AdGuard Desktop (유료)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://adguard.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://adguard.com/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1730478093058&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;AdGuard &amp;mdash; 세계에서 가장 진보된 광고 차단기! 최고의 광고 없는 환경을 경험하세요&quot; data-og-description=&quot;AdGuard는 짜증나는 광고를 없애고, 온라인 추적과 멀웨어로부터 컴퓨터를 지키는 최고의 방법입니다. 광고 없이 빠르고 안전하게 웹 서핑하세요.&quot; data-og-host=&quot;adguard.com&quot; data-og-source-url=&quot;https://adguard.com/&quot; data-og-url=&quot;https://adguard.com/ko/welcome.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dy7VTG/hyXs1e2Jf1/eIWWp6igb7cWG8O096k23k/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://adguard.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://adguard.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dy7VTG/hyXs1e2Jf1/eIWWp6igb7cWG8O096k23k/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;AdGuard &amp;mdash; 세계에서 가장 진보된 광고 차단기! 최고의 광고 없는 환경을 경험하세요&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;AdGuard는 짜증나는 광고를 없애고, 온라인 추적과 멀웨어로부터 컴퓨터를 지키는 최고의 방법입니다. 광고 없이 빠르고 안전하게 웹 서핑하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;adguard.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저 확장 프로그램에서 광고를 차단하는게 막혔다면, 컴퓨터 단에서 실행하면 됩니다. 기존에는 크롬 안에 광고 차단기가 있었다면 이 프로그램은 아예 분리되어 컴퓨터 전체의 광고를 차단합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;솔직히 구글이 왜 이런 결정을 했는지는 이해는 갑니다. 근데 아무리 생각해도 V3를 도입한 이유가 유튜브 광고 차단으로 인한 수익 저하 빼고 찾을 수 없기 때문에 화가 나는거죠. 파이어폭스가 없었고 모든 브라우저가 크로미움 기반이었다면 이번 사태는 좀 끔찍했을 것 같네요..&lt;/p&gt;</description>
      <category>개발</category>
      <author>윤서아</author>
      <guid isPermaLink="true">https://lemongreen.tistory.com/24</guid>
      <comments>https://lemongreen.tistory.com/24#entry24comment</comments>
      <pubDate>Fri, 1 Nov 2024 12:41:50 +0900</pubDate>
    </item>
    <item>
      <title>윈도우에서도 사파리 브라우저 환경 테스트하기</title>
      <link>https://lemongreen.tistory.com/23</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근 들어 개발하면서 사파리에서만 일어나는 문제가 너무 많았다. &amp;lt;video&amp;gt; 태그의 playsinline, svg의 &amp;lt;rect&amp;gt; 태그에 아무런 색을 주지 않으면 투명이 아니라 검은색으로 색칠되는 문제 등등... 프론트엔드를 하면서 유독 사파리만 비표준 혹은 동작이 다른 부분이 많아 속이 터질 지경이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심지어 나는 윈도우를 사랑하는 개발자인데 ㅠ 윈도우에는 사파리 (Webkit) 브라우저가 없다는 게 참 힘들었다. 테스트도 못하는 환경이라니.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이번엔 어떻게든 삽질해서 알아낸 윈도우에서 웹킷 브라우저를 사용할 수 있는 방법을 알려드리겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. WSL&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Windows Subsystem for Linux, 이하 WSL은 윈도우 환경에서 리눅스 시스템을 사용할 수 있게 해주는 기능이다. WSL2에 들어오면서 WSLg라는 기능이 추가되었는데, 무려 리눅스 GUI 프로그램을 그대로 윈도우에서 사용할 수 있는 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스에는 다행히도 Epiphany라는 Webkit 브라우저가 있으니, 해당 브라우저를 설치해서 사용해보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 링크를 참고해 WSL2와 우분투를 설치하자. 아마 내가 직접 쓰는 것보다 해당 링크에 더 상세한 가이드가 있을 것이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/install&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://learn.microsoft.com/ko-kr/windows/wsl/install&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1722579444796&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;WSL 설치&quot; data-og-description=&quot;wsl --install 명령을 사용하여 Linux용 Windows 하위 시스템을 설치합니다. Ubuntu, Debian, SUSE, Kali, Fedora, Pengwin, Alpine 등 원하는 Linux 배포판에서 실행되는 Windows 머신에서 Bash 터미널을 사용할 수 있습니&quot; data-og-host=&quot;learn.microsoft.com&quot; data-og-source-url=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/install&quot; data-og-url=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/install&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cE9EOl/hyWG1PexEZ/Pd0qgoJP6CvCn5xTeP3MfK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/install&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/install&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cE9EOl/hyWG1PexEZ/Pd0qgoJP6CvCn5xTeP3MfK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;WSL 설치&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;wsl --install 명령을 사용하여 Linux용 Windows 하위 시스템을 설치합니다. Ubuntu, Debian, SUSE, Kali, Fedora, Pengwin, Alpine 등 원하는 Linux 배포판에서 실행되는 Windows 머신에서 Bash 터미널을 사용할 수 있습니&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;learn.microsoft.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WSL이 준비되었다면, Epiphany를 설치하고 실행하면 된다!&lt;/p&gt;
&lt;pre id=&quot;code_1722579585284&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo snap install epiphany
sudo apt install epiphany-browser&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1962&quot; data-origin-height=&quot;1239&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buHj6Q/btsIS9zRLJO/kQIB85Y3Eefo41eXNQxnh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buHj6Q/btsIS9zRLJO/kQIB85Y3Eefo41eXNQxnh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buHj6Q/btsIS9zRLJO/kQIB85Y3Eefo41eXNQxnh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuHj6Q%2FbtsIS9zRLJO%2FkQIB85Y3Eefo41eXNQxnh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1962&quot; height=&quot;1239&quot; data-origin-width=&quot;1962&quot; data-origin-height=&quot;1239&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;장점&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WSL 리눅스 가상 환경에서 실행되어서, 무거운 VM 없이 리눅스 + Webkit이라는 환경 테스트를 진행할 수 있다.&lt;/li&gt;
&lt;li&gt;앞으로 설명할 다른 방법에 비해 그나마 UI, 브라우저 자체 기능이 존재하는 편이다.&lt;/li&gt;
&lt;li&gt;설치가 간편하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;단점&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리눅스를 다루기 어려운 사람에겐 힘들 수 있다.&lt;/li&gt;
&lt;li&gt;위의 스크린샷에서도 보이다시피, 한국어 지원이 안 좋다.&lt;/li&gt;
&lt;li&gt;WSLg가 완벽한 건 아니라, HiDPI 환경에서는 브라우저가 너무 작게 보이거나 할 수 있다.&lt;/li&gt;
&lt;li&gt;WSL은 네트워크 격리가 켜져있어서, 기본 설정에서는 localhost:3000 같이 로컬 개발 환경은 접속이 불가능하다. .wslconfig의 networkingMode를 mirrored로 수정하면 해결된다. (&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/wsl/wsl-config&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://learn.microsoft.com/en-us/windows/wsl/wsl-config&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Webkit WinCairo 빌드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹킷 공식 사이트에 적혀있는 윈도우에서 실행하는 방법이다. 빌드된 웹킷에 필요한 DLL을 따로 다운받아, 합쳐서 사용하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.webkit.org/Ports/WindowsPort.html#downloading-build-artifacts-from-buildbot&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.webkit.org/Ports/WindowsPort.html#downloading-build-artifacts-from-buildbot&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1722580109481&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Windows port - WebKit Documentation&quot; data-og-description=&quot;Windows port WebKit had two Windows ports, Apple Windows port and WinCairo port. WinCairo port is called Windows port after the Apple Windows port was deprecated. It is using cairo for the graphics backend, libcurl for the network backend. It supports only&quot; data-og-host=&quot;docs.webkit.org&quot; data-og-source-url=&quot;https://docs.webkit.org/Ports/WindowsPort.html#downloading-build-artifacts-from-buildbot&quot; data-og-url=&quot;https://docs.webkit.org/Ports/WindowsPort.html#downloading-build-artifacts-from-buildbot&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.webkit.org/Ports/WindowsPort.html#downloading-build-artifacts-from-buildbot&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.webkit.org/Ports/WindowsPort.html#downloading-build-artifacts-from-buildbot&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Windows port - WebKit Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Windows port WebKit had two Windows ports, Apple Windows port and WinCairo port. WinCairo port is called Windows port after the Apple Windows port was deprecated. It is using cairo for the graphics backend, libcurl for the network backend. It supports only&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.webkit.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DLL까지 넣어주고, MiniBrowser.exe를 열면 이런 초라한 브라우저가 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1904&quot; data-origin-height=&quot;1109&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NN2iK/btsIUvIx29Y/sizbG9WSRgYDKYDFqZsKJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NN2iK/btsIUvIx29Y/sizbG9WSRgYDKYDFqZsKJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NN2iK/btsIUvIx29Y/sizbG9WSRgYDKYDFqZsKJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNN2iK%2FbtsIUvIx29Y%2FsizbG9WSRgYDKYDFqZsKJ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1904&quot; height=&quot;1109&quot; data-origin-width=&quot;1904&quot; data-origin-height=&quot;1109&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;장점&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹킷의 가장 최신 빌드를 이용해 볼 수 있다.&lt;/li&gt;
&lt;li&gt;개발자 편의 기능이 많다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;단점&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정말 최소한의 브라우저 기능만 가지고 있다.&lt;/li&gt;
&lt;li&gt;WinCairo 그래픽 백엔드가 다이나믹 폰트를 지원하지 않는다. 현재 웹킷의 그래픽 백엔드를 Skia로 포팅하는 중이라는데, 포팅되기 전까지는 다이나믹 폰트를 사용하는 경우엔 이상하게 폰트가 보인다 ㅠ&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언젠가는 크롬, 파이어폭스, 웹킷 브라우저를 3개를 동시에 열고, 마우스 커서가 연동되는 그런 테스팅 툴을 만들고 싶다... ㅠ&lt;/p&gt;</description>
      <category>개발</category>
      <category>e2e</category>
      <category>Safari</category>
      <category>TDD</category>
      <category>webkit</category>
      <category>브라우저</category>
      <category>사파리</category>
      <category>웹킷</category>
      <author>윤서아</author>
      <guid isPermaLink="true">https://lemongreen.tistory.com/23</guid>
      <comments>https://lemongreen.tistory.com/23#entry23comment</comments>
      <pubDate>Fri, 2 Aug 2024 15:45:24 +0900</pubDate>
    </item>
    <item>
      <title>나만의 TTS 만들기 - VITS 모델로 TTS 만들기 회고</title>
      <link>https://lemongreen.tistory.com/22</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;전에 SCE-TTS로 친구의 TTS를 만든 적이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://lemongreen.tistory.com/13&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lemongreen.tistory.com/13&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1709705958934&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;SCE-TTS 버그 수정판과 TTS 제작 경험&quot; data-og-description=&quot;https://sce-tts.github.io/#/v2/index SCE-TTS: 내 목소리로 TTS 만들기 문서를 불러오고 있습니다... sce-tts.github.io 심심해서 SCE-TTS를 만져보고 있었는데, 여러가지 버그가 많았습니다. 근데 프로젝트 개발도 &quot; data-og-host=&quot;lemongreen.tistory.com&quot; data-og-source-url=&quot;https://lemongreen.tistory.com/13&quot; data-og-url=&quot;https://lemongreen.tistory.com/13&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b8whUn/hyVuhS2rwf/rKnAhcTplXI1zSWYQkRpM0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bXY3jS/hyVxpWdiD4/hihXL8TcPSeUrbPgUEKkD1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://lemongreen.tistory.com/13&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://lemongreen.tistory.com/13&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b8whUn/hyVuhS2rwf/rKnAhcTplXI1zSWYQkRpM0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bXY3jS/hyVxpWdiD4/hihXL8TcPSeUrbPgUEKkD1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;SCE-TTS 버그 수정판과 TTS 제작 경험&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;https://sce-tts.github.io/#/v2/index SCE-TTS: 내 목소리로 TTS 만들기 문서를 불러오고 있습니다... sce-tts.github.io 심심해서 SCE-TTS를 만져보고 있었는데, 여러가지 버그가 많았습니다. 근데 프로젝트 개발도&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;lemongreen.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;살짝 아쉬웠던 부분은, 버그를 떠나서 TTS의 퀄리티가 조금 아쉬웠다. train 양이 부족한 건지, 모델이 안 좋은건지, 데이터셋이 모자란건지 노이즈도 있었고, 살짝 기계의 느낌이 많이 났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러던 도중, SCE-TTS의 repo를 뒤져보다 branch에 v3의 흔적이 있길래, 좀 찾아봤는데 Piper라는 TTS 라이브러리를 사용하고 있었다. 상당히 설정도 간단하고, 성능도 좋은 것 같아서 시도하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로는 삽질의 향연이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;중요: 코딩 지식이 없는 사람은 안하는 걸 추천합니다. 너무 힘들거든요....&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 1. Piper는 한국어 지원이 없었다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/rhasspy/piper&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/rhasspy/piper&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1709706546369&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - rhasspy/piper: A fast, local neural text to speech system&quot; data-og-description=&quot;A fast, local neural text to speech system. Contribute to rhasspy/piper development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/rhasspy/piper&quot; data-og-url=&quot;https://github.com/rhasspy/piper&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bzQZb1/hyVxu4hB7x/NOkrTlmUE0Yga5VK45yx4k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/rhasspy/piper&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/rhasspy/piper&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bzQZb1/hyVxu4hB7x/NOkrTlmUE0Yga5VK45yx4k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - rhasspy/piper: A fast, local neural text to speech system&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A fast, local neural text to speech system. Contribute to rhasspy/piper development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;piper를 그대로 훈련에 쓰려고 했는데, 한국어 지원이 없었다.. 하지만 Piper가 VITS라는 모델에 기반하고 있다고 README에 적혀있길래, VITS의 한국어 트레이닝이 가능한 버전을 찾아 나섰다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히도 있었다. README도 친절하고 example도 있어서 기반 지식이 있는 분들은 쉽게 따라할 수 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/ouor/vits&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/ouor/vits&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1709706632102&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - ouor/vits: VITS implementation of Japanese, Chinese, Korean, Sanskrit and Thai&quot; data-og-description=&quot;VITS implementation of Japanese, Chinese, Korean, Sanskrit and Thai - ouor/vits&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/ouor/vits&quot; data-og-url=&quot;https://github.com/ouor/vits&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/blvbV5/hyVxzR3eWr/AKSyySET4gX8E6iGG1GAIk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/ouor/vits&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/ouor/vits&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/blvbV5/hyVxzR3eWr/AKSyySET4gX8E6iGG1GAIk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - ouor/vits: VITS implementation of Japanese, Chinese, Korean, Sanskrit and Thai&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;VITS implementation of Japanese, Chinese, Korean, Sanskrit and Thai - ouor/vits&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히 예전에 녹음한 TTS의 데이터셋과 완벽하게 호환되는 듯 했다. (LJSpeech) 전처리만 거치고 바로 트레이닝에 들어갔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 2. 트레이닝이 왜 안돼니&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전에 콜랩으로 훈련하다가, 콜랩 특유의 불안정성 때문에 콜랩을 갖다버리고 runpod으로 갈아타게 되었다. 훨씬 빠르고, 좋고, 싸다. 여러분도 꼭 써보시라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://runpod.io&quot;&gt;https://runpod.io&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1709707148554&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Rent Cloud GPUs from $0.2/hour&quot; data-og-description=&quot;Global Interoperability Select from 30+ regions across North America, Europe, and South America.&quot; data-og-host=&quot;www.runpod.io&quot; data-og-source-url=&quot;https://runpod.io&quot; data-og-url=&quot;https://www.runpod.io/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://runpod.io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://runpod.io&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Rent Cloud GPUs from $0.2/hour&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Global Interoperability Select from 30+ regions across North America, Europe, and South America.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.runpod.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 다른 곳에 있었다. runpod에 있는 최신 사양의 GPU인 4090과 pytorch 1.13.1 이미지로 작업할려니, CUDA 11.8을 깔아야한다더라. 문제는 CUDA 11.8을 지원하는 torch는 최소 ^2.0.0 버전부터였다. 우리가 사용하는 VITS repo는 2.0 지원이 없는 듯 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 3090으로 다운그레이드 하고 다시 시작했다. 아니 근데 콜랩에선 잘만 되던게 에러를 뿜는 것이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;illegal memory error... 아마 메모리 부족으로 터지는 것이 확실했다. 3090이 메모리가 부족해서 터지는 것이 어이가 없었지만 대안을 찾아나섰다. 아마 체크포인트 로딩이나 세이브 중에 load_state_dict 라는 함수를 호출하는 중에 메모리 부족으로 터지는 듯 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://discuss.pytorch.org/t/load-state-dict-causes-memory-leak/36189/3&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://discuss.pytorch.org/t/load-state-dict-causes-memory-leak/36189/3&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1709706907484&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Load_state_dict causes memory leak&quot; data-og-description=&quot;I&amp;rsquo;ll try that now and then post results here.&quot; data-og-host=&quot;discuss.pytorch.org&quot; data-og-source-url=&quot;https://discuss.pytorch.org/t/load-state-dict-causes-memory-leak/36189/3&quot; data-og-url=&quot;https://discuss.pytorch.org/t/load-state-dict-causes-memory-leak/36189/3&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bTmp36/hyVufAWSOM/ofniN0nikXzLhw0nkjs33K/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/wACJJ/hyVxqt2ULR/ag28z5hNAYLMxuTiDHUqx0/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://discuss.pytorch.org/t/load-state-dict-causes-memory-leak/36189/3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://discuss.pytorch.org/t/load-state-dict-causes-memory-leak/36189/3&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bTmp36/hyVufAWSOM/ofniN0nikXzLhw0nkjs33K/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/wACJJ/hyVxqt2ULR/ag28z5hNAYLMxuTiDHUqx0/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Load_state_dict causes memory leak&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;I&amp;rsquo;ll try that now and then post results here.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;discuss.pytorch.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히도 파이토치 커뮤니티에 해결 방법이 있어, 모든 load_state_dict를 CPU로 옮겨서 로딩하고 GPU로 옮기고, 불필요한 부분은 del도 하고, cache도 지우고.. 별 짓을 다했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 결국 해결하기 가장 좋은 법은 config.json에서 batch size를 줄이는 것이었다. 바로 해결되더라...아나..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 마지막 단계 ONNX로 최적화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제일 큰 문제가 다가왔다. 체크포인트를 그대로 쓸 순 없으니 ONNX로 export를 해야하는데, 지금 쓰고 있는 VITS repo와 piper repo의 onnx export 스크립트가 호환되지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애초에 트레이닝 코드가 조금 다르니까 안되는 게 당연하지만, 머신러닝 관련 코드를 직접 짜보지 않은 나에게는 적잖이 당황할 수 밖에 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 지식을 총동원해서 ONNX를 export 하는 법을 찾고 있었다. piper에서 몇 줄 가져오고... 기존 리포 infer 예제에서 몇 줄 가져오고.. 파이토치 문서에서 가져오고... 참고한 문서는 아래에 추가해놓겠습니다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/rhasspy/piper/blob/master/src/python/piper_train/export_onnx.py&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/rhasspy/piper/blob/master/src/python/piper_train/export_onnx.py&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/ouor/vits/blob/main/infer.ipynb&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/ouor/vits/blob/main/infer.ipynb&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tutorials.pytorch.kr/advanced/super_resolution_with_onnxruntime.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://tutorials.pytorch.kr/advanced/super_resolution_with_onnxruntime.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1709707765621&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;(선택) PyTorch 모델을 ONNX으로 변환하고 ONNX 런타임에서 실행하기&quot; data-og-description=&quot;이 튜토리얼에서는 어떻게 PyTorch에서 정의된 모델을 ONNX 형식으로 변환하고 또 어떻게 그 변환된 모델을 ONNX 런타임에서 실행할 수 있는지에 대해 알아보도록 하겠습니다. ONNX 런타임은 ONNX 모델&quot; data-og-host=&quot;tutorials.pytorch.kr&quot; data-og-source-url=&quot;https://tutorials.pytorch.kr/advanced/super_resolution_with_onnxruntime.html&quot; data-og-url=&quot;https://tutorials.pytorch.kr/advanced/super_resolution_with_onnxruntime.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dmOMRE/hyVxvoAcNp/g5ltUY22EDVakRo4eG0AdK/img.png?width=330&amp;amp;height=94&amp;amp;face=0_0_330_94,https://scrap.kakaocdn.net/dn/e7gcr/hyVxqng16B/uSuBark60t6hBI8zEfeIHK/img.jpg?width=672&amp;amp;height=672&amp;amp;face=0_0_672_672,https://scrap.kakaocdn.net/dn/47k9F/hyVxp2YMtv/5ukcTunVhAkqbFMMlytUSk/img.jpg?width=224&amp;amp;height=224&amp;amp;face=0_0_224_224&quot;&gt;&lt;a href=&quot;https://tutorials.pytorch.kr/advanced/super_resolution_with_onnxruntime.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://tutorials.pytorch.kr/advanced/super_resolution_with_onnxruntime.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dmOMRE/hyVxvoAcNp/g5ltUY22EDVakRo4eG0AdK/img.png?width=330&amp;amp;height=94&amp;amp;face=0_0_330_94,https://scrap.kakaocdn.net/dn/e7gcr/hyVxqng16B/uSuBark60t6hBI8zEfeIHK/img.jpg?width=672&amp;amp;height=672&amp;amp;face=0_0_672_672,https://scrap.kakaocdn.net/dn/47k9F/hyVxp2YMtv/5ukcTunVhAkqbFMMlytUSk/img.jpg?width=224&amp;amp;height=224&amp;amp;face=0_0_224_224');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;(선택) PyTorch 모델을 ONNX으로 변환하고 ONNX 런타임에서 실행하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이 튜토리얼에서는 어떻게 PyTorch에서 정의된 모델을 ONNX 형식으로 변환하고 또 어떻게 그 변환된 모델을 ONNX 런타임에서 실행할 수 있는지에 대해 알아보도록 하겠습니다. ONNX 런타임은 ONNX 모델&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;tutorials.pytorch.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇시간의 삽질 끝에.. 겨우 해냈다. 내가 스스로 ONNX 변환 코드를 짜다니. 내가 다 뿌듯하더라 ㅋㅋㅋ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설마 필요하실 분들을 위해 남겨놓겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1709708034444&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import IPython.display as ipd
import torch
import commons
import utils
from models import SynthesizerTrn
from text.symbols import symbols
from text import text_to_sequence
from scipy.io.wavfile import write


checkpoint_path = ''
config_path = ''
destination_path = 'wow.onnx'

hps = utils.get_hparams_from_file(config_path)
spk_count = hps.data.n_speakers

model_g = SynthesizerTrn(
            len(symbols),
            hps.data.filter_length // 2 + 1,
            hps.train.segment_size // hps.data.hop_length,
            n_speakers=hps.data.n_speakers,
            **hps.model)

model_g.eval()
utils.load_checkpoint(checkpoint_path, model_g, None)

def get_text(text):
    text_norm = text_to_sequence(text, hps.data.text_cleaners)
    if hps.data.add_blank:
        text_norm = commons.intersperse(text_norm, 0)
    text_norm = torch.LongTensor(text_norm)
    return text_norm

with torch.no_grad():
    model_g.dec.remove_weight_norm()
    
txt = get_text(&quot;학습은 잘 마치셨나요? 좋은 결과가 있길 바래요.&quot;)
input_text = txt.unsqueeze(0)
input_text_len = torch.LongTensor([txt.size(0)])
sid = torch.LongTensor([0])

arg = (output_text, output_text_len)

def infer_forward(text, text_lengths):
    audio = model_g.infer(
        text,
        text_lengths,
        noise_scale=.667,
        length_scale=1,
        noise_scale_w=0.8,
        sid=torch.LongTensor([0]),
    )[0][0,0]

    return audio

model_g.forward = infer_forward
model_g.cpu()

output = infer_forward(input_text, input_text_len).data.float().numpy()
print(output)
write(f'infer/onnx.wav', hps.data.sampling_rate, output)
ipd.display(ipd.Audio(output, rate=hps.data.sampling_rate, normalize=False))

torch.onnx.export(model_g, arg, destination_path,
    verbose=False,
    opset_version=15,
    input_names=[&quot;text&quot;, &quot;text_lengths&quot;],
    output_names=[&quot;output&quot;],
    dynamic_axes={
        &quot;text&quot;: {0: &quot;batch_size&quot;, 1: &quot;phonemes&quot;},
        &quot;text_lengths&quot;: {0: &quot;batch_size&quot;},
        &quot;output&quot;: {0: &quot;batch_size&quot;, 1: &quot;time&quot;},
    },
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ouor/vits 리포에 의존적이고, 하드코딩도 많으니 알아서 조금씩 수정하셔서 쓰시면 될 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ONNX 사용은 아래를 참고해주세용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1709708258954&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import onnxruntime
import IPython.display as ipd
import torch
import commons
import utils
from text.symbols import symbols
from text import text_to_sequence
import numpy as np
from scipy.io.wavfile import write

ort_session = onnxruntime.InferenceSession(&quot;wow.onnx&quot;)
checkpoint_path = ''
config_path = ''
hps = utils.get_hparams_from_file(config_path)

def get_text(text):
    text_norm = text_to_sequence(text, hps.data.text_cleaners)
    if hps.data.add_blank:
        text_norm = commons.intersperse(text_norm, 0)
    # text_norm = torch.LongTensor(text_norm)
    text_norm = np.array(text_norm, dtype=np.int64)
    return text_norm

txt = get_text(&quot;학습은 잘 마치셨나요? 좋은 결과가 있길 바래요.&quot;)
input_text = np.expand_dims(txt, axis=0)
input_text_len = np.array([txt.shape[0]], dtype=np.int64)

arg = {
    &quot;text&quot;: input_text,
    &quot;text_lengths&quot;: input_text_len,
}

# ONNX 런타임에서 계산된 결과값
ort_outs = ort_session.run([&quot;output&quot;], arg)
output = ort_outs[0]

write(f'infer/onnx.wav', hps.data.sampling_rate, output)
ipd.display(ipd.Audio(output, rate=hps.data.sampling_rate, normalize=False))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;onnx-simpilfier 사용하시면 용량도 줄고, 성능도 좋아집니다. 저의 경우에는 onnx 로딩에 0.9~초, inference에 0.7~초 걸리는 것 같더라구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/daquexian/onnx-simplifier&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/daquexian/onnx-simplifier&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1709708315120&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - daquexian/onnx-simplifier: Simplify your onnx model&quot; data-og-description=&quot;Simplify your onnx model. Contribute to daquexian/onnx-simplifier development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/daquexian/onnx-simplifier&quot; data-og-url=&quot;https://github.com/daquexian/onnx-simplifier&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b61gXL/hyVugs6CnV/BBwdCQumxILbYJRGmnsLY0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/daquexian/onnx-simplifier&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/daquexian/onnx-simplifier&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b61gXL/hyVugs6CnV/BBwdCQumxILbYJRGmnsLY0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - daquexian/onnx-simplifier: Simplify your onnx model&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Simplify your onnx model. Contribute to daquexian/onnx-simplifier development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드들이 아주 더럽습니다..ㅋㅋㅋ 급해서 메모장에서 바로바로 갈겨 쓴거라 그래요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쓰다보니 생각보다 커스텀한 구간이 많더라구요. inference 부분만 구현해놨긴 한데, 나중에 제대로 짜고 확장해서 tts-server도 만들어야겠습니다.. 자바스크립트로도 onnxruntime이 있다면 훨씬 좋았을텐데..ㅋㅋ 차피 numpy가 필요해서 안될 것 같네요 ㅋㅋ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+ 테스트 파일들은 example을 참고해주세요. 테스트 결과 파일은 제 목소리도 아닌 친구의 목소리기 때문에 공유해드릴 수가 없습니다.&lt;/p&gt;</description>
      <category>개발</category>
      <author>윤서아</author>
      <guid isPermaLink="true">https://lemongreen.tistory.com/22</guid>
      <comments>https://lemongreen.tistory.com/22#entry22comment</comments>
      <pubDate>Wed, 6 Mar 2024 16:08:17 +0900</pubDate>
    </item>
    <item>
      <title>Nuxt 3 간단 가이드 - useFetch의 장점, 단점, 팁</title>
      <link>https://lemongreen.tistory.com/21</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드 예제 - &lt;a href=&quot;https://stackblitz.com/edit/nuxt-usefetch-dollarfetch&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://stackblitz.com/edit/nuxt-usefetch-dollarfetch&lt;/a&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1702303593998&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Nuxt - useFetch, $fetch - StackBlitz&quot; data-og-description=&quot;Create a new Nuxt project, module, layer or start from a theme with our collection of starters.&quot; data-og-host=&quot;stackblitz.com&quot; data-og-source-url=&quot;https://stackblitz.com/edit/nuxt-usefetch-dollarfetch&quot; data-og-url=&quot;https://stackblitz.com/edit/nuxt-usefetch-dollarfetch&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cLXzpr/hyULYyAFkX/1tqKe2gdwjdZ85oz43nQ0K/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/b8lPc2/hyUIFtVmjl/xxo84rWWQZff83NFNn5UP0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://stackblitz.com/edit/nuxt-usefetch-dollarfetch&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stackblitz.com/edit/nuxt-usefetch-dollarfetch&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cLXzpr/hyULYyAFkX/1tqKe2gdwjdZ85oz43nQ0K/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/b8lPc2/hyUIFtVmjl/xxo84rWWQZff83NFNn5UP0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Nuxt - useFetch, $fetch - StackBlitz&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Create a new Nuxt project, module, layer or start from a theme with our collection of starters.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stackblitz.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Nuxt 특징 이해하기 - Nuxt는 리액트의 SSR 라이브러리처럼 따로 서버사이드 코드 / 클라이언트 사이드 코드를 분리하지 않는다.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트에 의존하는 부분은 알아서 내가 if (process.client) 등을 걸어서 처리해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드가 분리되지 않아 간단하지만 오히려 고도화가 되면 불편해지는 단점을 낳는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 사진은 Remix인데, 서버 사이드 코드는 깔끔하게 loader() 함수로 빠지고 props로 제공받는 걸 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;453&quot; data-origin-height=&quot;183&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNhSDi/btsBMXMIKMd/8uaVERx9El69I7KrbtWS30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNhSDi/btsBMXMIKMd/8uaVERx9El69I7KrbtWS30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNhSDi/btsBMXMIKMd/8uaVERx9El69I7KrbtWS30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNhSDi%2FbtsBMXMIKMd%2F8uaVERx9El69I7KrbtWS30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;453&quot; height=&quot;183&quot; data-origin-width=&quot;453&quot; data-origin-height=&quot;183&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt의 경우는 클라이언트와 서버의 경계가 없는 것처럼 쓸 수 있다. 처음에는 아주 편하지만 고도화 되면 불편을 야기할 수도 있다. (localStorage 액세스 같은 부분)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;444&quot; data-origin-height=&quot;187&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1RAMU/btsBKl1vyQo/SKk32DAGsF86boZB4wDTB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1RAMU/btsBKl1vyQo/SKk32DAGsF86boZB4wDTB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1RAMU/btsBKl1vyQo/SKk32DAGsF86boZB4wDTB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1RAMU%2FbtsBKl1vyQo%2FSKk32DAGsF86boZB4wDTB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;444&quot; height=&quot;187&quot; data-origin-width=&quot;444&quot; data-origin-height=&quot;187&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;useFetch - SSR에 특화 &lt;a href=&quot;https://nuxt.com/docs/api/composables/use-fetch&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nuxt.com/docs/api/composables/use-fetch&lt;/a&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;장점&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;SSR에 특화됨, server rendering -&amp;gt; client hydration 과정에서 중복 호출되지 않음.&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkm4oz/btsBGDu2joL/W7GaY2CvwAqUaO59tBi000/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkm4oz/btsBGDu2joL/W7GaY2CvwAqUaO59tBi000/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkm4oz/btsBGDu2joL/W7GaY2CvwAqUaO59tBi000/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbkm4oz%2FbtsBGDu2joL%2FW7GaY2CvwAqUaO59tBi000%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;749&quot; height=&quot;124&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;124&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사용에 용이하게 data, error, pending 등의 return value (ref type) 제공 (isLoading 선언과의 이별)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;775&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XDPT4/btsBKjJjkbm/hVDOAuNxHL6os6y1SzjI40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XDPT4/btsBKjJjkbm/hVDOAuNxHL6os6y1SzjI40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XDPT4/btsBKjJjkbm/hVDOAuNxHL6os6y1SzjI40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXDPT4%2FbtsBKjJjkbm%2FhVDOAuNxHL6os6y1SzjI40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;775&quot; height=&quot;309&quot; data-origin-width=&quot;775&quot; data-origin-height=&quot;309&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단점&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;useFetch().catch, try가 작동하지 않는다.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 요청이 완료되기도 전에 status, pending 등을 전달해주기 위해 에러 여부와 관계 없이 무조건 promise가 resolve가 된다. 따로 error와 status 데이터를 이용해 걸러 줄 필요가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사용자 인터랙션에 사용하기 안 좋다.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 말한 것 처럼 초기에 resolve가 되기 때문에, 리액티브하게 값이 업데이트 되지 않는 함수들에는 아주 치명적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 loadComments()에 useFetch를 넣어 사용한다면, 함수가 실행되었을 때 바로 pending: true를 뱉어내고 resolve 되어 함수가 끝난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 이미지에서 comments는 null, commentsStatus는 'idle'로 끝난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연하게도 더 이상의 업데이트가 생기지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 함수가 아닌데도 왜 작동하지 않냐면, &amp;lt;script setup&amp;gt; 안의 ref들은 모두 reactive하지만, if (process.client) 에서 스코프 안에 갇혀버려 더 이상 값이 바뀌어도 업데이트 되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다르게 말해서 스코프에 갇히는 순간 바보가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;473&quot; data-origin-height=&quot;273&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N8gdF/btsBQtkhCAY/PDXH6oAexmsPRYwvMVYAQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N8gdF/btsBQtkhCAY/PDXH6oAexmsPRYwvMVYAQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N8gdF/btsBQtkhCAY/PDXH6oAexmsPRYwvMVYAQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN8gdF%2FbtsBQtkhCAY%2FPDXH6oAexmsPRYwvMVYAQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;473&quot; height=&quot;273&quot; data-origin-width=&quot;473&quot; data-origin-height=&quot;273&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;then 말고 await을 이용하면 해결 되지 않나? 아니다. 아래처럼 await을 써도 결국 돌아오는건 pending: true와 data: false 이기때문에 따로 watch를 걸어줘야한다. 매우 더럽고 성능 저하가 생길 수도 있으니 절대 피하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;388&quot; data-origin-height=&quot;354&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DOUd9/btsBQR6hzbD/eBzf8uToFSWytKIhBH0Kd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DOUd9/btsBQR6hzbD/eBzf8uToFSWytKIhBH0Kd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DOUd9/btsBQR6hzbD/eBzf8uToFSWytKIhBH0Kd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDOUd9%2FbtsBQR6hzbD%2FeBzf8uToFSWytKIhBH0Kd1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;388&quot; height=&quot;354&quot; data-origin-width=&quot;388&quot; data-origin-height=&quot;354&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사용자 인터랙션에서는 $fetch를 사용하자.&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7tTOj/btsBKhEKaur/HLzwST1ZEGues3WBMCbSbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7tTOj/btsBKhEKaur/HLzwST1ZEGues3WBMCbSbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7tTOj/btsBKhEKaur/HLzwST1ZEGues3WBMCbSbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7tTOj%2FbtsBKhEKaur%2FHLzwST1ZEGues3WBMCbSbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;418&quot; height=&quot;300&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>개발</category>
      <category>NUXT</category>
      <category>Nuxt 3</category>
      <category>nuxt.js</category>
      <category>ssr</category>
      <category>useFetch</category>
      <category>vue</category>
      <category>프론트엔드</category>
      <author>윤서아</author>
      <guid isPermaLink="true">https://lemongreen.tistory.com/21</guid>
      <comments>https://lemongreen.tistory.com/21#entry21comment</comments>
      <pubDate>Mon, 11 Dec 2023 23:20:14 +0900</pubDate>
    </item>
    <item>
      <title>Nuxt 3 - useFetch가 첫 로딩 때 항상 null이에요</title>
      <link>https://lemongreen.tistory.com/16</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;로그인 된 유저 데이터를 가져오는데 자꾸 요청에 null이 돌아와서 난감이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고 보니 if (process.server) 등으로 서버 실행을 걸러내거나, Client-Only가 되었을 때 await으로 useFetch 등을 이용해 요청을 하면 hydration이 끝날 때까지 요청은 수행되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단 설명: client only로 작동하는 await useFetch는 첫 요청을 하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결책: $fetch를 쓰자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;119&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byzBrW/btsw6CGnH2q/oKXihe2AWyntdPIrZ2ruc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byzBrW/btsw6CGnH2q/oKXihe2AWyntdPIrZ2ruc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byzBrW/btsw6CGnH2q/oKXihe2AWyntdPIrZ2ruc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyzBrW%2Fbtsw6CGnH2q%2FoKXihe2AWyntdPIrZ2ruc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;784&quot; height=&quot;119&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;119&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nuxt.com/docs/api/composables/use-fetch&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://nuxt.com/docs/api/composables/use-fetch&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발</category>
      <author>윤서아</author>
      <guid isPermaLink="true">https://lemongreen.tistory.com/16</guid>
      <comments>https://lemongreen.tistory.com/16#entry16comment</comments>
      <pubDate>Wed, 4 Oct 2023 23:21:02 +0900</pubDate>
    </item>
    <item>
      <title>유튜브 무료로 쉽게 다운로드 하는 법</title>
      <link>https://lemongreen.tistory.com/15</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;예전에 4K Downloader를 많이 썼는데, 이게 유료화가 되어서 결국 안 쓰게 되었죠&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다고 yt-dlp를 쓰자니, 비개발자에겐 많이 사용하기가 힘듭니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 찾은 yt-dlp-gui입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/kannagi0303/yt-dlp-gui/releases&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/kannagi0303/yt-dlp-gui/releases&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1684152297134&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Releases &amp;middot; kannagi0303/yt-dlp-gui&quot; data-og-description=&quot;Windows GUI for yt-dlp. Contribute to kannagi0303/yt-dlp-gui development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/kannagi0303/yt-dlp-gui/releases&quot; data-og-url=&quot;https://github.com/kannagi0303/yt-dlp-gui/releases&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/5tJn4/hySCPScYeS/eBr6782jM5pC6d0AaPx77K/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/kannagi0303/yt-dlp-gui/releases&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/kannagi0303/yt-dlp-gui/releases&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/5tJn4/hySCPScYeS/eBr6782jM5pC6d0AaPx77K/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Releases &amp;middot; kannagi0303/yt-dlp-gui&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Windows GUI for yt-dlp. Contribute to kannagi0303/yt-dlp-gui development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 다운받으실 수 있고, 사용법은 간단합니다 링크 넣고 다운로드 하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;570&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cin5qw/btsf3fHOZuj/vDHlAf8GKjKClWoR0AapV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cin5qw/btsf3fHOZuj/vDHlAf8GKjKClWoR0AapV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cin5qw/btsf3fHOZuj/vDHlAf8GKjKClWoR0AapV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcin5qw%2Fbtsf3fHOZuj%2FvDHlAf8GKjKClWoR0AapV1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;755&quot; height=&quot;570&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;570&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>4kdownload</category>
      <category>4kdownloader</category>
      <category>YouTube</category>
      <category>yt-dlp</category>
      <category>ytdlp</category>
      <category>유튜브</category>
      <category>유튜브다운로더</category>
      <category>유튜브다운로드</category>
      <author>윤서아</author>
      <guid isPermaLink="true">https://lemongreen.tistory.com/15</guid>
      <comments>https://lemongreen.tistory.com/15#entry15comment</comments>
      <pubDate>Mon, 15 May 2023 21:06:11 +0900</pubDate>
    </item>
    <item>
      <title>Vue의 새로운 상태 관리 라이브러리 Pinia를 써본 경험과 Vuex와의 차이점</title>
      <link>https://lemongreen.tistory.com/14</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;전체적으로 Pinia가 좀 더 최신 트렌드를 반영하고, 자바스크립트 다워졌다고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 React 라이브러리처럼 쓸 수 있게 변했다 해야하나? 전체적으로 Vue 3가 독자 문법같은 노선에서 자바스크립트 표준 문법 노선으로 간 것 같아 마음에 듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pinia의 경우에는 state 선언 방법이 이렇습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1682236144159&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { defineStore } from 'pinia'

export const useProductStore = defineStore('product', {
  state: () =&amp;gt; ({
    products: [
      { name: 'Shoes', price: 30000 },
      { name: 'Apple', price: 5000 }
    ]
  }),
  getters: {
    productCount(state) {
      return state.products.length
    },
    productsCheaperThan(state) {
      return (price) =&amp;gt; (
        state.products.filter(product =&amp;gt;
          product.price &amp;lt; price
        )
      )
    }
  },
  actions: {
    addProduct() {
      this.products.push()
    }
  }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 defineStore를 사용하여 store를 선언하고, state와 getter, action을 선언할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vuex 3.x의 경우에는 Vuex.Store를 만들어서 export한 후에 Vue에서 use하게 하는 방식이었죠.&lt;/p&gt;
&lt;pre id=&quot;code_1682236288948&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용법은 조금 차이가 납니다. Vuex 3.x의 경우에는 Vue 컴포넌트에서 this.$store.state나 store.state로 접근한 반면에, Pinia에서는 직접 import하여 사용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1682236400804&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup&amp;gt;
  import { useProductStore } from './stores/ProductStore'
  const store = useProductStore()
&amp;lt;/script&amp;gt;
&amp;lt;template&amp;gt;
  &amp;lt;ul&amp;gt;
    &amp;lt;li v-for=&quot;product in store.products&quot;&amp;gt;
      ...
    &amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
  &amp;lt;p&amp;gt;{{ store.productCount }}&amp;lt;/p&amp;gt;
  &amp;lt;ul&amp;gt;
    &amp;lt;li v-for=&quot;product in store.productsCheaperThan(10000)&quot;&amp;gt;
      ...
    &amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
  &amp;lt;button @click=&quot;store.addProduct(somethingProduct)&quot;&amp;gt;Add&amp;lt;/button&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;약간 React를 보는 것 같지 않나요? store를 import하고, useProductStore를 사용하여 store 변수를 따로 만들어주는 것까지.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 Vuex 3.x에 비해 이 방법이 매우 마음에 듭니다. 각자 이렇게 import하는 게 번거로울 수 있지만, 전역 state로 몰빵하는 것 보단 낫고, 요즘 트렌드에 맞춰 가는 것 같아서 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue Mastery에서 Pinia Cheatsheet를 공유하고 있으니 꼭 참고하세요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 Devtool에서는 이곳에서! 변수를 확인 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;144&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCcwFQ/btsbSMqz1Ee/1LjCePh0EIIPXloCZVtFek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCcwFQ/btsbSMqz1Ee/1LjCePh0EIIPXloCZVtFek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCcwFQ/btsbSMqz1Ee/1LjCePh0EIIPXloCZVtFek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCcwFQ%2FbtsbSMqz1Ee%2F1LjCePh0EIIPXloCZVtFek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;564&quot; height=&quot;144&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;144&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://pinia.vuejs.org&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://pinia.vuejs.org&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1682236532509&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Pinia | The intuitive store for Vue.js&quot; data-og-description=&quot;Intuitive, type safe, light and flexible Store for Vue&quot; data-og-host=&quot;pinia.vuejs.org&quot; data-og-source-url=&quot;https://pinia.vuejs.org&quot; data-og-url=&quot;https://pinia.vuejs.org&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/hN1nI/hySmVZEqpF/5pU5qFPumdJgdtSkvvmkO1/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640&quot;&gt;&lt;a href=&quot;https://pinia.vuejs.org&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://pinia.vuejs.org&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/hN1nI/hySmVZEqpF/5pU5qFPumdJgdtSkvvmkO1/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Pinia | The intuitive store for Vue.js&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Intuitive, type safe, light and flexible Store for Vue&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;pinia.vuejs.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/TIL</category>
      <category>pinia</category>
      <category>vue</category>
      <category>vuex</category>
      <author>윤서아</author>
      <guid isPermaLink="true">https://lemongreen.tistory.com/14</guid>
      <comments>https://lemongreen.tistory.com/14#entry14comment</comments>
      <pubDate>Sun, 23 Apr 2023 16:55:45 +0900</pubDate>
    </item>
    <item>
      <title>SCE-TTS 버그 수정판과 TTS 제작 경험</title>
      <link>https://lemongreen.tistory.com/13</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sce-tts.github.io/#/v2/index&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://sce-tts.github.io/#/v2/index&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1678984070700&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;SCE-TTS: 내 목소리로 TTS 만들기&quot; data-og-description=&quot;문서를 불러오고 있습니다...&quot; data-og-host=&quot;sce-tts.github.io&quot; data-og-source-url=&quot;https://sce-tts.github.io/#/v2/index&quot; data-og-url=&quot;https://sce-tts.github.io/#/v2/index&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://sce-tts.github.io/#/v2/index&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sce-tts.github.io/#/v2/index&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;SCE-TTS: 내 목소리로 TTS 만들기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;문서를 불러오고 있습니다...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sce-tts.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심심해서 SCE-TTS를 만져보고 있었는데, 여러가지 버그가 많았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 프로젝트 개발도 멈춘 것 같고해서, 수정판을 만들어서 공유합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러가지 라이선스가 얽힌 문제때문에 깃허브엔 올리지 않겠습니다. 파일 정리도 안되있구요..ㅎㅎ&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;제작자 : &lt;a href=&quot;https://github.com/sce-tts&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/sce-tts, &lt;/a&gt;&lt;a href=&quot;https://github.com/MycroftAI/mimic-recording-studio&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/MycroftAI/mimic-recording-studio&lt;/a&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;다운로드: &lt;/b&gt;&lt;a href=&quot;https://junsu.io/run.zip&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;https://junsu.io/run.zip&lt;/b&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;압축 해제 후 위의 문서에 나온대로 사용하시면 됩니다. (run-server.bat)&lt;/b&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;수정한 소스는 &lt;a href=&quot;https://junsu.io/mimic-recording-studio-master.zip&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://junsu.io/mimic-recording-studio-master.zip&lt;/a&gt; 에 있습니다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;backend는 기존의 SCE-TTS 백엔드에서 저장 문제를 해결한 버전입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PR:&lt;a href=&quot;https://github.com/sce-tts/mimic-recording-studio/pull/1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;https://github.com/sce-tts/mimic-recording-studio/pull/1&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1682235063519&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Set encoding when read exists meta data file for append data. by smartse0k &amp;middot; Pull Request #1 &amp;middot; sce-tts/mimic-recording-studio&quot; data-og-description=&quot;2회차 녹음 이후부터 인코딩 오류가 발생하여 기존 메타데이터 파일을 읽어올 때 인코딩을 지정하도록 하였습니다. 영향받는 함수 save_meta_data() Fix encoding problem when record and save an audio after first re&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/sce-tts/mimic-recording-studio/pull/1&quot; data-og-url=&quot;https://github.com/sce-tts/mimic-recording-studio/pull/1&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bATTph/hySm493FVP/4OBnJ2bqPY8OnBjCVyZNRK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/sce-tts/mimic-recording-studio/pull/1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/sce-tts/mimic-recording-studio/pull/1&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bATTph/hySm493FVP/4OBnJ2bqPY8OnBjCVyZNRK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Set encoding when read exists meta data file for append data. by smartse0k &amp;middot; Pull Request #1 &amp;middot; sce-tts/mimic-recording-studio&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;2회차 녹음 이후부터 인코딩 오류가 발생하여 기존 메타데이터 파일을 읽어올 때 인코딩을 지정하도록 하였습니다. 영향받는 함수 save_meta_data() Fix encoding problem when record and save an audio after first re&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고한 파일: &lt;a href=&quot;https://github.com/sce-tts/mimic-recording-studio/pull/1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/sce-tts/mimic-recording-studio/pull/1/files&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;frontend는 getUserMedia의 변경으로 인해 오래된 mimic-recording-studio가 마이크를 못 불러오는 버그를 고친 버전입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본: &lt;a href=&quot;https://github.com/MycroftAI/mimic-recording-studio&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/MycroftAI/mimic-recording-studio&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1682235201746&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - MycroftAI/mimic-recording-studio: Mimic Recording Studio is a Docker-based application you can install to record voice &quot; data-og-description=&quot;Mimic Recording Studio is a Docker-based application you can install to record voice samples, which can then be trained into a TTS voice with Mimic2 - GitHub - MycroftAI/mimic-recording-studio: Mim...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/MycroftAI/mimic-recording-studio&quot; data-og-url=&quot;https://github.com/MycroftAI/mimic-recording-studio&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gdqEU/hySmSBPnwk/DsaEz3krZrvWdBtb9Wq8N0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/MycroftAI/mimic-recording-studio&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/MycroftAI/mimic-recording-studio&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gdqEU/hySmSBPnwk/DsaEz3krZrvWdBtb9Wq8N0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - MycroftAI/mimic-recording-studio: Mimic Recording Studio is a Docker-based application you can install to record voice&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Mimic Recording Studio is a Docker-based application you can install to record voice samples, which can then be trained into a TTS voice with Mimic2 - GitHub - MycroftAI/mimic-recording-studio: Mim...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수정한 부분: &lt;a href=&quot;https://github.com/MycroftAI/mimic-recording-studio/blob/master/frontend/src/App/components/Recorder.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/MycroftAI/mimic-recording-studio/blob/master/frontend/src/App/components/Recorder.js&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 문의 사항이 있으시면 bananamilk452@gmail.com이나 댓글로 써주시면 감사하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;TTS를 두 개 만들면서 얻은 노하우&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쩌다 지인 TTS를 만드는 프로젝트를 하게 되어서...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 녹음 할 때 빠르게 말하면 TTS도 빠르게 나옵니다. 평소 말하는 속도로 말해주세요. 3시간 녹음 귀찮다고 랩하듯이 해버리면 TTS도 랩을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 녹음 양이 많으면 많을 수록 TTS에 기계적인 느낌이 빠지고 자연스러워집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 훈련 시간과 퀄리티는 정비례 하지 않습니다. 저는 30만 체크포인트, 31000 체크포인트에서 보통 작업을 끝냈습니다. Tensorboard에서 loss를 보시면 알겠지만 점점 줄어드는데에도 한계가 있습니다. 잘 확인하시고 적당한 부분에서 훈련을 끝내시길 바랍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Colab에서 TTS를 제작하는 노트북을 사용하다보면 오류가 좀 있습니다. numba의 버전을 0.52에서 0.53으로 올려야하는 등.. Colab이 아닌 다른 상위 버전 GPU에서 하려면 전체적으로 버전을 다 올려야하는 등... 이 프로젝트는 비 개발자에게 친화적이지 않습니다!! 꼭.. 스트레스로 머리가 빠지기 싫으시다면 개발자에게 부탁하시거나.. 포기하는게 낫습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 마이크 소리가 너무 작으면 안됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 마이크 음질과 퀄리티는 어느정도 비례합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. mimic-recording-studio는 메모리 누수가 좀 있는지, 가끔가다 렉이 걸려 녹음이 끊기는 경우가 있습니다. 몇십개 한 후에는 새로고침을 해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발</category>
      <category>SCE-TTS</category>
      <category>TTS</category>
      <author>윤서아</author>
      <guid isPermaLink="true">https://lemongreen.tistory.com/13</guid>
      <comments>https://lemongreen.tistory.com/13#entry13comment</comments>
      <pubDate>Fri, 17 Mar 2023 01:31:20 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트에서 Date 객체를 생성하면 하루 전인 날짜가 나오는 이유</title>
      <link>https://lemongreen.tistory.com/12</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;어느 날, 일기장을 토이 프로젝트로 만들고 있는데, 왠 날짜를 받아서 해당 날짜의 일기를 뿌려주는 함수가 작동하지 않고 있었다. 어쩌다보니 2022/12/22처럼 /로 구분 된 String을 Date 객체로 만들어 사용하고 있었는데, 이게 무슨 일이람?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;652&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5aGa5/btrWLWT5hDx/vKSMGPrUJIfpeVT0JbkIkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5aGa5/btrWLWT5hDx/vKSMGPrUJIfpeVT0JbkIkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5aGa5/btrWLWT5hDx/vKSMGPrUJIfpeVT0JbkIkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5aGa5%2FbtrWLWT5hDx%2FvKSMGPrUJIfpeVT0JbkIkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;980&quot; height=&quot;652&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;652&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 기가 막힌 언어가 아닐 수 없다. &lt;b&gt;/ 로 구분해서 날짜를 넣으면 KST 시각으로 인식해서 1월 1일 15시&lt;/b&gt;로 출력이 되고, &lt;b&gt;- 로 구분해서 넣으면 UTC로 인식&lt;/b&gt;해서 잘 들어가는 기이한 현상을 볼 수 있었다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여담으로, 이 문제를 발견하게 된 이유는 일기장 프론트엔드는 KST로 출력되고, DB에서는 UTC 기준으로 나오고, JS에서는 KST로 받아서 UTC로 출력하고, DB에서 받은 UTC Date 객체를 String으로 바꿔버렸는데 그걸 KST로 착각해서 머리가 터져 아무 문제 없는 코드를 수정하고 있었다. 그래도 뭐 하나라도 배우고 가서 기분은 좋다. ㅠ&lt;/p&gt;</description>
      <category>개발/TIL</category>
      <category>Date</category>
      <category>date-fns</category>
      <category>javascript</category>
      <category>moment.js</category>
      <category>new Date</category>
      <category>자바스크립트</category>
      <category>자스</category>
      <author>윤서아</author>
      <guid isPermaLink="true">https://lemongreen.tistory.com/12</guid>
      <comments>https://lemongreen.tistory.com/12#entry12comment</comments>
      <pubDate>Fri, 20 Jan 2023 04:23:31 +0900</pubDate>
    </item>
    <item>
      <title>backdrop-filter가 사파리에서 작동 안해요!!</title>
      <link>https://lemongreen.tistory.com/11</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;정답: -webkit-backdrop-filter를 추가로 사용하기.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사파리에서는 vendor prefix와 함께 사용해야한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;589&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gj1sp/btrMnl4vcjT/4K9mPoMAdShkSeQXQooZqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gj1sp/btrMnl4vcjT/4K9mPoMAdShkSeQXQooZqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gj1sp/btrMnl4vcjT/4K9mPoMAdShkSeQXQooZqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGj1sp%2FbtrMnl4vcjT%2F4K9mPoMAdShkSeQXQooZqK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;811&quot; height=&quot;589&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;589&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>개발/TIL</category>
      <category>backdrop</category>
      <category>CSS</category>
      <category>HTML</category>
      <category>Safari</category>
      <category>사파리</category>
      <author>윤서아</author>
      <guid isPermaLink="true">https://lemongreen.tistory.com/11</guid>
      <comments>https://lemongreen.tistory.com/11#entry11comment</comments>
      <pubDate>Sun, 18 Sep 2022 11:14:03 +0900</pubDate>
    </item>
  </channel>
</rss>