@@ -59,6 +59,8 @@ void YouTubeAPI::AddFromJson(IAIMPPlaylist *playlist, const rapidjson::Value &d,
5959 state->PlaylistToUpdate ->Items .insert (trackId);
6060 }
6161
62+ auto permalink = L" https://www.youtube.com/watch?v=" + trackId;
63+
6264 std::wstring filename (L" youtube://" );
6365 filename += trackId + L" /" ;
6466 filename += final_title;
@@ -71,6 +73,7 @@ void YouTubeAPI::AddFromJson(IAIMPPlaylist *playlist, const rapidjson::Value &d,
7173 if (item.HasMember (" channelTitle" ) && (state->Flags & LoadingState::AddChannelTitle)) {
7274 file_info->SetValueAsObject (AIMP_FILEINFO_PROPID_ARTIST, AIMPString (item[" channelTitle" ]));
7375 }
76+ file_info->SetValueAsObject (AIMP_FILEINFO_PROPID_URL, AIMPString (permalink));
7477
7578 int64_t videoDuration = 0 ;
7679 if (contentDetails.IsObject () && contentDetails.HasMember (" duration" )) {
@@ -96,7 +99,6 @@ void YouTubeAPI::AddFromJson(IAIMPPlaylist *playlist, const rapidjson::Value &d,
9699 artwork = Tools::ToWString (item[" thumbnails" ][" high" ][" url" ]);
97100 }
98101
99- auto permalink = L" https://www.youtube.com/watch?v=" + trackId;
100102
101103 Config::TrackInfos[trackId] = Config::TrackInfo (final_title, trackId, permalink, artwork, videoDuration);
102104
@@ -159,7 +161,14 @@ void YouTubeAPI::LoadFromUrl(std::wstring url, IAIMPPlaylist *playlist, std::sha
159161 std::wstring userName = Tools::ToWString (d[" items" ][0 ][" snippet" ][" localized" ][" title" ]);
160162 IAIMPPropertyList *plProp = nullptr ;
161163 if (SUCCEEDED (playlist->QueryInterface (IID_IAIMPPropertyList, reinterpret_cast <void **>(&plProp)))) {
162- plProp->SetValueAsObject (AIMP_PLAYLIST_PROPID_NAME, AIMPString (userName));
164+ bool isRenamed = true ;
165+ IAIMPString *str = nullptr ;
166+ if (SUCCEEDED (plProp->GetValueAsObject (AIMP_PLAYLIST_PROPID_NAME, IID_IAIMPString, reinterpret_cast <void **>(&str)))) {
167+ isRenamed = wcscmp (L" YouTube" , str->GetData ());
168+ str->Release ();
169+ }
170+ if (!isRenamed)
171+ plProp->SetValueAsObject (AIMP_PLAYLIST_PROPID_NAME, AIMPString (userName));
163172 plProp->Release ();
164173 }
165174 state->ReferenceName = userName;
@@ -490,10 +499,15 @@ std::wstring YouTubeAPI::GetStreamUrl(const std::wstring &id) {
490499}
491500
492501void YouTubeAPI::LoadSignatureDecoder () {
493- // TODO: http://en.cppreference.com/w/cpp/regex/regex_match
502+ static std::map<std::string, std::function<void (std::string &s, int param)>> mutatorTypes {
503+ { " swap" , [](std::string &s, int param) { std::swap (s[0 ], s[param]); } },
504+ { " erase" , [](std::string &s, int param) { s.erase (0 , param); } },
505+ { " reverse" , [](std::string &s, int param) { std::reverse (s.begin (), s.end ()); } },
506+ };
494507
495- std::wstring ua (L" Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3304.0 Safari/537.36" );
496- AimpHTTP::Get (L" https://www.youtube.com/\r\n User-Agent: " + ua, [](unsigned char *data, int size) {
508+ // TODO: http://en.cppreference.com/w/cpp/regex/regex_match
509+ std::wstring ua (L" Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3353.0 Safari/537.36" );
510+ AimpHTTP::Get (L" https://www.youtube.com/\r\n User-Agent: " + ua, [&](unsigned char *data, int size) {
497511 if (char *playerurl = strstr ((char *)data, " \" js\" :\" " )) {
498512 playerurl += 6 ;
499513 if (char *end = strchr (playerurl, ' "' ))
@@ -503,21 +517,21 @@ void YouTubeAPI::LoadSignatureDecoder() {
503517 if (player.find (" http" ) == std::string::npos)
504518 player = " https://www.youtube.com" + player;
505519
506- player += " \r\n Accept-Encoding: gzip;q=0,deflate;q=0,identity" ;
520+ player += " \r\n Accept-Encoding: gzip;q=0,deflate;q=0,identity" ;
507521
508- AimpHTTP::Get (Tools::ToWString (player), [](unsigned char *rawData, int size) {
522+ AimpHTTP::Get (Tools::ToWString (player), [& ](unsigned char *rawData, int size) {
509523 std::string data (reinterpret_cast <char *>(rawData), size);
510524 Tools::ReplaceString (" \n " , " " , data);
511525 Tools::ReplaceString (" \r " , " " , data);
512526
513527 std::size_t funcname;
514- if ((funcname = data.find (" .set( \" signature\" ," )) != std::string::npos) {
515- funcname += 17 ;
528+ if ((funcname = data.find (" \" signature\" ," )) != std::string::npos) {
529+ funcname += 12 ;
516530 std::size_t end;
517531 if ((end = data.find (' (' , funcname)) != std::string::npos) {
518532 std::string fname (data.substr (funcname, end - funcname));
519533 if (fname.find (' )' ) != std::string::npos) {
520- if ((funcname = data.find (" .set( \" signature\" ," , funcname)) != std::string::npos) {
534+ if ((funcname = data.find (" \" signature\" ," , funcname)) != std::string::npos) {
521535 funcname += 17 ;
522536 std::size_t end;
523537 if ((end = data.find (' (' , funcname)) != std::string::npos) {
@@ -547,19 +561,14 @@ void YouTubeAPI::LoadSignatureDecoder() {
547561 end = data.find (" join(\"\" )" , funcdef);
548562 funcdef += sigLen;
549563
550- std::map<std::string, std::function< void (std:: string &s, int param)> > mutators;
564+ std::map<std::string, std::string> mutators;
551565 std::string mutStr = data.substr (mutatorObjectStart, mutatorObjectEnd - mutatorObjectStart);
552566 Tools::SplitString (mutStr, " }," , [&](std::string token) {
553567 token = Tools::Trim (token);
554568 std::string name (token.substr (0 , 2 ));
555- if (token.find (" var " ) != std::string::npos)
556- mutators[name] = [](std::string &s, int param) { std::swap (s[0 ], s[param]); };
557-
558- if (token.find (" splice" ) != std::string::npos)
559- mutators[name] = [](std::string &s, int param) { s.erase (0 , param); };
560-
561- if (token.find (" reverse" ) != std::string::npos)
562- mutators[name] = [](std::string &s, int param) { std::reverse (s.begin (), s.end ()); };
569+ if (token.find (" var " ) != std::string::npos) mutators[name] = " swap" ;
570+ if (token.find (" splice" ) != std::string::npos) mutators[name] = " erase" ;
571+ if (token.find (" reverse" ) != std::string::npos) mutators[name] = " reverse" ;
563572 });
564573
565574 std::string sstr (data.substr (funcdef, end - funcdef));
@@ -573,7 +582,10 @@ void YouTubeAPI::LoadSignatureDecoder() {
573582 if (char *end = strchr (params, ' )' )) *end = 0 ;
574583 int param = std::stoi (params + 1 );
575584 if (mutators.find (mutator) != mutators.end ()) {
576- YouTubeAPI::SigDecoder.push_back ({ mutators[mutator], param });
585+ DebugA (" \t ['%s', %d],\n " , mutators[mutator].c_str (), param);
586+ if (mutatorTypes.find (mutators[mutator]) != mutatorTypes.end ()) {
587+ YouTubeAPI::SigDecoder.push_back ({ mutatorTypes[mutators[mutator]], param });
588+ }
577589 } else {
578590 DebugA (" Unknown mutator: %s\n " , mutator.c_str ());
579591 }
@@ -586,6 +598,23 @@ void YouTubeAPI::LoadSignatureDecoder() {
586598 }, true );
587599 }
588600 }, true );
601+
602+ if (YouTubeAPI::SigDecoder.empty ()) {
603+ AimpHTTP::Get (L" http://eddy.cx/dev/ytsig.php" , [&](unsigned char *data, int size) {
604+ rapidjson::Document d;
605+ d.Parse (reinterpret_cast <const char *>(data));
606+
607+ if (d.IsArray () && d.Size () > 0 ) {
608+ for (auto i = d.Begin (), e = d.End (); i != e; i++) {
609+ const auto &x = *i;
610+ if (!x.IsArray () || x.Size () != 2 )
611+ continue ;
612+
613+ YouTubeAPI::SigDecoder.push_back ({ mutatorTypes[x[0 ].GetString ()], x[1 ].GetInt () });
614+ }
615+ }
616+ }, true );
617+ }
589618}
590619
591620void YouTubeAPI::AddToPlaylist (Config::Playlist &pl, const std::wstring &trackId) {
0 commit comments