├── 1.ico ├── README.md ├── config.h ├── daye.cpp ├── daye.h ├── db4musicdownloader.cpp ├── db4musicdownloader.h ├── downloader.cpp ├── downloader.h ├── downloadqueue.cpp ├── downloadqueue.h ├── help.cpp ├── help.h ├── help.ui ├── id3tag.cpp ├── id3tag.h ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── musicDownloader.pro ├── musicDownloader.pro.user ├── neteaseplaylist.cpp ├── neteaseplaylist.h ├── neteasesong.cpp ├── neteasesong.h ├── pic.qrc ├── proxyform.cpp ├── proxyform.h ├── proxyform.ui ├── qqmusic.cpp ├── qqmusic.h ├── qqmusicalbum.cpp ├── qqmusicalbum.h ├── qqmusicplaylist.cpp ├── qqmusicplaylist.h ├── qqmusicsearch.cpp ├── qqmusicsearch.h ├── qqmusicsong.cpp ├── qqmusicsong.h ├── singerallalbum.cpp ├── singerallalbum.h ├── singerallalbum.ui ├── thanks.cpp ├── thanks.h ├── thanks.ui ├── vkeyinit2.cpp └── vkeyinit2.h /1.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z52c/MusicDownloader/0f75ff42d21d4748337a5158e4b1f6cb66457a58/1.ico -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 貌似付费凉凉了,等等吧 2 | 3 | 若要删除所有下载队列,只需关闭程序,删除daye.db即可 4 | 5 | 1.8.0版本添加功能下载歌手所有专辑歌曲,自动添加到下载队列中 6 | 7 | 1.7.0版本开始使用下载队列,保存在数据库中,不需要像之前一样下载完一个任务才能添加下一个任务,粘贴好链接,选择好格式音质目录,点下载即可添加到下载队列,想要停止,直接关闭程序即可,重新打开程序会从数据库中读取任务链接开始继续下载 8 | 9 | 在1.6.2开始的版本中增加Mac版本,在realease中下载解压后,双击执行目录下MacOS/musicDownloader 文件 10 | 11 | ## 功能 ## 12 | 1. 下载QQ音乐**单曲** 13 | 2. 下载QQ音乐**专辑**下所有歌曲 14 | 3. 下载QQ音乐**歌单**下所有歌曲 15 | 4. 下载网易云音乐**歌单**下所有歌曲 16 | 5. 只下载网易云音乐歌单中**灰掉**的歌曲 17 | 6. 音质支持高清、无损,付费音乐以及灰掉的也能下载 18 | 7. 由于直接下载的MP3文件标签内容中的编码不一致会有乱码,所以在程序里将MP3标签头用unicode编码重新编辑了,并插入了封面图 19 | 8. 要下载单曲以及专辑,请使用QQ音乐中的链接 20 | 21 | ## 提示 ## 22 | 1. 不支持短链接,QQ音乐软件复制出来的链接是短链接,要复制到浏览器之后再把链接粘贴过来 23 | 2. 代理选项只支持socks5,一般在国外才需要使用代理,代理设置后重启生效,网上找来的代理速度一般及其慢,基本无法工作,最好找国内好点的socks5代理,或者自己假设服务器 24 | 3. Mac版本,在realease中下载解压后,双击执行目录下Contents/MacOS/musicDownloader 文件 25 | 4. 要看怎么实现的,只需看qqmusicsong.cpp 以及 config.h即可 26 | 27 | ## 使用说明 ## 28 | 29 | 参考 [http://z52c.com/musicdownloader/][1] 30 | 31 | ![image](https://o05g5zevc.qnssl.com/e09bcd80-09af-4ce8-b225-ce89f0a388b1/TIM%E5%9B%BE%E7%89%8720180713231527.png?imageMogr2/auto-orient/strip/thumbnail/!1600x1600%3E) 32 | 33 | Mac配图未更新,同上 34 | 35 | ![image](https://o05g5zevc.qnssl.com/2e1c3700-4ccb-49ed-9879-02efce9a752f/TIM%E5%9B%BE%E7%89%8720180709202927.png?imageMogr2/auto-orient/strip/thumbnail/!1600x1600%3E) 36 | 37 | 38 | [1]: http://z52c.com/musicdownloader/ 39 | 40 | 41 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | #include 4 | #include 5 | 6 | struct neteaseInfo{ 7 | QString singerName; 8 | QString songName; 9 | QString album; 10 | }; 11 | 12 | struct downloadQueueInfo{ 13 | int flag; 14 | int quality; 15 | int nameType; 16 | QString dir; 17 | QString url; 18 | }; 19 | 20 | #define UA " Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5221.400 QQBrowser/10.0.1125.400" 21 | #define REFERERURL "y.qq.com" 22 | 23 | 24 | #define DOWNLOADLINKHEAD "http://dl.stream.qqmusic.qq.com/" 25 | #define DOWNLOADLINKMID "?fromtag=64&vkey=" 26 | #define DOWNLOADLINKGUID "&guid=" 27 | #define DOWNLOADLINKTAIL "&fromtag=1" 28 | 29 | #define NDOWNLOADLINKHEAD "http://streamoc.music.tc.qq.com/" 30 | #define NDOWNLOADLINKMID "?vkey=" 31 | #define NDOWNLOADLINKTAIL "&guid=1234567890&uin=1008611&fromtag=8" 32 | 33 | //歌曲html页面链接 HEAD+SONGMID+TAIL 34 | #define SONGLINKHEAD "https://y.qq.com/n/yqq/song/" 35 | #define SONGLINKTAIL ".html" 36 | 37 | //获取vkey 38 | #define USERAGENT "Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19" 39 | #define GETVKEYLINKHEAD "https://i.y.qq.com/v8/playsong.html?ADTAG=newyqq.song&songmid=" 40 | #define GETVKEYLINKTAIL "#webchat_redirect" 41 | 42 | //单曲信息 43 | #define SINGLESONGHEAD "https://c.y.qq.com/v8/fcg-bin/fcg_play_single_song.fcg?songmid=" 44 | #define SINGLESONGTAIL "&tpl=yqq_song_detail&format=json&callback=getOneSongInfoCallback&g_tk=5381&jsonCallback=getOneSongInfoCallback&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0" 45 | 46 | //专辑封面链接 47 | #define ALBUMPICLINKHEAD "https://y.gtimg.cn/music/photo_new/T002R800x800M000" 48 | #define ALBUMPICLINKTAIL ".jpg?max_age=2592000" 49 | 50 | //歌单下载链接 51 | #define PLAYLISTLINKHEAD "https://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg?type=1&json=1&utf8=1&onlysong=0&disstid=" 52 | #define PALYLISTLINKTAIL "&format=jsonp&g_tk=5381&jsonpCallback=playlistinfoCallback&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0" 53 | 54 | //歌手html页面链接 55 | #define SINGERLINKHEAD "https://y.qq.com/n/yqq/singer/" 56 | #define SINGERLINKTAIL ".html" 57 | 58 | #define SINGERALBUMHEAD "https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_album.fcg?g_tk=5381&jsonCallback=MusicJsonCallbacksinger_album&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0&singermid=" 59 | #define SINGERALBUMMID1 "&order=time&begin=" 60 | #define SINGERALBUMMID2 "&num=" 61 | #define SINGERALBUMTAIL "&exstatus=1" 62 | 63 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 64 | * 拼接歌手单曲列表下载链接:HEAD+SINGERMID+MID+BEGINNUM+TAIL* 65 | * 每页30个,下载后拼接文件,begin确定从哪一个开始 * 66 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 67 | #define SINGERSONGLISTLINKHEAD "https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg?g_tk=5381&jsonpCallback=MusicJsonCallbacksinger_track&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0&singermid=" 68 | #define SINGERSONGLISTLINKMID "&order=listen&begin=" 69 | #define SINGERSONGLISTLINKTAIL "&num=30&songstatus=1" 70 | 71 | //下载专辑歌单列表 72 | #define ALBUMLINKHEAD "https://c.y.qq.com/v8/fcg-bin/fcg_v8_album_info_cp.fcg?albummid=" 73 | #define ALBUMLINKTAIL "&g_tk=5381&jsonpCallback=albuminfoCallback&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0" 74 | 75 | //临时文件 76 | #define SONGHTMLFILE "songhtml.tmp" 77 | #define SINGERHTMLFILE "singerhtml.tmp" 78 | #define ALBUMLISTFILE "albumlist.tmp" 79 | #define PLAYLISTFILE "playlist.tmp" 80 | #define SONGMIDFROMFILE "songmidfromfile.tmp" 81 | #define SEARCHRESULTFILE "search.tmp" 82 | #define SONGINFOFILE "songInfo.json" 83 | 84 | 85 | 86 | #endif // CONFIG_H 87 | -------------------------------------------------------------------------------- /daye.cpp: -------------------------------------------------------------------------------- 1 | #include "daye.h" 2 | 3 | int getStringBetweenAandB(const char* a,const char* A,const char* B,char *find) 4 | { 5 | 6 | //空字符串返回-1 7 | if(!a || !A || !B) 8 | return -1; 9 | 10 | char source[strlen(a)+1]; 11 | strcpy(source,a); 12 | 13 | char * startIndex=NULL; 14 | if(!(startIndex=strstr(source,A))) 15 | return -2; 16 | 17 | startIndex=startIndex+strlen(A); 18 | char *endIndex=NULL; 19 | if(!(endIndex=strstr(startIndex,B))) 20 | return -3; 21 | 22 | strncpy(find,startIndex,endIndex-startIndex); 23 | find[endIndex-startIndex]='\0'; 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /daye.h: -------------------------------------------------------------------------------- 1 | #ifndef DAYE_H 2 | #define DAYE_H 3 | 4 | #include 5 | #include 6 | int getStringBetweenAandB(const char* a,const char* A,const char* B,char *find); 7 | 8 | #endif // DAYE_H 9 | -------------------------------------------------------------------------------- /db4musicdownloader.cpp: -------------------------------------------------------------------------------- 1 | #include "db4musicdownloader.h" 2 | 3 | db4MusicDownloader::db4MusicDownloader(QObject *parent) : QObject(parent) 4 | { 5 | db=new QSqlDatabase(); 6 | if (QSqlDatabase::contains("qt_sql_default_connection")) 7 | { 8 | *db = QSqlDatabase::database("qt_sql_default_connection"); 9 | } 10 | else 11 | { 12 | *db = QSqlDatabase::addDatabase("QSQLITE"); 13 | db->setDatabaseName("daye.db"); 14 | } 15 | if (!db->open()) 16 | { 17 | qDebug() << "Error: Failed to connect database." << db->lastError(); 18 | } 19 | else 20 | { 21 | _createTable(); 22 | } 23 | } 24 | 25 | bool db4MusicDownloader::_createTable() 26 | { 27 | QSqlQuery sql_query; 28 | QString create_sql = "create table downloadQueue (id INTEGER PRIMARY KEY AUTOINCREMENT, flag INTEGER, quality INTEGER,nameType INTEGER,dir varchar(255),url varchar(255))"; 29 | sql_query.prepare(create_sql); 30 | if(!sql_query.exec()) 31 | { 32 | qDebug() << "Error: Fail to create table." << sql_query.lastError(); 33 | return false; 34 | } 35 | else 36 | { 37 | qDebug() << "Table downloadQueue created!"; 38 | return true; 39 | } 40 | } 41 | 42 | bool db4MusicDownloader::deleteFromDownloadQueue(QString inUrl) 43 | { 44 | QSqlQuery sql_query; 45 | QString create_sql =QString( "DELETE FROM downloadQueue where url=\'%1\'").arg(inUrl); 46 | sql_query.prepare(create_sql); 47 | if(!sql_query.exec()) 48 | { 49 | qDebug() << "Error while delete:" << sql_query.lastError(); 50 | return false; 51 | } 52 | else 53 | { 54 | qDebug() << "delete sucess!"; 55 | return true; 56 | } 57 | } 58 | 59 | bool db4MusicDownloader::insertDownloadQueue(int inFlag, int inQuality, int inNameType,QString inDir, QString inUrl) 60 | { 61 | QSqlQuery sql_query; 62 | QString insert_sql=QString("INSERT INTO downloadQueue VALUES(NULL,%1,%2,%3,\'%4\',\'%5\')").arg(inFlag).arg(inQuality).arg(inNameType).arg(inDir).arg(inUrl); 63 | if(!sql_query.exec(insert_sql)) 64 | { 65 | qDebug()< db4MusicDownloader::getQueue() 75 | { 76 | struct downloadQueueInfo tmp; 77 | QList rtn; 78 | QSqlQuery sql_query; 79 | QString select_sql ="select * from downloadQueue"; 80 | if(!sql_query.exec(select_sql)) 81 | { 82 | qDebug()< 5 | #include 6 | #include 7 | #include 8 | #include "daye.h" 9 | #include "config.h" 10 | #include 11 | 12 | class db4MusicDownloader : public QObject 13 | { 14 | Q_OBJECT 15 | public: 16 | explicit db4MusicDownloader(QObject *parent = nullptr); 17 | bool insertDownloadQueue(int inFlag,int inQuality,int inNameType,QString inDir,QString inUrl); 18 | bool deleteFromDownloadQueue(QString inUrl); 19 | bool _createTable(); 20 | QList getQueue(); 21 | signals: 22 | 23 | private: 24 | QSqlDatabase *db; 25 | 26 | }; 27 | 28 | #endif // DB4MUSICDOWNLOADER_H 29 | -------------------------------------------------------------------------------- /downloader.cpp: -------------------------------------------------------------------------------- 1 | #include "downloader.h" 2 | #include 3 | 4 | downloader::downloader() 5 | { 6 | manager.setCookieJar(new QNetworkCookieJar(this)); 7 | connect(&manager,SIGNAL(finished(QNetworkReply*)),SLOT(downloadFinished(QNetworkReply*))); 8 | } 9 | 10 | void downloader::init(const QString inUrl, const QString inFileName) 11 | { 12 | if(inFileName=="") 13 | { 14 | flagSave=0; 15 | url = QUrl::fromEncoded(inUrl.toLocal8Bit()); 16 | } 17 | else 18 | { 19 | flagSave=1; 20 | url = QUrl::fromEncoded(inUrl.toLocal8Bit()); 21 | fileName = inFileName; 22 | } 23 | } 24 | /* 25 | void downloader::init(char *inU, char *inF=NULL) 26 | { 27 | if(inF==NULL) 28 | { 29 | init(QString(inU)); 30 | } 31 | } 32 | */ 33 | void downloader::setUserAgent(const QString ua) 34 | { 35 | request.setRawHeader(QByteArray("User-Agent"),QByteArray(ua.toLocal8Bit())); 36 | } 37 | 38 | void downloader::setReferer(const QString referer) 39 | { 40 | request.setRawHeader(QByteArray("Referer"),QByteArray(referer.toLocal8Bit())); 41 | } 42 | 43 | void downloader::setCookie(const QString cookie) 44 | { 45 | request.setRawHeader(QByteArray("Cookie"),QByteArray(cookie.toLocal8Bit())); 46 | } 47 | 48 | void downloader::setOrigin(const QString origin) 49 | { 50 | request.setRawHeader(QByteArray("Origin"),QByteArray(origin.toLocal8Bit())); 51 | } 52 | 53 | void downloader::setAccept(const QString accept) 54 | { 55 | request.setRawHeader(QByteArray("Accept"),QByteArray(accept.toLocal8Bit())); 56 | } 57 | 58 | void downloader::setPostData(QString key, QString value) 59 | { 60 | postData.addQueryItem(key,value); 61 | } 62 | 63 | void downloader::clearPostData() 64 | { 65 | postData.clear(); 66 | } 67 | 68 | void downloader::doGet() 69 | { 70 | request.setUrl(url); 71 | reply = manager.get(request); 72 | connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(downloadProgress(qint64,qint64))); 73 | #if QT_CONFIG(ssl) 74 | connect(reply, SIGNAL(sslErrors(QList)), 75 | SLOT(sslErrors(QList))); 76 | #endif 77 | } 78 | 79 | void downloader::doPost() 80 | { 81 | request.setUrl(url); 82 | qDebug()<)), 87 | SLOT(sslErrors(QList))); 88 | #endif 89 | } 90 | 91 | bool downloader::saveToDisk(QIODevice *data) 92 | { 93 | QFile file(fileName); 94 | if(!file.open(QIODevice::WriteOnly)) 95 | { 96 | qDebug()<<"could not open file to write"; 97 | return false; 98 | } 99 | file.write(data->readAll()); 100 | file.close(); 101 | qDebug()<<"66666"<attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); 109 | return statusCode==320 || statusCode==302 || statusCode==303 || statusCode==305 || statusCode==307 || statusCode==308 || statusCode==301; 110 | } 111 | 112 | void downloader::sslErrors(const QList &errors) 113 | { 114 | #if QT_CONFIG(ssl) 115 | //for (const QSslError &error : sslErrors) 116 | // qDebug()<<"ssl error:"<url(); 125 | if(reply->error()) 126 | { 127 | QString errorStringTmp=QString("download ")+tmpUrl.toEncoded().constData()+QString("failed : ")+reply->errorString(); 128 | qDebug()<attribute(QNetworkRequest::RedirectionTargetAttribute); 134 | reply->deleteLater(); 135 | emit redirected(reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toString()); 136 | } else { 137 | if(flagSave==0) 138 | { 139 | dataStr=reply->readAll(); 140 | reply->deleteLater(); 141 | emit finished(); 142 | } 143 | else{ 144 | saveToDisk(reply); 145 | reply->deleteLater(); 146 | emit finished(); 147 | } 148 | } 149 | } 150 | } 151 | 152 | void downloader::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) 153 | { 154 | emit progress(bytesReceived,bytesTotal); 155 | } 156 | 157 | 158 | QList downloader::getCookies() 159 | { 160 | return manager.cookieJar()->cookiesForUrl(url); 161 | } 162 | 163 | 164 | QString downloader::readData() 165 | { 166 | return dataStr; 167 | } 168 | -------------------------------------------------------------------------------- /downloader.h: -------------------------------------------------------------------------------- 1 | #ifndef DOWNLOADER_H 2 | #define DOWNLOADER_H 3 | 4 | #include 5 | #include 6 | 7 | class QSslError; 8 | 9 | class downloader: public QObject 10 | { 11 | Q_OBJECT 12 | protected: 13 | QNetworkAccessManager manager; 14 | QUrl url; 15 | QString fileName; 16 | QNetworkRequest request; 17 | QNetworkReply *reply; 18 | QUrlQuery postData; 19 | 20 | int flagSave; 21 | QString dataStr; 22 | 23 | public: 24 | downloader(); 25 | void init(const QString inUrl,const QString inFileName=""); 26 | void doGet(); 27 | void doPost(); 28 | bool saveToDisk(QIODevice *data); 29 | static bool isHttpRedirect(QNetworkReply *reply); 30 | void setUserAgent(const QString ua); 31 | void setReferer(const QString referer); 32 | void setCookie(const QString cookie); 33 | void setOrigin(const QString origin); 34 | void setAccept(const QString accept); 35 | QList getCookies(); 36 | 37 | void setPostData(QString key,QString value); 38 | void clearPostData(); 39 | 40 | QString readData(); 41 | public slots: 42 | void downloadFinished(QNetworkReply *reply); 43 | void sslErrors(const QList &errors); 44 | void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); 45 | signals: 46 | void progress(qint64, qint64); 47 | void finished(); 48 | void downloadError(QString); 49 | void redirected(QString); 50 | }; 51 | 52 | #endif // DOWNLOADER_H 53 | -------------------------------------------------------------------------------- /downloadqueue.cpp: -------------------------------------------------------------------------------- 1 | #include "downloadqueue.h" 2 | 3 | downloadQueue::downloadQueue(QObject *parent) : QObject(parent) 4 | { 5 | downloading=false; 6 | db=new db4MusicDownloader(); 7 | queueList=db->getQueue(); 8 | q=new qqmusic(); 9 | connect(q,SIGNAL(finished()),this,SLOT(oneTaskFinished())); 10 | connect(q,SIGNAL(progress(qint64,qint64)),this,SIGNAL(downloadProgress(qint64,qint64))); 11 | connect(q,SIGNAL(status(QString)),this,SIGNAL(status(QString))); 12 | np=new neteasePlaylist(); 13 | connect(np,SIGNAL(finished(int,QStringList)),q,SLOT(beginToDownload(int,QStringList))); 14 | connect(np,SIGNAL(status(QString)),this,SIGNAL(status(QString))); 15 | 16 | doJob(); 17 | 18 | } 19 | 20 | void downloadQueue::doJob() 21 | { 22 | if(!queueList.count()) 23 | return; 24 | downloading=true; 25 | struct downloadQueueInfo tmp=queueList.at(0); 26 | 27 | switch(tmp.flag) 28 | { 29 | case 0: //QQ音乐下载 30 | songNameType=tmp.nameType;songQuality=tmp.quality;mp3Dir=tmp.dir;q->doJob(tmp.url);break; 31 | case 1://网易云歌单下载(全部) 32 | songNameType=tmp.nameType;songQuality=tmp.quality;mp3Dir=tmp.dir;np->doJob(false,tmp.url);break; 33 | case 2://网易云歌单下载(灰掉的) 34 | songNameType=tmp.nameType;songQuality=tmp.quality;mp3Dir=tmp.dir;np->doJob(true,tmp.url); 35 | } 36 | } 37 | 38 | void downloadQueue::oneTaskFinished() 39 | { 40 | 41 | downloading=false; 42 | db->deleteFromDownloadQueue(queueList.at(0).url); 43 | queueList.removeAt(0); 44 | emit finished(mp3Dir); 45 | doJob(); 46 | 47 | } 48 | 49 | void downloadQueue::insertQueue(int inFlag, int inQuality, int inNameType, QString inDir, QString inUrl) 50 | { 51 | struct downloadQueueInfo tmp; 52 | tmp.flag=inFlag; 53 | tmp.quality=inQuality; 54 | tmp.nameType=inNameType; 55 | tmp.dir=inDir; 56 | tmp.url=inUrl; 57 | db->insertDownloadQueue(inFlag,inQuality,inNameType,inDir,inUrl); 58 | queueList.append(tmp); 59 | if(!downloading) 60 | doJob(); 61 | } 62 | 63 | QList downloadQueue::getQueue() 64 | { 65 | return queueList; 66 | } 67 | -------------------------------------------------------------------------------- /downloadqueue.h: -------------------------------------------------------------------------------- 1 | #ifndef DOWNLOADQUEUE_H 2 | #define DOWNLOADQUEUE_H 3 | 4 | #include 5 | #include "qqmusic.h" 6 | #include "neteaseplaylist.h" 7 | #include "config.h" 8 | #include "db4musicdownloader.h" 9 | 10 | extern int songNameType; 11 | extern int songQuality; 12 | extern QString mp3FileName; 13 | extern QString mp3Dir; 14 | extern QString vkey; 15 | extern QString guid; 16 | extern QString vkey2; 17 | 18 | class downloadQueue : public QObject 19 | { 20 | Q_OBJECT 21 | public: 22 | explicit downloadQueue(QObject *parent = nullptr); 23 | void insertQueue(int inFlag,int inQuality,int inNameType,QString inDir,QString inUrl); 24 | QList getQueue(); 25 | signals: 26 | void downloadProgress(qint64, qint64); 27 | void status(QString); 28 | void finished(QString); 29 | private slots: 30 | void oneTaskFinished(); 31 | 32 | private: 33 | QList queueList; 34 | qqmusic *q; 35 | neteasePlaylist *np; 36 | db4MusicDownloader *db; 37 | 38 | bool downloading; 39 | 40 | void doJob(); 41 | }; 42 | 43 | #endif // DOWNLOADQUEUE_H 44 | -------------------------------------------------------------------------------- /help.cpp: -------------------------------------------------------------------------------- 1 | #include "help.h" 2 | 3 | 4 | help::help(QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::help) 7 | { 8 | ui->setupUi(this); 9 | this->hide(); 10 | } 11 | 12 | help::~help() 13 | { 14 | delete ui; 15 | } 16 | 17 | void help::on_pushButton_clicked() 18 | { 19 | this->hide(); 20 | } 21 | -------------------------------------------------------------------------------- /help.h: -------------------------------------------------------------------------------- 1 | #ifndef HELP_H 2 | #define HELP_H 3 | 4 | #include 5 | #include "ui_help.h" 6 | 7 | namespace Ui { 8 | class help; 9 | } 10 | 11 | class help : public QWidget 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | explicit help(QWidget *parent = 0); 17 | ~help(); 18 | 19 | private slots: 20 | void on_pushButton_clicked(); 21 | 22 | private: 23 | Ui::help *ui; 24 | }; 25 | 26 | #endif // HELP_H 27 | -------------------------------------------------------------------------------- /help.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | help 4 | 5 | 6 | 7 | 0 8 | 0 9 | 420 10 | 321 11 | 12 | 13 | 14 | 帮助说明 15 | 16 | 17 | 18 | 19 | 0 20 | 0 21 | 421 22 | 321 23 | 24 | 25 | 26 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 27 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> 28 | p, li { white-space: pre-wrap; } 29 | </style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;"> 30 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">详细使用帮助请用浏览器打开链接:</span><span style=" font-family:'-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif'; font-size:13px; color:#666666; background-color:#f1f1f1;"> </span><a name="sample-permalink"></a><a href="http://z52c.com/musicdownloader/"><span style=" font-family:'-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif'; font-size:13px; text-decoration: underline; color:#0073aa; background-color:#f1f1f1;">h</span></a><span style=" font-family:'-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif'; font-size:13px; text-decoration: underline; color:#0073aa; background-color:#f1f1f1;">ttp://z52c.com/</span><a name="editable-post-name"></a><a href="http://z52c.com/musicdownloader/"><span style=" font-family:'-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif'; font-size:13px; font-weight:600; text-decoration: underline; color:#0073aa; background-color:#f1f1f1;">m</span></a><span style=" font-family:'-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif'; font-size:13px; font-weight:600; text-decoration: underline; color:#0073aa; background-color:#f1f1f1;">usicdownloader</span><a href="http://z52c.com/musicdownloader/"><span style=" font-family:'-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif'; font-size:13px; text-decoration: underline; color:#0073aa; background-color:#f1f1f1;">/</span></a><span style=" font-family:'-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif'; font-size:13px; color:#666666; background-color:#f1f1f1;"> </span></p> 31 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">在链接后面粘贴链接</p> 32 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">链接内容(QQ音乐支持):</span></p> 33 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 歌曲链接(如https://y.qq.com/n/yqq/song/003Afb7F2LwcmR.html)</p> 34 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 歌单链接(如https://y.qq.com/n/yqq/playlist/863753969.html)</p> 35 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 专辑链接(如https://y.qq.com/n/yqq/album/004QbYQU4CB1Zi.html)</p> 36 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">链接内容(网易云音乐支持):</span></p> 37 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 歌单链接(如http://music.163.com/#/playlist?id=940396145)</p> 38 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">若是想要下载排行榜整个榜单,可以先将排行榜收藏到歌单,再找到歌单链接下载。</p> 39 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">本软件网易云音乐下载,实际上调用的是QQ音乐的资源,所以有及其个别歌曲可能会有下载不到的情况,但很少(<span style=" text-decoration: underline;">基本不存在</span>)。</p> 40 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> 41 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">拯救网易云音乐灰掉的歌曲:一键下载歌单中所有灰掉的歌曲。</p> 42 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> 43 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">下载歌单或者专辑会在选中目录下以歌单名或者专辑名创建文件夹下载。</p> 44 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> 45 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">128音质较差,mp3推荐320音质,ape以及flac为无损音质</p> 46 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> 47 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">如果选择高的音质,在没有高的音质情况下,会默认下载128的音质</span></p></body></html> 48 | 49 | 50 | 51 | 52 | 53 | 300 54 | 20 55 | 75 56 | 23 57 | 58 | 59 | 60 | 关闭帮助 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /id3tag.cpp: -------------------------------------------------------------------------------- 1 | #include "id3tag.h" 2 | #include 3 | 4 | ID3tag::ID3tag(QObject *parent) : QObject(parent) 5 | { 6 | 7 | } 8 | 9 | ID3tag::~ID3tag() 10 | { 11 | delete fileN; 12 | delete fileS; 13 | delete fileImage; 14 | delete dStreamS; 15 | delete dStream; 16 | // delete tStream; 17 | } 18 | 19 | ID3tag::ID3tag(QString fileName) 20 | { 21 | mp3FileName=fileName; 22 | mp3FileNameTmp=fileName+QString(".tmp"); 23 | fileS=new QFile(mp3FileName); 24 | fileS->open(QIODevice::ReadOnly); 25 | fileN=new QFile(mp3FileNameTmp); 26 | fileN->open(QIODevice::WriteOnly); 27 | dStream=new QDataStream(fileN); 28 | memset(&tagHeader,0,sizeof(tagHeader)); 29 | memset(&titleHeader,0,sizeof(titleHeader)); 30 | memset(&artistHeader,0,sizeof(artistHeader)); 31 | memset(&albumHeader,0,sizeof(albumHeader)); 32 | memset(&picHeader,0,sizeof(picHeader)); 33 | tagHeader.identifier[0]='I'; 34 | tagHeader.identifier[1]='D'; 35 | tagHeader.identifier[2]='3'; 36 | tagHeader.version[0]=0x03; 37 | titleHeader.frameID[0]='T';titleHeader.frameID[1]='I';titleHeader.frameID[2]='T';titleHeader.frameID[3]='2'; 38 | artistHeader.frameID[0]='T';artistHeader.frameID[1]='P';artistHeader.frameID[2]='E';artistHeader.frameID[3]='1'; 39 | albumHeader.frameID[0]='T';albumHeader.frameID[1]='A';albumHeader.frameID[2]='L';albumHeader.frameID[3]='B'; 40 | picHeader.frameID[0]='A';picHeader.frameID[1]='P';picHeader.frameID[2]='I';picHeader.frameID[3]='C'; 41 | 42 | //获取mp3音频内容 43 | dStreamS =new QDataStream(fileS); 44 | dStreamS->readRawData((char*)&tagHeaderOld,10); 45 | int oldHeaderSize=128*128*128*tagHeaderOld.size[0]+128*128*tagHeaderOld.size[1]+128*tagHeaderOld.size[2]+tagHeaderOld.size[3]; 46 | fileS->seek(10+oldHeaderSize); 47 | mp3File=fileS->readAll(); 48 | } 49 | 50 | void ID3tag::setTitle(QString t) 51 | { 52 | title=t; 53 | titleSize=2*title.size()+3; 54 | titleHeader.size[3]=titleSize; 55 | } 56 | 57 | void ID3tag::setArtist(QString a) 58 | { 59 | artist=a; 60 | artistSize=2*a.size()+3; 61 | artistHeader.size[3]=artistSize; 62 | } 63 | 64 | void ID3tag::setAlbum(QString a) 65 | { 66 | album=a; 67 | albumSize=2*album.size()+3; 68 | albumHeader.size[3]=albumSize; 69 | } 70 | 71 | void ID3tag::setPic(QString imageFileName) 72 | { 73 | fileImage=new QFile(imageFileName); 74 | fileImage->open(QIODevice::ReadOnly); 75 | image=fileImage->readAll(); 76 | memset(mimeInfo,0,14); 77 | char tmp[14]={0x00,0x69,0x6D,0x61,0x67,0x65,0x2F,0x6A,0x70,0x65,0x67,0x00,0x03,0x00}; 78 | memcpy(mimeInfo,tmp,14); 79 | picSize=image.size()+14; 80 | picHeader.size[0]=picSize/(256*256*256); 81 | picHeader.size[1]=picSize%(256*256*256)/(256*256); 82 | picHeader.size[2]=picSize%(256*256*256)%(256*256)/256; 83 | picHeader.size[3]=picSize%(256*256*256)%(256*256)%256; 84 | } 85 | 86 | void ID3tag::doJob() 87 | { 88 | qDebug()<<"title QString:"<writeRawData((char*)&tagHeader,10); 109 | dStream->writeRawData((char*)&titleHeader,10); 110 | dStream->writeRawData((char*)unicodeBom,3); 111 | dStream->writeRawData((char*)title.data(),title.size()*2); 112 | dStream->writeRawData((char*)&artistHeader,10); 113 | dStream->writeRawData((char*)unicodeBom,3); 114 | dStream->writeRawData((char*)artist.data(),artist.size()*2); 115 | dStream->writeRawData((char*)&albumHeader,10); 116 | dStream->writeRawData((char*)unicodeBom,3); 117 | dStream->writeRawData((char*)album.data(),album.size()*2); 118 | dStream->writeRawData((char*)&picHeader,10); 119 | dStream->writeRawData(mimeInfo,14); 120 | dStream->writeRawData((char*)image.data(),image.size()); 121 | dStream->writeRawData((char*)mp3File.data(),mp3File.size()); 122 | fileImage->close(); 123 | fileN->close(); 124 | fileS->close(); 125 | fileS->remove(); 126 | fileN->rename(mp3FileName); 127 | emit finished(); 128 | } 129 | -------------------------------------------------------------------------------- /id3tag.h: -------------------------------------------------------------------------------- 1 | #ifndef ID3TAG_H 2 | #define ID3TAG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | typedef struct ID3HEADER{ 10 | char identifier[3]; 11 | char version[2]; 12 | char flags; 13 | char size[4]; 14 | }id3Header; 15 | 16 | typedef struct FRAMEHEADER{ 17 | char frameID[4]; 18 | char size[4]; 19 | char flags[2]; 20 | }frameHeader; 21 | 22 | class ID3tag : public QObject 23 | { 24 | Q_OBJECT 25 | private: 26 | id3Header tagHeaderOld; 27 | QString mp3FileName; 28 | QString mp3FileNameTmp; 29 | 30 | id3Header tagHeader; 31 | frameHeader titleHeader; 32 | frameHeader artistHeader; 33 | frameHeader albumHeader; 34 | frameHeader picHeader; 35 | 36 | int titleSize; 37 | int artistSize; 38 | int albumSize; 39 | int picSize; 40 | 41 | QString title; 42 | QString artist; 43 | QString album; 44 | QByteArray image; 45 | QByteArray mp3File; 46 | char mimeInfo[14]; 47 | 48 | QFile *fileN; //新的的文件 49 | QFile *fileS; //原来的文件 50 | QFile *fileImage; 51 | QDataStream *dStreamS; 52 | QDataStream *dStream; 53 | // QTextStream *tStream; 54 | 55 | public: 56 | explicit ID3tag(QObject *parent = nullptr); 57 | ID3tag(QString fileName); 58 | ~ID3tag(); 59 | void setTitle(QString t); 60 | void setArtist(QString a); 61 | void setAlbum(QString a); 62 | void setPic(QString imageFileName); 63 | void doJob(); 64 | 65 | signals: 66 | processState(QString ); 67 | finished(); 68 | public slots: 69 | }; 70 | 71 | #endif // ID3TAG_H 72 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int songNameType; 5 | int songQuality; 6 | QString mp3FileName; 7 | QString mp3Dir; 8 | QString vkey; 9 | QString guid; 10 | QString vkey2; 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | QApplication a(argc, argv); 15 | MainWindow w; 16 | w.show(); 17 | 18 | return a.exec(); 19 | } 20 | -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | 4 | MainWindow::MainWindow(QWidget *parent) : 5 | QMainWindow(parent), 6 | ui(new Ui::MainWindow) 7 | { songNameType=0; 8 | songQuality=0; 9 | ui->setupUi(this); 10 | dq=new downloadQueue(); 11 | connect(dq,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(downloadProgress(qint64,qint64))); 12 | connect(dq,SIGNAL(status(QString)),this,SLOT(status(QString))); 13 | connect(dq,SIGNAL(finished(QString)),this,SLOT(oneTaskFinished(QString))); 14 | 15 | h=new help(); 16 | t=new thanks(); 17 | p=new proxyForm(); 18 | _singerAllAlbum=new singerAllAlbum(); 19 | _singerAllAlbum->setDownloadQueue(dq); 20 | 21 | _vkeyinit2=new vkeyinit2(); 22 | connect(_vkeyinit2,SIGNAL(status(QString)),this,SLOT(status(QString))); 23 | connect(_vkeyinit2,SIGNAL(finished()),this,SLOT(init2Finished())); 24 | 25 | ui->pushButtonDownload->setEnabled(false); 26 | _vkeyinit2->init(); 27 | } 28 | 29 | MainWindow::~MainWindow() 30 | { 31 | delete ui; 32 | } 33 | 34 | void MainWindow::init2Finished() 35 | { 36 | ui->pushButtonDownload->setEnabled(true); 37 | QList tmp; 38 | tmp=dq->getQueue(); 39 | while(tmp.count()>0) 40 | { 41 | ui->textEditDownloadQueueInfo->append(tmp.at(0).url); 42 | tmp.removeAt(0); 43 | } 44 | } 45 | 46 | void MainWindow::on_pushButtonChosePath_clicked() 47 | { 48 | mp3Dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), "/home", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); 49 | ui->lineEditMp3Path->setText(mp3Dir); 50 | } 51 | 52 | 53 | void MainWindow::on_radioButtonSongNameType1_clicked() 54 | { 55 | songNameType=1; 56 | } 57 | 58 | void MainWindow::on_radioButtonSongNameType2_clicked() 59 | { 60 | songNameType=2; 61 | } 62 | 63 | void MainWindow::on_radioButtonQuality128_clicked() 64 | { 65 | songQuality=1; 66 | } 67 | 68 | void MainWindow::on_radioButtonQuality320_clicked() 69 | { 70 | songQuality=2; 71 | } 72 | 73 | void MainWindow::on_radioButtonQualityflac_clicked() 74 | { 75 | songQuality=3; 76 | } 77 | 78 | void MainWindow::on_radioButtonQualityape_clicked() 79 | { 80 | songQuality=4; 81 | } 82 | 83 | void MainWindow::on_pushButtonDownload_clicked() 84 | { 85 | mp3Dir=ui->lineEditMp3Path->text(); 86 | if(!songNameType || !songQuality || ui->lineEditMp3Path->text().isEmpty() || ui->lineEditLink->text().isEmpty()) 87 | { 88 | ui->textEditFinishedInfo->append("请输入合法的设置"); 89 | } 90 | else{ 91 | if(ui->lineEditLink->text().contains("y.qq.com")) 92 | { 93 | if(ui->lineEditLink->text().contains("num")) 94 | { 95 | ui->textEditFinishedInfo->append("请选择不含num的链接"); 96 | return; 97 | } 98 | qDebug()<insertQueue(0,songQuality,songNameType,mp3Dir,ui->lineEditLink->text()); 100 | ui->textEditDownloadQueueInfo->append(ui->lineEditLink->text()); 101 | 102 | } 103 | else{ 104 | if(ui->lineEditLink->text().contains("music.163.com")) 105 | { 106 | if(ui->lineEditLink->text().contains("playlist")) 107 | { 108 | ui->textEditDownloadQueueInfo->append(ui->lineEditLink->text()); 109 | dq->insertQueue(1,songQuality,songNameType,mp3Dir,ui->lineEditLink->text()); 110 | } 111 | else{ 112 | ui->textEditFinishedInfo->append("网易云音乐仅支持歌单下载,单曲以及专辑下载请使用qq音乐链接"); 113 | } 114 | } 115 | } 116 | 117 | } 118 | } 119 | 120 | 121 | void MainWindow::status(QString inStr) 122 | { 123 | ui->textEditNowInfo->append(inStr); 124 | } 125 | 126 | void MainWindow::oneTaskFinished(QString inStr) 127 | { 128 | ui->textEditDownloadQueueInfo->clear(); 129 | ui->textEditNowInfo->clear(); 130 | ui->textEditFinishedInfo->append(QString("%1 finished").arg(inStr)); 131 | QList tmp; 132 | tmp=dq->getQueue(); 133 | while(tmp.count()>0) 134 | { 135 | ui->textEditDownloadQueueInfo->append(tmp.at(0).url); 136 | tmp.removeAt(0); 137 | } 138 | } 139 | 140 | void MainWindow::on_pushButtonGray_clicked() 141 | { 142 | mp3Dir=ui->lineEditMp3Path->text(); 143 | if(ui->lineEditLink->text().contains("music.163.com")&&ui->lineEditLink->text().contains("playlist")) 144 | { 145 | ui->textEditDownloadQueueInfo->append(ui->lineEditLink->text()); 146 | dq->insertQueue(2,songQuality,songNameType,mp3Dir,ui->lineEditLink->text()); 147 | } 148 | } 149 | 150 | void MainWindow::on_pushButton_clicked() 151 | { 152 | qDebug()<progressBar->setMaximum(bytesTotal); 159 | ui->progressBar->setValue(bytesReceived); 160 | } 161 | 162 | void MainWindow::on_action_triggered() 163 | { 164 | h->show(); 165 | } 166 | 167 | void MainWindow::on_action_2_triggered() 168 | { 169 | t->show(); 170 | } 171 | 172 | void MainWindow::on_action_3_triggered() 173 | { 174 | p->show(); 175 | } 176 | 177 | void MainWindow::on_action_4_triggered() 178 | { 179 | _singerAllAlbum->show(); 180 | } 181 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include "downloadqueue.h" 6 | #include "help.h" 7 | #include "thanks.h" 8 | #include "vkeyinit2.h" 9 | #include "proxyform.h" 10 | #include 11 | #include 12 | #include 13 | #include "singerallalbum.h" 14 | 15 | namespace Ui { 16 | class MainWindow; 17 | } 18 | 19 | class MainWindow : public QMainWindow 20 | { 21 | Q_OBJECT 22 | 23 | public: 24 | explicit MainWindow(QWidget *parent = 0); 25 | ~MainWindow(); 26 | 27 | private slots: 28 | void on_pushButtonChosePath_clicked(); 29 | 30 | void on_radioButtonSongNameType1_clicked(); 31 | 32 | void on_radioButtonSongNameType2_clicked(); 33 | 34 | void on_radioButtonQuality128_clicked(); 35 | 36 | void on_radioButtonQuality320_clicked(); 37 | 38 | void on_radioButtonQualityflac_clicked(); 39 | 40 | void on_radioButtonQualityape_clicked(); 41 | 42 | void status(QString inStr); 43 | void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); 44 | void oneTaskFinished(QString inStr); 45 | 46 | void on_pushButtonDownload_clicked(); 47 | 48 | void on_pushButtonGray_clicked(); 49 | 50 | void init2Finished(); 51 | 52 | void on_pushButton_clicked(); 53 | 54 | void on_action_triggered(); 55 | 56 | void on_action_2_triggered(); 57 | 58 | void on_action_3_triggered(); 59 | 60 | void on_action_4_triggered(); 61 | 62 | private: 63 | Ui::MainWindow *ui; 64 | int songNameType; 65 | int songQuality; 66 | QString mp3Dir; 67 | 68 | downloadQueue *dq; 69 | 70 | help *h; 71 | thanks *t; 72 | proxyForm *p; 73 | singerAllAlbum *_singerAllAlbum; 74 | vkeyinit2 *_vkeyinit2; 75 | }; 76 | 77 | #endif // MAINWINDOW_H 78 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 654 10 | 459 11 | 12 | 13 | 14 | QQMusic&NeteaseMusicDownloader 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 链接: 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 文件保存目录: 44 | 45 | 46 | 47 | 48 | 49 | 50 | true 51 | 52 | 53 | 54 | 55 | 56 | 57 | ... 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 名称格式 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 歌名-歌手 75 | 76 | 77 | 78 | 79 | 80 | 81 | 歌手-歌名 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 音质 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 128 102 | 103 | 104 | 105 | 106 | 107 | 108 | 320 109 | 110 | 111 | 112 | 113 | 114 | 115 | flac 116 | 117 | 118 | 119 | 120 | 121 | 122 | ape 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | Qt::Horizontal 137 | 138 | 139 | 140 | 188 141 | 20 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 下载 150 | 151 | 152 | 153 | 154 | 155 | 156 | 拯救网易云灰色歌曲 157 | 158 | 159 | 160 | 161 | 162 | 163 | 打开下载的位置 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 当前歌曲进度 175 | 176 | 177 | 178 | 179 | 180 | 181 | 0 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 队列中的下载任务(第一行为当前任务) 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 已完成的任务 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 0 234 | 0 235 | 654 236 | 23 237 | 238 | 239 | 240 | 241 | 帮助 242 | 243 | 244 | 245 | 246 | 247 | 248 | 代理 249 | 250 | 251 | 252 | 253 | 254 | 下载歌手所有专辑 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | TopToolBarArea 265 | 266 | 267 | false 268 | 269 | 270 | 271 | 272 | 273 | 使用说明 274 | 275 | 276 | 277 | 278 | 要饭 279 | 280 | 281 | 282 | 283 | 代理 284 | 285 | 286 | 287 | 288 | 下载歌手所有专辑 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | -------------------------------------------------------------------------------- /musicDownloader.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2018-07-12T15:31:35 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui network sql 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = musicDownloader 12 | TEMPLATE = app 13 | 14 | RC_ICONS=1.ico 15 | 16 | # The following define makes your compiler emit warnings if you use 17 | # any feature of Qt which has been marked as deprecated (the exact warnings 18 | # depend on your compiler). Please consult the documentation of the 19 | # deprecated API in order to know how to port your code away from it. 20 | DEFINES += QT_DEPRECATED_WARNINGS 21 | 22 | # You can also make your code fail to compile if you use deprecated APIs. 23 | # In order to do so, uncomment the following line. 24 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 25 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 26 | 27 | 28 | SOURCES += \ 29 | main.cpp \ 30 | mainwindow.cpp \ 31 | daye.cpp \ 32 | downloader.cpp \ 33 | help.cpp \ 34 | id3tag.cpp \ 35 | proxyform.cpp \ 36 | thanks.cpp \ 37 | db4musicdownloader.cpp \ 38 | downloadqueue.cpp \ 39 | neteaseplaylist.cpp \ 40 | neteasesong.cpp \ 41 | qqmusic.cpp \ 42 | qqmusicalbum.cpp \ 43 | qqmusicplaylist.cpp \ 44 | qqmusicsearch.cpp \ 45 | qqmusicsong.cpp \ 46 | vkeyinit2.cpp \ 47 | singerallalbum.cpp \ 48 | axeldownload.cpp 49 | 50 | HEADERS += \ 51 | mainwindow.h \ 52 | config.h \ 53 | daye.h \ 54 | downloader.h \ 55 | help.h \ 56 | id3tag.h \ 57 | proxyform.h \ 58 | thanks.h \ 59 | db4musicdownloader.h \ 60 | downloadqueue.h \ 61 | neteaseplaylist.h \ 62 | neteasesong.h \ 63 | qqmusic.h \ 64 | qqmusicalbum.h \ 65 | qqmusicplaylist.h \ 66 | qqmusicsearch.h \ 67 | qqmusicsong.h \ 68 | vkeyinit2.h \ 69 | singerallalbum.h \ 70 | axeldownload.h 71 | 72 | FORMS += \ 73 | mainwindow.ui \ 74 | help.ui \ 75 | proxyform.ui \ 76 | thanks.ui \ 77 | singerallalbum.ui 78 | 79 | RESOURCES += \ 80 | pic.qrc 81 | 82 | DISTFILES += \ 83 | 1.jpg \ 84 | 1.ico 85 | 86 | VERSION = 1.8.4 87 | -------------------------------------------------------------------------------- /musicDownloader.pro.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {a3f93c6e-ab67-4342-b3ab-7cc3ebbade5e} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | true 45 | 0 46 | 8 47 | true 48 | 1 49 | true 50 | true 51 | true 52 | false 53 | 54 | 55 | 56 | ProjectExplorer.Project.PluginSettings 57 | 58 | 59 | 60 | ProjectExplorer.Project.Target.0 61 | 62 | Desktop Qt 5.11.0 MinGW 32bit_static 63 | Desktop Qt 5.11.0 MinGW 32bit_static 64 | {0c47e6e6-c7e4-4aa1-85fa-c060226e239c} 65 | 1 66 | 0 67 | 0 68 | 69 | D:/QtProject/build-musicDownloader-Desktop_Qt_5_11_0_MinGW_32bit_static-Debug 70 | 71 | 72 | true 73 | qmake 74 | 75 | QtProjectManager.QMakeBuildStep 76 | true 77 | 78 | false 79 | false 80 | false 81 | 82 | 83 | true 84 | Make 85 | 86 | Qt4ProjectManager.MakeStep 87 | 88 | false 89 | 90 | 91 | 92 | 2 93 | Build 94 | 95 | ProjectExplorer.BuildSteps.Build 96 | 97 | 98 | 99 | true 100 | Make 101 | 102 | Qt4ProjectManager.MakeStep 103 | 104 | true 105 | clean 106 | 107 | 108 | 1 109 | Clean 110 | 111 | ProjectExplorer.BuildSteps.Clean 112 | 113 | 2 114 | false 115 | 116 | Debug 117 | Debug 118 | Qt4ProjectManager.Qt4BuildConfiguration 119 | 2 120 | true 121 | 122 | 123 | D:/QtProject/build-musicDownloader-Desktop_Qt_5_11_0_MinGW_32bit_static-Release 124 | 125 | 126 | true 127 | qmake 128 | 129 | QtProjectManager.QMakeBuildStep 130 | false 131 | 132 | false 133 | false 134 | false 135 | 136 | 137 | true 138 | Make 139 | 140 | Qt4ProjectManager.MakeStep 141 | 142 | false 143 | 144 | 145 | 146 | 2 147 | Build 148 | 149 | ProjectExplorer.BuildSteps.Build 150 | 151 | 152 | 153 | true 154 | Make 155 | 156 | Qt4ProjectManager.MakeStep 157 | 158 | true 159 | clean 160 | 161 | 162 | 1 163 | Clean 164 | 165 | ProjectExplorer.BuildSteps.Clean 166 | 167 | 2 168 | false 169 | 170 | Release 171 | Release 172 | Qt4ProjectManager.Qt4BuildConfiguration 173 | 0 174 | true 175 | 176 | 177 | D:/QtProject/build-musicDownloader-Desktop_Qt_5_11_0_MinGW_32bit_static-Profile 178 | 179 | 180 | true 181 | qmake 182 | 183 | QtProjectManager.QMakeBuildStep 184 | true 185 | 186 | false 187 | true 188 | false 189 | 190 | 191 | true 192 | Make 193 | 194 | Qt4ProjectManager.MakeStep 195 | 196 | false 197 | 198 | 199 | 200 | 2 201 | Build 202 | 203 | ProjectExplorer.BuildSteps.Build 204 | 205 | 206 | 207 | true 208 | Make 209 | 210 | Qt4ProjectManager.MakeStep 211 | 212 | true 213 | clean 214 | 215 | 216 | 1 217 | Clean 218 | 219 | ProjectExplorer.BuildSteps.Clean 220 | 221 | 2 222 | false 223 | 224 | Profile 225 | Profile 226 | Qt4ProjectManager.Qt4BuildConfiguration 227 | 0 228 | true 229 | 230 | 3 231 | 232 | 233 | 0 234 | 部署 235 | 236 | ProjectExplorer.BuildSteps.Deploy 237 | 238 | 1 239 | 部署设置 240 | 241 | ProjectExplorer.DefaultDeployConfiguration 242 | 243 | 1 244 | 245 | 246 | false 247 | false 248 | 1000 249 | 250 | true 251 | 252 | false 253 | false 254 | false 255 | false 256 | true 257 | 0.01 258 | 10 259 | true 260 | 1 261 | 25 262 | 263 | 1 264 | true 265 | false 266 | true 267 | valgrind 268 | 269 | 0 270 | 1 271 | 2 272 | 3 273 | 4 274 | 5 275 | 6 276 | 7 277 | 8 278 | 9 279 | 10 280 | 11 281 | 12 282 | 13 283 | 14 284 | 285 | 2 286 | 287 | musicDownloader 288 | 289 | Qt4ProjectManager.Qt4RunConfiguration:D:/QtProject/musicDownloader/musicDownloader.pro 290 | true 291 | 292 | musicDownloader.pro 293 | false 294 | 295 | D:/QtProject/build-musicDownloader-Desktop_Qt_5_11_0_MinGW_32bit_static-Release 296 | 3768 297 | false 298 | true 299 | false 300 | false 301 | true 302 | 303 | 1 304 | 305 | 306 | 307 | ProjectExplorer.Project.TargetCount 308 | 1 309 | 310 | 311 | ProjectExplorer.Project.Updater.FileVersion 312 | 18 313 | 314 | 315 | Version 316 | 18 317 | 318 | 319 | -------------------------------------------------------------------------------- /neteaseplaylist.cpp: -------------------------------------------------------------------------------- 1 | #include "neteaseplaylist.h" 2 | 3 | neteasePlaylist::neteasePlaylist(QObject *parent) : QObject(parent) 4 | { 5 | isGray=false; 6 | d=new downloader(); 7 | d->setUserAgent(UA); 8 | connect(d,SIGNAL(finished()),this,SLOT(htmlGot())); 9 | connect(d,SIGNAL(downloadError(QString)),this,SLOT(htmlGotFailed(QString))); 10 | connect(d,SIGNAL(redirected(QString)),this,SLOT(htmlGotRedirected(QString))); 11 | s=new neteaseSong(); 12 | connect(s,SIGNAL(finished(int,bool,QString)),this,SLOT(neteaseSongFinished(int,bool,QString))); 13 | } 14 | 15 | void neteasePlaylist::doJob(bool inIsGray,QString inUrl) 16 | { 17 | emit status("下载列表所有歌曲信息,此处需要耐心等待片刻,曲目数越多,等待时间越长"); 18 | isGray=inIsGray; 19 | infoList.clear(); 20 | grayList.clear(); 21 | songMidList.clear(); 22 | listTitle=""; 23 | int pos; 24 | if(inUrl.contains("playlist?id=")&&inUrl.contains("music.163.com")) 25 | { 26 | if(inUrl.contains("&")) 27 | { 28 | char a[20]; 29 | getStringBetweenAandB(inUrl.toStdString().c_str(),"=","&",a); 30 | mid=QString(a); 31 | }else{ 32 | pos=inUrl.indexOf(QString("=")); 33 | mid=inUrl.mid(pos+1); 34 | } 35 | }else if(inUrl.contains("playlist/")) 36 | { 37 | char a[20]; 38 | getStringBetweenAandB(inUrl.toStdString().c_str(),"playlist/","/",a); 39 | mid=QString(a); 40 | } 41 | else 42 | { 43 | finished(-1,infoList); 44 | } 45 | 46 | QString listUrl=QString("http://music.163.com/playlist?id=")+mid; 47 | d->init(listUrl,SONGHTMLFILE); 48 | d->doGet(); 49 | } 50 | 51 | void neteasePlaylist::htmlGotFailed(QString errorString) 52 | { 53 | emit status(QString("neteasePlaylist html failed:")+errorString); 54 | finished(-1,infoList); 55 | } 56 | 57 | void neteasePlaylist::htmlGotRedirected(QString redirectString) 58 | { 59 | d->init(redirectString,SONGHTMLFILE); 60 | d->doGet(); 61 | } 62 | 63 | void neteasePlaylist::htmlGot() 64 | { 65 | QFile file(SONGHTMLFILE); 66 | QString line; 67 | int pos; 68 | char tmpString[200]; 69 | if(file.open(QIODevice::ReadOnly)) 70 | { 71 | while(!file.atEnd()) 72 | { 73 | line=file.readLine(); 74 | if(line.contains("appid")) 75 | { 76 | line=file.readLine(); 77 | getStringBetweenAandB(line.toStdString().c_str(),"\"title\": \"","\"",tmpString); 78 | listTitle=QString(tmpString); 79 | break; 80 | } 81 | } 82 | qDebug()<')); 109 | listTitle.remove(QChar('<')); 110 | listTitle.remove(QChar('*')); 111 | listTitle.remove(QChar('?')); 112 | listTitle.remove(QChar('/')); 113 | listTitle.remove(QChar('\\')); 114 | listTitle.remove(QChar(':')); 115 | 116 | mp3Dir=mp3Dir+QString("/")+listTitle; 117 | QDir tmp(mp3Dir); 118 | if(!tmp.exists()) 119 | { 120 | tmp.mkdir(mp3Dir); 121 | } 122 | s->doJob(songMidList.at(0)); 123 | } 124 | 125 | 126 | void neteasePlaylist::neteaseSongFinished(int inFlag,bool inIsGray,QString inString) 127 | { 128 | if(inFlag) 129 | { 130 | emit status(songMidList.at(0)+QString("html下载失败:")+inString); 131 | } 132 | else{ 133 | if(inIsGray) 134 | grayList.append(inString); 135 | infoList.append(inString); 136 | songMidList.removeAt(0); 137 | if(songMidList.count()>0) 138 | { 139 | s->doJob(songMidList.at(0)); 140 | } 141 | else{ 142 | if(isGray){ 143 | emit finished(0,grayList); 144 | } 145 | else{ 146 | finished(0,infoList); 147 | } 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /neteaseplaylist.h: -------------------------------------------------------------------------------- 1 | #ifndef NETEASEPLAYLIST_H 2 | #define NETEASEPLAYLIST_H 3 | 4 | #include 5 | #include "downloader.h" 6 | #include "daye.h" 7 | #include "config.h" 8 | #include "neteasesong.h" 9 | 10 | extern int songNameType; 11 | extern int songQuality; 12 | extern QString mp3FileName; 13 | extern QString mp3Dir; 14 | extern QString vkey; 15 | extern QString guid; 16 | 17 | 18 | class neteasePlaylist : public QObject 19 | { 20 | Q_OBJECT 21 | public: 22 | explicit neteasePlaylist(QObject *parent = nullptr); 23 | void doJob(bool inIsGray,QString inUrl); 24 | signals: 25 | void finished(int ,QStringList); 26 | void status(QString); 27 | public slots: 28 | void htmlGot(); 29 | void htmlGotFailed(QString errorString); 30 | void htmlGotRedirected(QString redirectString); 31 | void neteaseSongFinished(int inFlag,bool inIsGray,QString inString); 32 | 33 | private: 34 | QString mid; 35 | downloader *d; 36 | neteaseSong *s; 37 | QStringList songMidList; 38 | bool isGray; 39 | QStringList infoList; 40 | QStringList grayList; 41 | QString listTitle; 42 | }; 43 | 44 | #endif // NETEASEPLAYLIST_H 45 | -------------------------------------------------------------------------------- /neteasesong.cpp: -------------------------------------------------------------------------------- 1 | #include "neteasesong.h" 2 | 3 | neteaseSong::neteaseSong(QObject *parent) : QObject(parent) 4 | { 5 | d=new downloader(); 6 | d->setUserAgent(UA); 7 | connect(d,SIGNAL(finished()),this,SLOT(htmlFileGot())); 8 | connect(d,SIGNAL(downloadError(QString)),this,SLOT(htmlFileGotFailed(QString))); 9 | connect(d,SIGNAL(redirected(QString)),this,SLOT(htmlGotRedirected(QString))); 10 | 11 | search=new qqMusicSearch(); 12 | connect(search,SIGNAL(finished(int,QString)),this,SLOT(searchResultGot(int,QString))); 13 | } 14 | 15 | void neteaseSong::doJob(QString inMid) 16 | { 17 | QString tmpUrl=QString("http://music.163.com/song?id=")+inMid; 18 | qDebug()<init(tmpUrl,QString(SONGHTMLFILE)); 20 | d->doGet(); 21 | } 22 | 23 | void neteaseSong::htmlGotRedirected(QString redirectString) 24 | { 25 | d->init(redirectString,QString(SONGHTMLFILE)); 26 | d->doGet(); 27 | } 28 | 29 | void neteaseSong::htmlFileGotFailed(QString errorString) 30 | { 31 | emit finished(-1,0,errorString); 32 | } 33 | 34 | void neteaseSong::htmlFileGot() 35 | { 36 | isGray=false; 37 | QString line; 38 | QFile file(SONGHTMLFILE); 39 | file.open(QIODevice::ReadOnly); 40 | char tmpSongName[200]; 41 | char tmpSinger[100]; 42 | char tmpAlbum[100]; 43 | while(!file.atEnd()) 44 | { 45 | line=file.readLine(); 46 | 47 | if(line.contains(QString("appid"))) 48 | { 49 | line=file.readLine(); 50 | getStringBetweenAandB(line.toStdString().c_str(),"\"title\": \"","\"",tmpSongName); 51 | line=file.readLine(); 52 | line=file.readLine(); 53 | getStringBetweenAandB(line.toStdString().c_str(),"歌手:","。",tmpSinger); 54 | getStringBetweenAandB(line.toStdString().c_str(),"所属专辑:","。",tmpAlbum); 55 | break; 56 | } 57 | } 58 | while(!file.atEnd()) 59 | { 60 | line=file.readLine(); 61 | if(line.contains("u-btni-play")) 62 | { 63 | isGray=true; 64 | break; 65 | } 66 | } 67 | file.close(); 68 | search->doJob(QString(tmpSongName)+QString(" ")+QString(tmpSinger)+QString(" ")+QString(tmpAlbum)); 69 | } 70 | 71 | void neteaseSong::searchResultGot(int inFlag, QString inString) 72 | { 73 | finished(inFlag,isGray,inString); 74 | } 75 | -------------------------------------------------------------------------------- /neteasesong.h: -------------------------------------------------------------------------------- 1 | #ifndef NETEASESONG_H 2 | #define NETEASESONG_H 3 | 4 | #include 5 | #include "downloader.h" 6 | #include "daye.h" 7 | #include "config.h" 8 | #include "qqmusicsearch.h" 9 | 10 | class neteaseSong : public QObject 11 | { 12 | Q_OBJECT 13 | public: 14 | explicit neteaseSong(QObject *parent = nullptr); 15 | void doJob(QString inMid); 16 | signals: 17 | void finished(int ,bool,QString); 18 | public slots: 19 | void htmlFileGot(); 20 | void htmlFileGotFailed(QString errorString); 21 | void htmlGotRedirected(QString redirectString); 22 | void searchResultGot(int inFlag,QString inString); 23 | private: 24 | downloader *d; 25 | qqMusicSearch *search; 26 | bool isGray; 27 | }; 28 | 29 | #endif // NETEASESONG_H 30 | -------------------------------------------------------------------------------- /pic.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.jpg 4 | 5 | 6 | -------------------------------------------------------------------------------- /proxyform.cpp: -------------------------------------------------------------------------------- 1 | #include "proxyform.h" 2 | #include "ui_proxyform.h" 3 | #include 4 | #include "daye.h" 5 | #include 6 | proxyForm::proxyForm(QWidget *parent) : 7 | QWidget(parent), 8 | ui(new Ui::proxyForm) 9 | { 10 | ui->setupUi(this); 11 | QFileInfo a("proxy.conf"); 12 | if(a.isFile()) 13 | { 14 | QFile fileProxy("proxy.conf"); 15 | QString line; 16 | char tmp[5000]; 17 | if(fileProxy.open(QIODevice::ReadOnly)) 18 | { 19 | line=fileProxy.readLine(); 20 | fileProxy.close(); 21 | } 22 | if(!line.isEmpty()) 23 | { 24 | getStringBetweenAandB(line.toStdString().c_str(),"socks5Addr:\"","\"",tmp); 25 | ui->lineEditAddr->setText(tmp); 26 | getStringBetweenAandB(line.toStdString().c_str(),"socks5Port:\"","\"",tmp); 27 | ui->lineEditPort->setText(tmp); 28 | getStringBetweenAandB(line.toStdString().c_str(),"socks5User:\"","\"",tmp); 29 | ui->lineEditUser->setText(tmp); 30 | getStringBetweenAandB(line.toStdString().c_str(),"socks5Pass:\"","\"",tmp); 31 | ui->lineEditPass->setText(tmp); 32 | } 33 | fileProxy.close(); 34 | } 35 | } 36 | 37 | proxyForm::~proxyForm() 38 | { 39 | delete ui; 40 | } 41 | 42 | void proxyForm::on_pushButton_2_clicked() 43 | { 44 | this->close(); 45 | } 46 | 47 | void proxyForm::on_pushButton_clicked() 48 | { 49 | QFile fileProxy("proxy.conf"); 50 | QString writeData; 51 | writeData=QString("\"socks5Addr:\"")+ui->lineEditAddr->text()+QString("\",")+QString("\"socks5Port:\"")+ui->lineEditPort->text()+QString("\",")+QString("\"socks5User:\"")+ui->lineEditUser->text()+QString("\",")+QString("\"socks5Pass:\"")+ui->lineEditPass->text()+QString("\""); 52 | if(fileProxy.open(QIODevice::WriteOnly)) 53 | { 54 | QTextStream in(&fileProxy); 55 | in<close(); 59 | } 60 | -------------------------------------------------------------------------------- /proxyform.h: -------------------------------------------------------------------------------- 1 | #ifndef PROXYFORM_H 2 | #define PROXYFORM_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class proxyForm; 8 | } 9 | 10 | class proxyForm : public QWidget 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit proxyForm(QWidget *parent = 0); 16 | ~proxyForm(); 17 | 18 | private slots: 19 | void on_pushButton_2_clicked(); 20 | 21 | void on_pushButton_clicked(); 22 | 23 | private: 24 | Ui::proxyForm *ui; 25 | }; 26 | 27 | #endif // PROXYFORM_H 28 | -------------------------------------------------------------------------------- /proxyform.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | proxyForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 333 10 | 206 11 | 12 | 13 | 14 | ProxyForm(work after reboot) 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | socks5Address: 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | port: 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | user: 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | password: 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | Qt::Horizontal 81 | 82 | 83 | 84 | 40 85 | 20 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | ok 94 | 95 | 96 | 97 | 98 | 99 | 100 | cancel 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /qqmusic.cpp: -------------------------------------------------------------------------------- 1 | #include "qqmusic.h" 2 | 3 | qqmusic::qqmusic(QObject *parent) : QObject(parent) 4 | { 5 | album=new qqMusicAlbum(); 6 | connect(album,SIGNAL(status(QString)),this,SIGNAL(status(QString))); 7 | connect(album,SIGNAL(finished(int,QStringList)),this,SLOT(beginToDownload(int,QStringList))); 8 | playlist=new qqMusicPlaylist(); 9 | connect(playlist,SIGNAL(status(QString)),this,SIGNAL(status(QString))); 10 | connect(playlist,SIGNAL(finished(int,QStringList)),this,SLOT(beginToDownload(int,QStringList))); 11 | song=new qqMusicSong(); 12 | connect(song,SIGNAL(status(QString)),this,SIGNAL(status(QString))); 13 | connect(song,SIGNAL(progress(qint64,qint64)),this,SIGNAL(progress(qint64,qint64))); 14 | connect(song,SIGNAL(finished(int)),this,SLOT(songDownloadFinished(int))); 15 | 16 | } 17 | 18 | void qqmusic::doJob(QString inlink) 19 | { 20 | songMidList.clear(); 21 | index=0; 22 | total=0; 23 | char tmpMid[20]; 24 | if(inlink.contains("y.qq.com/n/yqq/song")) 25 | { 26 | getStringBetweenAandB(inlink.toStdString().c_str(),"y.qq.com/n/yqq/song/",".html",tmpMid); 27 | songMidList.append(QString(tmpMid)); 28 | downloadSong(); 29 | return; 30 | } 31 | 32 | if(inlink.contains("y.qq.com/n/yqq/album")) 33 | { 34 | getStringBetweenAandB(inlink.toStdString().c_str(),"y.qq.com/n/yqq/album/",".html",tmpMid); 35 | album->doJob(QString(tmpMid)); 36 | return; 37 | } 38 | 39 | if(inlink.contains("y.qq.com/n/yqq/playsquare")) 40 | { 41 | getStringBetweenAandB(inlink.toStdString().c_str(),"y.qq.com/n/yqq/playsquare/",".html",tmpMid); 42 | playlist->doJob(QString(tmpMid)); 43 | return; 44 | } 45 | if(inlink.contains("y.qq.com/n/yqq/playlist")) 46 | { 47 | getStringBetweenAandB(inlink.toStdString().c_str(),"y.qq.com/n/yqq/playlist/",".html",tmpMid); 48 | playlist->doJob(QString(tmpMid)); 49 | return; 50 | } 51 | } 52 | 53 | 54 | void qqmusic::beginToDownload(int inFlag, QStringList inSongMidList) 55 | { 56 | if(inFlag) 57 | { 58 | emit finished(); 59 | return; 60 | } 61 | else{ 62 | songMidList=inSongMidList; 63 | downloadSong(); 64 | } 65 | } 66 | 67 | void qqmusic::downloadSong() 68 | { 69 | total=songMidList.count(); 70 | emit status(QString("下载第1/")+QString::number(total)+QString("首...")); 71 | song->doJob(songMidList.at(0)); 72 | } 73 | 74 | void qqmusic::songDownloadFinished(int inFlag) 75 | { 76 | songMidList.removeAt(0); 77 | if(songMidList.count()>0) 78 | { 79 | emit status(QString("下载第")+QString::number(total-songMidList.count()+1)+QString("/")+QString::number(total)+QString("首...")); 80 | song->doJob(songMidList.at(0)); 81 | } 82 | else{ 83 | emit finished(); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /qqmusic.h: -------------------------------------------------------------------------------- 1 | #ifndef QQMUSIC_H 2 | #define QQMUSIC_H 3 | 4 | #include 5 | #include "qqmusicalbum.h" 6 | #include "qqmusicplaylist.h" 7 | #include "qqmusicsong.h" 8 | 9 | extern int songNameType; 10 | extern int songQuality; 11 | extern QString mp3FileName; 12 | extern QString mp3Dir; 13 | extern QString vkey; 14 | extern QString guid; 15 | 16 | class qqmusic : public QObject 17 | { 18 | Q_OBJECT 19 | public: 20 | explicit qqmusic(QObject *parent = nullptr); 21 | void doJob(QString inlink); 22 | signals: 23 | void progress(qint64, qint64); 24 | void finished(); 25 | void status(QString); 26 | public slots: 27 | void beginToDownload(int inFlag,QStringList inSongMidList); 28 | void songDownloadFinished(int inFlag); 29 | private: 30 | qqMusicAlbum *album; 31 | qqMusicPlaylist *playlist; 32 | qqMusicSong *song; 33 | 34 | QStringList songMidList; 35 | int index; 36 | int total; 37 | 38 | void downloadSong(); 39 | }; 40 | 41 | #endif // QQMUSIC_H 42 | -------------------------------------------------------------------------------- /qqmusicalbum.cpp: -------------------------------------------------------------------------------- 1 | #include "qqmusicalbum.h" 2 | 3 | qqMusicAlbum::qqMusicAlbum(QObject *parent) : QObject(parent) 4 | { 5 | d=new downloader(); 6 | connect(d,SIGNAL(finished()),this,SLOT(albumListGot())); 7 | connect(d,SIGNAL(downloadError(QString)),this,SLOT(albumListGotFailed(QString))); 8 | connect(d,SIGNAL(redirected(QString)),this,SLOT(albumListGotFailed(QString))); 9 | } 10 | 11 | void qqMusicAlbum::doJob(QString inMid) 12 | { 13 | albumMid=inMid; 14 | albumDownloadLink=QString(ALBUMLINKHEAD)+albumMid+QString(ALBUMLINKTAIL); 15 | d->init(albumDownloadLink,QString(ALBUMLISTFILE)); 16 | qDebug()<<"准备下载专辑列表"; 17 | d->doGet(); 18 | } 19 | 20 | void qqMusicAlbum::albumListGotFailed(QString errorString) 21 | { 22 | QStringList a; 23 | emit status(QString("QQMusic albumlist json data download failed:")+errorString); 24 | finished(-1,a); 25 | } 26 | 27 | void qqMusicAlbum::albumListGot() 28 | { 29 | songMidList.clear(); 30 | QFile file(ALBUMLISTFILE); 31 | int index=0; 32 | QString songmid; 33 | QString albumDirName; 34 | file.open(QIODevice::ReadOnly); 35 | QString str=file.readAll(); 36 | file.close(); 37 | 38 | //将专辑名字作为目录名 39 | if(-1!=(index=str.indexOf("albumname",index))) 40 | { 41 | index+=12; 42 | albumDirName=""; 43 | while(str.at(index)!='\"') 44 | { 45 | albumDirName+=str.at(index); 46 | index++; 47 | } 48 | albumDirName.remove(QChar('|')); 49 | albumDirName.remove(QChar('>')); 50 | albumDirName.remove(QChar('<')); 51 | albumDirName.remove(QChar('*')); 52 | albumDirName.remove(QChar('?')); 53 | albumDirName.remove(QChar('/')); 54 | albumDirName.remove(QChar('\\')); 55 | albumDirName.remove(QChar(':')); 56 | qDebug()< 5 | #include "daye.h" 6 | #include "config.h" 7 | #include "downloader.h" 8 | 9 | extern int songNameType; 10 | extern int songQuality; 11 | extern QString mp3FileName; 12 | extern QString mp3Dir; 13 | extern QString vkey; 14 | extern QString guid; 15 | 16 | class qqMusicAlbum : public QObject 17 | { 18 | Q_OBJECT 19 | public: 20 | explicit qqMusicAlbum(QObject *parent = nullptr); 21 | void doJob(QString inMid); 22 | signals: 23 | void finished(int,QStringList); 24 | void status(QString); 25 | public slots: 26 | void albumListGot(); 27 | void albumListGotFailed(QString errorString); 28 | private: 29 | downloader *d; //下载专辑json数据,只用一次 30 | QStringList songMidList; 31 | QString albumMid; 32 | QString albumDownloadLink; 33 | }; 34 | 35 | #endif // QQMUSICALBUM_H 36 | -------------------------------------------------------------------------------- /qqmusicplaylist.cpp: -------------------------------------------------------------------------------- 1 | #include "qqmusicplaylist.h" 2 | #include "QtDebug" 3 | 4 | qqMusicPlaylist::qqMusicPlaylist(QObject *parent) : QObject(parent) 5 | { 6 | d=new downloader(); 7 | connect(d,SIGNAL(downloadError(QString)),this,SLOT(playlistGotFailed(QString))); 8 | connect(d,SIGNAL(redirected(QString)),this,SLOT(playlistGotFailed(QString))); 9 | connect(d,SIGNAL(finished()),this,SLOT(playlistGot())); 10 | } 11 | 12 | void qqMusicPlaylist::doJob(QString inMid) 13 | { 14 | playListMid=inMid; 15 | refererString =QString("https://y.qq.com/n/yqq/playsquare/")+inMid+QString(".html"); 16 | playListDownloadLink=QString(PLAYLISTLINKHEAD)+playListMid+QString(PALYLISTLINKTAIL); 17 | d->init(playListDownloadLink,QString(PLAYLISTFILE)); 18 | qDebug()<setReferer(refererString); 20 | qDebug()<<"准备下载歌单列表"; 21 | emit status("准备下载歌单json数据"); 22 | d->doGet(); 23 | } 24 | 25 | void qqMusicPlaylist::playlistGotFailed(QString errorString) 26 | { 27 | QStringList a; 28 | emit status(QString("QQMusic playlist json data download failed:")+errorString); 29 | finished(-1,a); 30 | } 31 | 32 | void qqMusicPlaylist::playlistGot() 33 | { 34 | songMidList.clear(); 35 | QFile file(PLAYLISTFILE); 36 | int index=0; 37 | QString songmid; 38 | QString playListName; 39 | file.open(QIODevice::ReadOnly); 40 | QString str=file.readAll(); 41 | file.close(); 42 | 43 | //将歌单名字作为目录名 44 | if(-1!=(index=str.indexOf("dissname",index))) 45 | { 46 | index+=11; 47 | playListName=""; 48 | while(str.at(index)!='\"') 49 | { 50 | playListName+=str.at(index); 51 | index++; 52 | } 53 | playListName.remove(QChar('|')); 54 | playListName.remove(QChar('>')); 55 | playListName.remove(QChar('<')); 56 | playListName.remove(QChar('*')); 57 | playListName.remove(QChar('?')); 58 | playListName.remove(QChar('/')); 59 | playListName.remove(QChar('\\')); 60 | playListName.remove(QChar(':')); 61 | qDebug()< 5 | #include "downloader.h" 6 | #include "daye.h" 7 | #include "config.h" 8 | 9 | extern int songNameType; 10 | extern int songQuality; 11 | extern QString mp3FileName; 12 | extern QString mp3Dir; 13 | extern QString vkey; 14 | extern QString guid; 15 | 16 | class qqMusicPlaylist : public QObject 17 | { 18 | Q_OBJECT 19 | public: 20 | explicit qqMusicPlaylist(QObject *parent = nullptr); 21 | void doJob(QString inMid); 22 | signals: 23 | void finished(int,QStringList); 24 | void status(QString); 25 | public slots: 26 | void playlistGot(); 27 | void playlistGotFailed(QString errorString); 28 | 29 | private: 30 | downloader *d; //下载歌单json数据,只用一次 31 | QStringList songMidList; 32 | QString playListMid; 33 | QString refererString; 34 | QString playListDownloadLink; 35 | }; 36 | 37 | #endif // QQMUSICPLAYLIST_H 38 | -------------------------------------------------------------------------------- /qqmusicsearch.cpp: -------------------------------------------------------------------------------- 1 | #include "qqmusicsearch.h" 2 | 3 | qqMusicSearch::qqMusicSearch(QObject *parent) : QObject(parent) 4 | { 5 | d=new downloader(); 6 | connect(d,SIGNAL(downloadError(QString)),this,SLOT(searchResultGotFailed(QString))); 7 | connect(d,SIGNAL(redirected(QString)),this,SLOT(searchResultGotFailed(QString))); 8 | connect(d,SIGNAL(finished()),this,SLOT(searchResultGot())); 9 | } 10 | 11 | void qqMusicSearch::doJob(QString request) 12 | { 13 | sRequest=request; 14 | request=request.toUtf8().toPercentEncoding(); 15 | QString searchUrl="https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.center&searchid=46778975652331378&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=20&w="; 16 | searchUrl=searchUrl+request+QString("&g_tk=5381&jsonpCallback=MusicJsonCallback20651003929414546&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0"); 17 | 18 | d->init(searchUrl,SEARCHRESULTFILE); 19 | d->doGet(); 20 | } 21 | 22 | void qqMusicSearch::searchResultGot() 23 | { 24 | QFile file(SEARCHRESULTFILE); 25 | QString line; 26 | char tmpMid[30]; 27 | if(file.open(QIODevice::ReadOnly)) 28 | { 29 | line=file.readLine(); 30 | int pos=line.indexOf(QString("lyric")); 31 | line=line.mid(pos); 32 | getStringBetweenAandB(line.toStdString().c_str(),"mid\":\"","\"",tmpMid); 33 | file.close(); 34 | emit finished(0,QString(tmpMid)); 35 | } 36 | } 37 | 38 | void qqMusicSearch::searchResultGotFailed(QString errorString) 39 | { 40 | emit finished(-1,errorString); 41 | } 42 | -------------------------------------------------------------------------------- /qqmusicsearch.h: -------------------------------------------------------------------------------- 1 | #ifndef QQMUSICSEARCH_H 2 | #define QQMUSICSEARCH_H 3 | 4 | #include 5 | #include 6 | #include "config.h" 7 | #include "daye.h" 8 | 9 | class qqMusicSearch : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | explicit qqMusicSearch(QObject *parent = nullptr); 14 | void doJob(QString request); 15 | signals: 16 | void finished(int,QString); 17 | public slots: 18 | void searchResultGot(); 19 | void searchResultGotFailed(QString errorString); 20 | private: 21 | downloader *d; 22 | QString sRequest; 23 | }; 24 | 25 | #endif // QQMUSICSEARCH_H 26 | -------------------------------------------------------------------------------- /qqmusicsong.cpp: -------------------------------------------------------------------------------- 1 | #include "qqmusicsong.h" 2 | 3 | qqMusicSong::qqMusicSong(QObject *parent) : QObject(parent) 4 | { 5 | d=new downloader(); 6 | d->setUserAgent(USERAGENT); 7 | connect(d,SIGNAL(downloadError(QString)),this,SLOT(htmlGotFailed(QString))); 8 | connect(d,SIGNAL(redirected(QString)),this,SLOT(htmlGotFailed(QString))); 9 | connect(d,SIGNAL(finished()),this,SLOT(htmlGot())); 10 | 11 | m=new downloader(); 12 | connect(m,SIGNAL(downloadError(QString)),this,SLOT(musicDownloadFailed(QString))); 13 | connect(m,SIGNAL(redirected(QString)),this,SLOT(musicDownloadFailed(QString))); 14 | connect(m,SIGNAL(finished()),this,SLOT(musicDownloaded())); 15 | connect(m,SIGNAL(progress(qint64,qint64)),this,SIGNAL(progress(qint64,qint64))); 16 | 17 | p=new downloader(); 18 | connect(p,SIGNAL(downloadError(QString)),this,SLOT(picDownloadFailed(QString))); 19 | connect(p,SIGNAL(redirected(QString)),this,SLOT(picDownloadFailed(QString))); 20 | connect(p,SIGNAL(finished()),this,SLOT(picDownloaded())); 21 | } 22 | 23 | void qqMusicSong::doJob(QString inMid) 24 | { 25 | sizeape=0; 26 | size320=0; 27 | songMid=inMid; 28 | htmlLink=QString(SINGLESONGHEAD)+songMid+QString(SINGLESONGTAIL); 29 | 30 | d->init(htmlLink,QString(SONGINFOFILE)); 31 | d->doGet(); 32 | } 33 | 34 | void qqMusicSong::htmlGotFailed(QString errorString) 35 | { 36 | emit status(songMid+QString("-html下载失败,失败原因:")+errorString); 37 | finished(-1); 38 | } 39 | 40 | 41 | /**************************** 42 | * html文件已经下载 43 | * 找出mediaMid,songName,albumMid,singerName 44 | * **************************/ 45 | 46 | void qqMusicSong::htmlGot() 47 | { 48 | QFile file(SONGINFOFILE); 49 | if(file.open(QIODevice::ReadOnly)) 50 | { 51 | QByteArray b=file.readAll(); 52 | QJsonParseError jsonError; 53 | QJsonDocument doucment = QJsonDocument::fromJson(b,&jsonError); 54 | if(jsonError.error!=QJsonParseError::NoError) 55 | { 56 | qDebug() << "read singleSong json file failed"; 57 | emit status("read singleSong json file failed"); 58 | file.close(); 59 | } 60 | QJsonObject obj=doucment.object(); 61 | QJsonArray tmpArray=obj["data"].toArray(); 62 | obj=tmpArray.first().toObject(); 63 | 64 | QJsonObject tmpObj=obj["album"].toObject(); 65 | albumMid=tmpObj["mid"].toString(); 66 | qDebug()<0) 89 | { 90 | tmpObj=tmpArray.first().toObject(); 91 | singerName=singerName+QString("/")+tmpObj["name"].toString(); 92 | tmpArray.removeFirst(); 93 | qDebug()<init(picUrl,"tmp.jpg"); 116 | p->doGet(); 117 | } 118 | else 119 | { 120 | emit finished(0); 121 | } 122 | } 123 | 124 | void qqMusicSong::picDownloadFailed(QString errorString) 125 | { 126 | emit status(QString("封面图片下载失败:")+errorString+QString(",不设置封面图")); 127 | finished(0); 128 | } 129 | 130 | void qqMusicSong::picDownloaded() 131 | { 132 | tagtmp=new ID3tag(mp3FileName); 133 | connect(tagtmp,SIGNAL(finished()),this,SLOT(tagDone())); 134 | tagtmp->setTitle(songName); 135 | tagtmp->setArtist(singerName.replace("-","/")); 136 | tagtmp->setAlbum(albumName); 137 | tagtmp->setPic(QString("tmp.jpg")); 138 | tagtmp->doJob(); 139 | } 140 | 141 | void qqMusicSong::tagDone() 142 | { 143 | delete tagtmp; 144 | emit status("封面图设置结束"); 145 | emit finished(0); 146 | } 147 | 148 | void qqMusicSong::getSongLink() 149 | { 150 | if(size320==0 || songQuality == 1) 151 | { 152 | mp3Link=QString(NDOWNLOADLINKHEAD)+QString("M500")+mediaMid+QString(".mp3")+QString(NDOWNLOADLINKMID)+vkey2+QString(NDOWNLOADLINKTAIL); 153 | return ; 154 | } 155 | 156 | if(sizeape==0 || songQuality == 2) 157 | { 158 | mp3Link=QString(NDOWNLOADLINKHEAD)+QString("M800")+mediaMid+QString(".mp3")+QString(NDOWNLOADLINKMID)+vkey2+QString(NDOWNLOADLINKTAIL); 159 | return; 160 | } 161 | 162 | switch (songQuality) { 163 | case 2: 164 | mp3Link=QString(NDOWNLOADLINKHEAD)+QString("M800")+mediaMid+QString(".mp3")+QString(NDOWNLOADLINKMID)+vkey2+QString(NDOWNLOADLINKTAIL); 165 | break; 166 | case 3: 167 | mp3Link=QString(NDOWNLOADLINKHEAD)+QString("F000")+mediaMid+QString(".flac")+QString(NDOWNLOADLINKMID)+vkey2+QString(NDOWNLOADLINKTAIL); 168 | break; 169 | case 4: 170 | mp3Link=QString(NDOWNLOADLINKHEAD)+QString("A000")+mediaMid+QString(".ape")+QString(NDOWNLOADLINKMID)+vkey2+QString(NDOWNLOADLINKTAIL); 171 | break; 172 | default: 173 | mp3Link=QString(NDOWNLOADLINKHEAD)+QString("M500")+mediaMid+QString(".mp3")+QString(NDOWNLOADLINKMID)+vkey2+QString(NDOWNLOADLINKTAIL); 174 | break; 175 | } 176 | } 177 | 178 | void qqMusicSong::downloadSong() 179 | { 180 | getSongLink(); 181 | if(songNameType==2) 182 | mp3FileName=mp3Dir+QString("/")+singerName.replace("/","-")+QString("-")+songName; 183 | else 184 | mp3FileName=mp3Dir+QString("/")+songName+QString("-")+singerName.replace("/","-"); 185 | switch (songQuality) { 186 | case 1: 187 | mp3FileName=mp3FileName+QString("-128")+".mp3"; 188 | break; 189 | case 2: 190 | mp3FileName=mp3FileName+".mp3"; 191 | break; 192 | case 3: 193 | mp3FileName=mp3FileName+".flac"; 194 | break; 195 | case 4: 196 | mp3FileName=mp3FileName+".ape"; 197 | break; 198 | } 199 | qDebug()<<"mp3link:"<init(mp3Link,mp3FileName); 211 | emit status(QString("准备下载")+mp3FileName); 212 | m->doGet(); 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /qqmusicsong.h: -------------------------------------------------------------------------------- 1 | #ifndef QQMUSICSONG_H 2 | #define QQMUSICSONG_H 3 | 4 | #include 5 | #include "id3tag.h" 6 | #include "downloader.h" 7 | #include "daye.h" 8 | #include "config.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | extern int songNameType; 15 | extern int songQuality; 16 | extern QString mp3FileName; 17 | extern QString mp3Dir; 18 | extern QString vkey; 19 | extern QString guid; 20 | extern QString vkey2; 21 | 22 | 23 | class qqMusicSong : public QObject 24 | { 25 | Q_OBJECT 26 | public: 27 | explicit qqMusicSong(QObject *parent = nullptr); 28 | void doJob(QString inMid); 29 | signals: 30 | void progress(qint64, qint64); 31 | void finished(int);//成功0,html失败-1,音乐文件下载失败-2 32 | void status(QString); 33 | public slots: 34 | void htmlGot(); 35 | void htmlGotFailed(QString errorString); 36 | 37 | void musicDownloaded(); 38 | void musicDownloadFailed(QString errorString); 39 | 40 | void picDownloaded(); 41 | void picDownloadFailed(QString errorString); 42 | 43 | void tagDone(); 44 | private: 45 | QString songMid; 46 | QString htmlLink; 47 | QString songName; 48 | QString singerName; 49 | 50 | QString picUrl; 51 | QString albumName; 52 | QString albumMid; 53 | int sizeape; 54 | int size320; 55 | QString mediaMid; 56 | QString mp3Link; 57 | downloader *d;//下载html文件 58 | downloader *m;//下载音乐文件 59 | downloader *p;//下载图片文件 60 | 61 | ID3tag *tagtmp; 62 | QString tmpHtmlFileName; 63 | 64 | void downloadSong(); 65 | void getSongLink(); 66 | }; 67 | 68 | #endif // QQMUSICSONG_H 69 | -------------------------------------------------------------------------------- /singerallalbum.cpp: -------------------------------------------------------------------------------- 1 | #include "singerallalbum.h" 2 | #include "ui_singerallalbum.h" 3 | 4 | singerAllAlbum::singerAllAlbum(QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::singerAllAlbum) 7 | { 8 | songNameType=0; 9 | songQuality=0; 10 | ui->setupUi(this); 11 | d=new downloader(); 12 | connect(d,SIGNAL(finished()),this,SLOT(downloadFinished())); 13 | connect(d,SIGNAL(downloadError(QString)),this,SLOT(downloadFailed(QString))); 14 | connect(d,SIGNAL(redirected(QString)),this,SLOT(downloadFailed(QString))); 15 | } 16 | 17 | singerAllAlbum::~singerAllAlbum() 18 | { 19 | delete ui; 20 | } 21 | 22 | void singerAllAlbum::on_pushButtonChosePath_clicked() 23 | { 24 | mp3Dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), "/home", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); 25 | ui->lineEditMp3Path->setText(mp3Dir); 26 | } 27 | 28 | void singerAllAlbum::on_radioButtonSongNameType1_clicked() 29 | { 30 | songNameType=1; 31 | } 32 | 33 | void singerAllAlbum::on_radioButtonSongNameType2_clicked() 34 | { 35 | songNameType=2; 36 | } 37 | 38 | void singerAllAlbum::on_radioButtonQuality128_clicked() 39 | { 40 | songQuality=1; 41 | } 42 | 43 | void singerAllAlbum::on_radioButtonQuality320_clicked() 44 | { 45 | songQuality=2; 46 | } 47 | 48 | void singerAllAlbum::on_radioButtonQualityflac_clicked() 49 | { 50 | songQuality=3; 51 | } 52 | 53 | void singerAllAlbum::on_radioButtonQualityape_clicked() 54 | { 55 | songQuality=4; 56 | } 57 | 58 | void singerAllAlbum::on_pushButton_clicked() 59 | { 60 | ui->textEdit->clear(); 61 | mp3Dir=ui->lineEditMp3Path->text(); 62 | if(!songNameType || !songQuality || ui->lineEditMp3Path->text().isEmpty() || ui->lineEditSingerUrl->text().isEmpty()) 63 | { 64 | ui->textEdit->append("请输入合法的设置"); 65 | } 66 | else{ 67 | if(ui->lineEditSingerUrl->text().contains("y.qq.com/n/yqq/singer")) 68 | { 69 | if(ui->lineEditSingerUrl->text().contains("num")) 70 | { 71 | ui->textEdit->append("请选择不含num的链接"); 72 | return; 73 | } 74 | ui->pushButton->setEnabled(false); 75 | doJob(); 76 | } 77 | else{ 78 | ui->textEdit->append("请填入如https://y.qq.com/n/yqq/singer/002J4UUk29y8BY.html的歌手链接"); 79 | } 80 | } 81 | } 82 | 83 | void singerAllAlbum::setDownloadQueue(downloadQueue *inDQ) 84 | { 85 | dq=inDQ; 86 | } 87 | 88 | void singerAllAlbum::doJob() 89 | { 90 | singerName=""; 91 | albumList.clear(); 92 | albumNum=0; 93 | nowNum=30; 94 | char tmp[30]; 95 | getStringBetweenAandB(ui->lineEditSingerUrl->text().toStdString().c_str(),"yqq/singer/",".html",tmp); 96 | singerMid=tmp; 97 | 98 | QString link=QString(SINGERALBUMHEAD)+singerMid+QString(SINGERALBUMMID1)+QString("0")+QString(SINGERALBUMMID2)+QString("30")+QString(SINGERALBUMTAIL); 99 | d->init(link,"singerAllAlbum.tmp"); 100 | d->setUserAgent(UA); 101 | d->setReferer("https://y.qq.com"); 102 | d->doGet(); 103 | } 104 | 105 | void singerAllAlbum::downloadFailed(QString inStr) 106 | { 107 | ui->textEdit->append("获取专辑信息失败,请联系作者"); 108 | ui->textEdit->append(inStr); 109 | } 110 | 111 | void singerAllAlbum::downloadFinished() 112 | { 113 | char tmp[200]; 114 | QFile file("singerAllAlbum.tmp"); 115 | if(file.open(QIODevice::ReadOnly)) 116 | { 117 | QByteArray b=file.readAll(); 118 | QJsonParseError jsonError; 119 | QJsonDocument doucment = QJsonDocument::fromJson(b,&jsonError); 120 | if(jsonError.error!=QJsonParseError::NoError) 121 | { 122 | qDebug() << "read singerAllAlbum.tmp file failed"; 123 | qDebug()<textEdit->append("read singerAllAlbum.tmp file failed"); 126 | file.close(); 127 | ui->pushButton->setEnabled(true); 128 | return; 129 | } 130 | QJsonObject obj=doucment.object(); 131 | obj=obj["data"].toObject(); 132 | if(nowNum==30) 133 | { 134 | singerName=obj["singer_name"].toString(); 135 | albumNum=obj["total"].toInt(); 136 | mp3Dir=mp3Dir+QString("/")+singerName; 137 | QDir tmp(mp3Dir); 138 | if(!tmp.exists()) 139 | { 140 | tmp.mkdir(mp3Dir); 141 | } 142 | } 143 | QJsonArray tmpArray=obj["list"].toArray(); 144 | 145 | while(tmpArray.count()>0) 146 | { 147 | obj=tmpArray.first().toObject(); 148 | albumList.append(obj["albumMID"].toString()); 149 | qDebug()<init(link,"singerAllAlbum.tmp"); 159 | d->doGet(); 160 | } 161 | else 162 | { 163 | while(albumList.count()>0) 164 | { 165 | dq->insertQueue(0,songQuality,songNameType,mp3Dir,QString("https://y.qq.com/n/yqq/album/%1.html").arg(albumList.first())); 166 | albumList.removeFirst(); 167 | } 168 | ui->pushButton->setEnabled(true); 169 | ui->textEdit->append(QString("%1张专辑已经添加到下载队列,请回到主页面查看进度,当前界面可以关闭").arg(albumNum)); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /singerallalbum.h: -------------------------------------------------------------------------------- 1 | #ifndef SINGERALLALBUM_H 2 | #define SINGERALLALBUM_H 3 | 4 | #include 5 | #include "downloadqueue.h" 6 | #include "downloader.h" 7 | #include "config.h" 8 | #include 9 | 10 | namespace Ui { 11 | class singerAllAlbum; 12 | } 13 | 14 | class singerAllAlbum : public QWidget 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | explicit singerAllAlbum(QWidget *parent = 0); 20 | void setDownloadQueue(downloadQueue *inDQ); 21 | ~singerAllAlbum(); 22 | 23 | private slots: 24 | void on_pushButtonChosePath_clicked(); 25 | 26 | void on_radioButtonSongNameType1_clicked(); 27 | 28 | void on_radioButtonSongNameType2_clicked(); 29 | 30 | void on_radioButtonQuality128_clicked(); 31 | 32 | void on_radioButtonQuality320_clicked(); 33 | 34 | void on_radioButtonQualityflac_clicked(); 35 | 36 | void on_radioButtonQualityape_clicked(); 37 | 38 | void on_pushButton_clicked(); 39 | 40 | void downloadFinished(); 41 | void downloadFailed(QString inStr); 42 | 43 | private: 44 | Ui::singerAllAlbum *ui; 45 | 46 | int songNameType; 47 | int songQuality; 48 | QString mp3Dir; 49 | 50 | downloadQueue *dq; 51 | downloader *d; 52 | 53 | int albumNum; 54 | int nowNum; 55 | 56 | 57 | QString singerMid; 58 | QStringList albumList; 59 | QString singerName; 60 | 61 | void doJob(); 62 | }; 63 | 64 | #endif // SINGERALLALBUM_H 65 | -------------------------------------------------------------------------------- /singerallalbum.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | singerAllAlbum 4 | 5 | 6 | 7 | 0 8 | 0 9 | 447 10 | 299 11 | 12 | 13 | 14 | 下载歌手所有专辑 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 歌手链接: 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 文件保存目录: 41 | 42 | 43 | 44 | 45 | 46 | 47 | true 48 | 49 | 50 | 51 | 52 | 53 | 54 | ... 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 名称格式 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 歌名-歌手 72 | 73 | 74 | 75 | 76 | 77 | 78 | 歌手-歌名 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 音质 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 128 99 | 100 | 101 | 102 | 103 | 104 | 105 | 320 106 | 107 | 108 | 109 | 110 | 111 | 112 | flac 113 | 114 | 115 | 116 | 117 | 118 | 119 | ape 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 下载歌手所有专辑 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /thanks.cpp: -------------------------------------------------------------------------------- 1 | #include "thanks.h" 2 | #include "ui_thanks.h" 3 | 4 | thanks::thanks(QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::thanks) 7 | { 8 | ui->setupUi(this); 9 | this->hide(); 10 | } 11 | 12 | thanks::~thanks() 13 | { 14 | delete ui; 15 | } 16 | 17 | void thanks::on_pushButton_clicked() 18 | { 19 | this->hide(); 20 | } 21 | 22 | void thanks::on_pushButton_4_clicked() 23 | { 24 | this->hide(); 25 | } 26 | 27 | void thanks::on_pushButton_2_clicked() 28 | { 29 | this->hide(); 30 | } 31 | 32 | void thanks::on_pushButton_3_clicked() 33 | { 34 | this->hide(); 35 | } 36 | -------------------------------------------------------------------------------- /thanks.h: -------------------------------------------------------------------------------- 1 | #ifndef THANKS_H 2 | #define THANKS_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class thanks; 8 | } 9 | 10 | class thanks : public QWidget 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit thanks(QWidget *parent = 0); 16 | ~thanks(); 17 | 18 | private slots: 19 | void on_pushButton_clicked(); 20 | 21 | void on_pushButton_4_clicked(); 22 | 23 | void on_pushButton_2_clicked(); 24 | 25 | void on_pushButton_3_clicked(); 26 | 27 | private: 28 | Ui::thanks *ui; 29 | }; 30 | 31 | #endif // THANKS_H 32 | -------------------------------------------------------------------------------- /thanks.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | thanks 4 | 5 | 6 | Qt::WindowModal 7 | 8 | 9 | 10 | 0 11 | 0 12 | 240 13 | 369 14 | 15 | 16 | 17 | 要饭 18 | 19 | 20 | 21 | 22 | 0 23 | 0 24 | 241 25 | 371 26 | 27 | 28 | 29 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 30 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> 31 | p, li { white-space: pre-wrap; } 32 | </style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;"> 33 | <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">如果可以的话</p> 34 | <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; color:#ff0000;">一分两分也是爱</span></p> 35 | <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src=":/new/prefix1/1.jpg" /></p></body></html> 36 | 37 | 38 | 39 | 40 | 41 | 180 42 | 10 43 | 51 44 | 23 45 | 46 | 47 | 48 | 关闭 49 | 50 | 51 | 52 | 53 | 54 | 10 55 | 10 56 | 51 57 | 23 58 | 59 | 60 | 61 | 关闭 62 | 63 | 64 | 65 | 66 | 67 | 10 68 | 50 69 | 51 70 | 23 71 | 72 | 73 | 74 | 关闭 75 | 76 | 77 | 78 | 79 | 80 | 180 81 | 50 82 | 51 83 | 23 84 | 85 | 86 | 87 | 关闭 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /vkeyinit2.cpp: -------------------------------------------------------------------------------- 1 | #include "vkeyinit2.h" 2 | #include "daye.h" 3 | #include "config.h" 4 | #include 5 | 6 | vkeyinit2::vkeyinit2(QObject *parent) : QObject(parent) 7 | { 8 | d=new downloader(); 9 | connect(d,SIGNAL(finished()),this,SLOT(htmlGot())); 10 | connect(d,SIGNAL(downloadError(QString)),this,SLOT(htmlFailed())); 11 | } 12 | 13 | void vkeyinit2::init() 14 | { 15 | QString htmlLink=QString("https://c.y.qq.com/base/fcgi-bin/fcg_music_express_mobile3.fcg?g_tk=0&loginUin=1008611&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0&cid=205361747&uin=1008611&songmid=003a1tne1nSz1Y&filename=C400003a1tne1nSz1Y.m4a&guid=1234567890"); 16 | d->init(htmlLink,QString(SONGHTMLFILE)); 17 | d->setUserAgent("Dalvik/2.1.0 (Linux; U; Android 5.1.1; vivo x5s l Build/LMY48Z)"); 18 | d->setReferer("https://y.qq.com/portal/profile.html"); 19 | d->doGet(); 20 | } 21 | 22 | void vkeyinit2::htmlFailed() 23 | { 24 | emit status("无法下载无损歌曲"); 25 | } 26 | 27 | void vkeyinit2::htmlGot() 28 | { 29 | QString line; 30 | QFile file(SONGHTMLFILE); 31 | int a; 32 | char tmp[200]; 33 | if(file.open(QIODevice::ReadOnly)) 34 | { 35 | line=file.readLine(); 36 | if(line.contains("vkey")) 37 | { 38 | a=getStringBetweenAandB(line.toStdString().c_str(),"vkey\":\"","\"",tmp); 39 | if(!a && strlen(tmp)) 40 | { 41 | vkey2=QString(tmp); 42 | qDebug()< 5 | #include "downloader.h" 6 | 7 | extern QString vkey2; 8 | 9 | class vkeyinit2 : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | explicit vkeyinit2(QObject *parent = nullptr); 14 | void init(); 15 | signals: 16 | void finished(); 17 | void status(QString); 18 | private slots: 19 | void htmlGot(); 20 | void htmlFailed(); 21 | private: 22 | downloader *d; 23 | }; 24 | 25 | #endif // VKEYINIT2_H 26 | --------------------------------------------------------------------------------