mirror of
https://gitea.invidious.io/iv-org/invidious.git
synced 2024-08-15 00:53:41 +00:00
added youtube playlist import functionality. fixes issue #2114
Signed-off-by: Gavin Johnson <gavinj1984@gmail.com>
This commit is contained in:
parent
855202e40e
commit
96344f28b4
5 changed files with 86 additions and 72 deletions
|
@ -33,7 +33,7 @@
|
||||||
"Import": "Import",
|
"Import": "Import",
|
||||||
"Import Invidious data": "Import Invidious JSON data",
|
"Import Invidious data": "Import Invidious JSON data",
|
||||||
"Import YouTube subscriptions": "Import YouTube/OPML subscriptions",
|
"Import YouTube subscriptions": "Import YouTube/OPML subscriptions",
|
||||||
"Import YouTube playlist": "Import YouTube playlist (.csv)",
|
"Import YouTube playlist (.csv)": "Import YouTube playlist (.csv)",
|
||||||
"Import FreeTube subscriptions (.db)": "Import FreeTube subscriptions (.db)",
|
"Import FreeTube subscriptions (.db)": "Import FreeTube subscriptions (.db)",
|
||||||
"Import NewPipe subscriptions (.json)": "Import NewPipe subscriptions (.json)",
|
"Import NewPipe subscriptions (.json)": "Import NewPipe subscriptions (.json)",
|
||||||
"Import NewPipe data (.zip)": "Import NewPipe data (.zip)",
|
"Import NewPipe data (.zip)": "Import NewPipe data (.zip)",
|
||||||
|
|
|
@ -310,6 +310,16 @@ module Invidious::Routes::PreferencesRoute
|
||||||
response: error_template(415, "Invalid subscription file uploaded")
|
response: error_template(415, "Invalid subscription file uploaded")
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
# Gavin Johnson (thtmnisamnstr), 20230127: Call the Youtube playlist import function
|
||||||
|
when "import_youtube_pl"
|
||||||
|
filename = part.filename || ""
|
||||||
|
success = Invidious::User::Import.from_youtube_pl(user, body, filename, type)
|
||||||
|
|
||||||
|
if !success
|
||||||
|
haltf(env, status_code: 415,
|
||||||
|
response: error_template(415, "Invalid playlist file uploaded")
|
||||||
|
)
|
||||||
|
end
|
||||||
when "import_freetube"
|
when "import_freetube"
|
||||||
Invidious::User::Import.from_freetube(user, body)
|
Invidious::User::Import.from_freetube(user, body)
|
||||||
when "import_newpipe_subscriptions"
|
when "import_newpipe_subscriptions"
|
||||||
|
|
|
@ -30,75 +30,72 @@ struct Invidious::User
|
||||||
return subscriptions
|
return subscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
# Parse a youtube CSV playlist file and create the playlist
|
# Gavin Johnson (thtmnisamnstr), 20230127: Parse a youtube CSV playlist file and create the playlist
|
||||||
#NEW - Done
|
|
||||||
def parse_playlist_export_csv(user : User, csv_content : String)
|
def parse_playlist_export_csv(user : User, csv_content : String)
|
||||||
rows = CSV.new(csv_content, headers: false)
|
rows = CSV.new(csv_content, headers: true)
|
||||||
if rows.size >= 2
|
row_counter = 0
|
||||||
title = rows[1][4]?.try &.as_s?.try
|
playlist = uninitialized InvidiousPlaylist
|
||||||
descripton = rows[1][5]?.try &.as_s?.try
|
title = uninitialized String
|
||||||
visibility = rows[1][6]?.try &.as_s?.try
|
description = uninitialized String
|
||||||
|
visibility = uninitialized String
|
||||||
|
rows.each do |row|
|
||||||
|
if row_counter == 0
|
||||||
|
title = row[4]
|
||||||
|
description = row[5]
|
||||||
|
visibility = row[6]
|
||||||
|
|
||||||
if visibility.compare("Public", case_insensitive: true) == 0
|
if visibility.compare("Public", case_insensitive: true) == 0
|
||||||
privacy = PlaylistPrivacy:Public
|
privacy = PlaylistPrivacy::Public
|
||||||
else
|
else
|
||||||
privacy = PlaylistPrivacy:Private
|
privacy = PlaylistPrivacy::Private
|
||||||
|
end
|
||||||
|
|
||||||
|
if title && privacy && user
|
||||||
|
playlist = create_playlist(title, privacy, user)
|
||||||
|
end
|
||||||
|
|
||||||
|
if playlist && description
|
||||||
|
Invidious::Database::Playlists.update_description(playlist.id, description)
|
||||||
|
end
|
||||||
|
|
||||||
|
row_counter += 1
|
||||||
end
|
end
|
||||||
|
if row_counter > 0 && row_counter < 3
|
||||||
if title && privacy && user
|
row_counter += 1
|
||||||
playlist = create_playlist(title, privacy, user)
|
|
||||||
end
|
end
|
||||||
|
if row_counter >= 3
|
||||||
|
if playlist
|
||||||
|
video_id = row[0]
|
||||||
|
row_counter += 1
|
||||||
|
next if !video_id
|
||||||
|
|
||||||
if playlist && descripton
|
begin
|
||||||
Invidious::Database::Playlists.update_description(playlist.id, description)
|
video = get_video(video_id)
|
||||||
|
rescue ex
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
playlist_video = PlaylistVideo.new({
|
||||||
|
title: video.title,
|
||||||
|
id: video.id,
|
||||||
|
author: video.author,
|
||||||
|
ucid: video.ucid,
|
||||||
|
length_seconds: video.length_seconds,
|
||||||
|
published: video.published,
|
||||||
|
plid: playlist.id,
|
||||||
|
live_now: video.live_now,
|
||||||
|
index: Random::Secure.rand(0_i64..Int64::MAX),
|
||||||
|
})
|
||||||
|
|
||||||
|
Invidious::Database::PlaylistVideos.insert(playlist_video)
|
||||||
|
Invidious::Database::Playlists.update_video_added(playlist.id, playlist_video.index)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return playlist
|
return playlist
|
||||||
end
|
end
|
||||||
|
|
||||||
# Parse a youtube CSV playlist file and add videos from it to a playlist
|
|
||||||
#NEW - done
|
|
||||||
def parse_playlist_videos_export_csv(playlist : Playlist, csv_content : String)
|
|
||||||
rows = CSV.new(csv_content, headers: false)
|
|
||||||
if rows.size >= 5
|
|
||||||
offset = env.params.query["index"]?.try &.to_i? || 0
|
|
||||||
row_counter = 0
|
|
||||||
rows.each do |row|
|
|
||||||
if row_counter >= 4
|
|
||||||
video_id = row[0]?.try &.as_s?.try
|
|
||||||
end
|
|
||||||
row_counter += 1
|
|
||||||
next if !video_id
|
|
||||||
|
|
||||||
begin
|
|
||||||
video = get_video(video_id)
|
|
||||||
rescue ex
|
|
||||||
next
|
|
||||||
end
|
|
||||||
|
|
||||||
playlist_video = PlaylistVideo.new({
|
|
||||||
title: video.title,
|
|
||||||
id: video.id,
|
|
||||||
author: video.author,
|
|
||||||
ucid: video.ucid,
|
|
||||||
length_seconds: video.length_seconds,
|
|
||||||
published: video.published,
|
|
||||||
plid: playlist.id,
|
|
||||||
live_now: video.live_now,
|
|
||||||
index: Random::Secure.rand(0_i64..Int64::MAX),
|
|
||||||
})
|
|
||||||
|
|
||||||
Invidious::Database::PlaylistVideos.insert(playlist_video)
|
|
||||||
Invidious::Database::Playlists.update_video_added(playlist.id, playlist_video.index)
|
|
||||||
end
|
|
||||||
|
|
||||||
videos = get_playlist_videos(playlist, offset: offset)
|
|
||||||
end
|
|
||||||
|
|
||||||
return videos
|
|
||||||
end
|
|
||||||
|
|
||||||
# -------------------
|
# -------------------
|
||||||
# Invidious
|
# Invidious
|
||||||
# -------------------
|
# -------------------
|
||||||
|
@ -218,20 +215,20 @@ struct Invidious::User
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
# Import playlist from Youtube
|
# Gavin Johnson (thtmnisamnstr), 20230127: Import playlist from Youtube export. Returns success status.
|
||||||
# Returns success status
|
|
||||||
#NEW
|
|
||||||
def from_youtube_pl(user : User, body : String, filename : String, type : String) : Bool
|
def from_youtube_pl(user : User, body : String, filename : String, type : String) : Bool
|
||||||
extension = filename.split(".").last
|
extension = filename.split(".").last
|
||||||
|
|
||||||
if extension == "csv" || type == "text/csv"
|
if extension == "csv" || type == "text/csv"
|
||||||
playlist = parse_playlist_export_csv(user, body)
|
playlist = parse_playlist_export_csv(user, body)
|
||||||
playlist = parse_playlist_videos_export_csv(playlist, body)
|
if playlist
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
else
|
else
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# -------------------
|
# -------------------
|
||||||
|
|
|
@ -5,14 +5,21 @@
|
||||||
<%= rendered "components/feed_menu" %>
|
<%= rendered "components/feed_menu" %>
|
||||||
|
|
||||||
<div class="pure-g h-box">
|
<div class="pure-g h-box">
|
||||||
<div class="pure-u-2-3">
|
<div class="pure-u-1-3">
|
||||||
<h3><%= translate(locale, "user_created_playlists", %(<span id="count">#{items_created.size}</span>)) %></h3>
|
<h3><%= translate(locale, "user_created_playlists", %(<span id="count">#{items_created.size}</span>)) %></h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="pure-u-1-3" style="text-align:right">
|
<div class="pure-u-1-3">
|
||||||
<h3>
|
<h3 style="text-align:center">
|
||||||
<a href="/create_playlist?referer=<%= URI.encode_www_form(referer) %>"><%= translate(locale, "Create playlist") %></a>
|
<a href="/create_playlist?referer=<%= URI.encode_www_form(referer) %>"><%= translate(locale, "Create playlist") %></a>
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="pure-u-1-3">
|
||||||
|
<h3 style="text-align:right">
|
||||||
|
<a href="/data_control?referer=<%= URI.encode_www_form(referer) %>">
|
||||||
|
<%= translate(locale, "Import/export") %>
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pure-g">
|
<div class="pure-g">
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<legend><%= translate(locale, "Import") %></legend>
|
<legend><%= translate(locale, "Import") %></legend>
|
||||||
|
|
||||||
<div class="pure-control-group">
|
<div class="pure-control-group">
|
||||||
<label for="import_youtube"><%= translate(locale, "Import Invidious data") %></label>
|
<label for="import_invidious"><%= translate(locale, "Import Invidious data") %></label>
|
||||||
<input type="file" id="import_invidious" name="import_invidious">
|
<input type="file" id="import_invidious" name="import_invidious">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pure-control-group">
|
<div class="pure-control-group">
|
||||||
<label for="import_youtube_pl"><%= translate(locale, "Import YouTube playlists") %></label>
|
<label for="import_youtube_pl"><%= translate(locale, "Import YouTube playlist (.csv)") %></label>
|
||||||
<input type="file" id="import_youtube_pl" name="import_youtube_pl">
|
<input type="file" id="import_youtube_pl" name="import_youtube_pl">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue