forked from midou/invidious
		
	User: Allow CSV Youtube playlists to be imported (#3595)
This commit is contained in:
		| @@ -33,6 +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 (.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,15 @@ module Invidious::Routes::PreferencesRoute | |||||||
|               response: error_template(415, "Invalid subscription file uploaded") |               response: error_template(415, "Invalid subscription file uploaded") | ||||||
|             ) |             ) | ||||||
|           end |           end | ||||||
|  |         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,6 +30,60 @@ struct Invidious::User | |||||||
|       return subscriptions |       return subscriptions | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  |     def parse_playlist_export_csv(user : User, raw_input : String) | ||||||
|  |       # Split the input into head and body content | ||||||
|  |       raw_head, raw_body = raw_input.split("\n\n", limit: 2, remove_empty: true) | ||||||
|  |  | ||||||
|  |       # Create the playlist from the head content | ||||||
|  |       csv_head = CSV.new(raw_head, headers: true) | ||||||
|  |       csv_head.next | ||||||
|  |       title = csv_head[4] | ||||||
|  |       description = csv_head[5] | ||||||
|  |       visibility = csv_head[6] | ||||||
|  |  | ||||||
|  |       if visibility.compare("Public", case_insensitive: true) == 0 | ||||||
|  |         privacy = PlaylistPrivacy::Public | ||||||
|  |       else | ||||||
|  |         privacy = PlaylistPrivacy::Private | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       playlist = create_playlist(title, privacy, user) | ||||||
|  |       Invidious::Database::Playlists.update_description(playlist.id, description) | ||||||
|  |  | ||||||
|  |       # Add each video to the playlist from the body content | ||||||
|  |       csv_body = CSV.new(raw_body, headers: true) | ||||||
|  |       csv_body.each do |row| | ||||||
|  |         video_id = row[0] | ||||||
|  |         if playlist | ||||||
|  |           next if !video_id | ||||||
|  |           next if video_id == "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 | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       return playlist | ||||||
|  |     end | ||||||
|  |  | ||||||
|     # ------------------- |     # ------------------- | ||||||
|     #  Invidious |     #  Invidious | ||||||
|     # ------------------- |     # ------------------- | ||||||
| @@ -149,6 +203,21 @@ struct Invidious::User | |||||||
|       return true |       return true | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  |     def from_youtube_pl(user : User, body : String, filename : String, type : String) : Bool | ||||||
|  |       extension = filename.split(".").last | ||||||
|  |  | ||||||
|  |       if extension == "csv" || type == "text/csv" | ||||||
|  |         playlist = parse_playlist_export_csv(user, body) | ||||||
|  |         if playlist | ||||||
|  |           return true | ||||||
|  |         else | ||||||
|  |           return false | ||||||
|  |         end | ||||||
|  |       else | ||||||
|  |         return false | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |  | ||||||
|     # ------------------- |     # ------------------- | ||||||
|     #  Freetube |     #  Freetube | ||||||
|     # ------------------- |     # ------------------- | ||||||
|   | |||||||
| @@ -5,12 +5,19 @@ | |||||||
| <%= 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("/feed/playlists") %>"><%= translate(locale, "Create playlist") %></a> | ||||||
|  |         </h3> | ||||||
|  |     </div> | ||||||
|  |     <div class="pure-u-1-3"> | ||||||
|  |         <h3 style="text-align:right"> | ||||||
|  |             <a href="/data_control?referer=<%= URI.encode_www_form("/feed/playlists") %>"> | ||||||
|  |                 <%= translate(locale, "Import/export") %> | ||||||
|  |             </a> | ||||||
|         </h3> |         </h3> | ||||||
|     </div> |     </div> | ||||||
| </div> | </div> | ||||||
|   | |||||||
| @@ -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> | ||||||
|  |  | ||||||
| @@ -21,6 +21,11 @@ | |||||||
|                 <input type="file" id="import_youtube" name="import_youtube"> |                 <input type="file" id="import_youtube" name="import_youtube"> | ||||||
|             </div> |             </div> | ||||||
|  |  | ||||||
|  |             <div class="pure-control-group"> | ||||||
|  |                 <label for="import_youtube_pl"><%= translate(locale, "Import YouTube playlist (.csv)") %></label> | ||||||
|  |                 <input type="file" id="import_youtube_pl" name="import_youtube_pl"> | ||||||
|  |             </div> | ||||||
|  |  | ||||||
|             <div class="pure-control-group"> |             <div class="pure-control-group"> | ||||||
|                 <label for="import_freetube"><%= translate(locale, "Import FreeTube subscriptions (.db)") %></label> |                 <label for="import_freetube"><%= translate(locale, "Import FreeTube subscriptions (.db)") %></label> | ||||||
|                 <input type="file" id="import_freetube" name="import_freetube"> |                 <input type="file" id="import_freetube" name="import_freetube"> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user