Skip to content

Instantly share code, notes, and snippets.

@rptb1
Last active October 31, 2021 21:28
Show Gist options
  • Save rptb1/cba49b801825ef3fffe4698dd96e360e to your computer and use it in GitHub Desktop.
Save rptb1/cba49b801825ef3fffe4698dd96e360e to your computer and use it in GitHub Desktop.
Convert YouTube subscriptions exported via Google Takeout into OPML
# youtube-subs-to-opml.py -- Convert YouTube subscriptions exported
# via Google Takeout into OPML
#
# See <https://www.reddit.com/r/youtube/comments/jqlks2/where_did_opml_export_go/gcdii2n/>.
#
# Usage:
# python3 youtube-subs-to-opml.py < ~/Downloads/Takeout/YouTube\ and\ YouTube\ Music/subscriptions/subscriptions.json > yt-subs.opml
import sys
import json
from xml.sax.saxutils import escape
subs = json.load(sys.stdin)
if len(subs) > 0:
parent = escape(subs[0]['snippet']['channelId'])
print(f'''<?xml version="1.0" encoding="UTF-8"?>
<opml version="1.0">
<body>
<outline title="YouTube {parent}" text="YouTube {parent}">
''')
for sub in subs:
title = escape(sub['snippet']['title'])
channelId = escape(sub['snippet']['resourceId']['channelId'])
print(f''' <outline title="{title}"
text="{title}"
xmlUrl="https://www.youtube.com/feeds/videos.xml?channel_id={channelId}"
htmlUrl="https://www.youtube.com/channel/{channelId}" />
''')
print('''
</outline>
</body>
</opml>
''')
# Open source under BSD-2-Clause
# <https://opensource.org/licenses/BSD-2-Clause>
#
# Copyright 2021 Richard Brooksby <rptb1>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
@rptb1
Copy link
Author

rptb1 commented Dec 21, 2020

Pretty useful, thanks a lot. Although I had to manually add a </opml> after the </body> before feedly would accept the file as valid OPML

Oops! I think my reader didn't care, so I didn't notice this. Fixed. Thanks.

@Hinechan
Copy link

Hello i'm pretty new to python, i'm trying to run your .py file.

I checked python is running well, I also put the json file in the correct place as you noted above. I used cmd to run the python but it has no feedback/return.

Is there any way to know if it's running correctly? Or perhaps my json file is a little big and it will take some time?

Please help because youtube subscription really messed up now, Thank you in advanced.

@jeosadn
Copy link

jeosadn commented Oct 29, 2021

Since the last time I used this, YouTube changed the subscription list to csv instead of json. I created a fork here to support both json and csv

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment